summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadezhda Ivanova <nadezhda.ivanova@postpath.com>2010-01-04 11:24:10 +0200
committerNadezhda Ivanova <nadezhda.ivanova@postpath.com>2010-01-04 11:24:10 +0200
commitfb5383c69ee52fb5e6d066a43451dc8c806cc795 (patch)
tree45b72e03f68ab6d212755c524f8e8a60a3b4373a
parent60d8ab3b7b0bd2c9b633f0380d1fdf5bcf5e2621 (diff)
parenta06e5cdb99ddf7abf16486d3837105ec4e0da9ee (diff)
downloadsamba-fb5383c69ee52fb5e6d066a43451dc8c806cc795.tar.gz
samba-fb5383c69ee52fb5e6d066a43451dc8c806cc795.tar.bz2
samba-fb5383c69ee52fb5e6d066a43451dc8c806cc795.zip
Merge branch 'master' of git://git.samba.org/samba
-rw-r--r--.gitignore2
-rw-r--r--docs-xml/build/DTD/samba.entities20
-rw-r--r--docs-xml/manpages-3/mount.cifs.8.xml54
-rw-r--r--docs-xml/manpages-3/pdbedit.8.xml174
-rw-r--r--docs-xml/manpages-3/rpcclient.1.xml11
-rw-r--r--docs-xml/manpages-3/smbcacls.1.xml28
-rw-r--r--docs-xml/manpages-3/smbclient.1.xml28
-rw-r--r--docs-xml/manpages-3/smbget.1.xml8
-rw-r--r--docs-xml/manpages-3/smbtree.1.xml6
-rw-r--r--docs-xml/manpages-3/tdbbackup.8.xml2
-rw-r--r--docs-xml/manpages-3/tdbdump.8.xml2
-rw-r--r--docs-xml/manpages-3/tdbtool.8.xml2
-rw-r--r--lib/replace/libreplace.m42
-rw-r--r--lib/replace/replace.c23
-rw-r--r--lib/replace/replace.h6
-rw-r--r--lib/replace/snprintf.c1
-rw-r--r--lib/replace/test/testsuite.c37
-rw-r--r--lib/tdb/Makefile.in6
-rw-r--r--lib/tdb/configure.ac7
-rw-r--r--lib/tdb/include/tdb.h2
-rw-r--r--lib/tdb/manpages/tdbbackup.8.xml136
-rw-r--r--lib/tdb/manpages/tdbdump.8.xml61
-rw-r--r--lib/tdb/manpages/tdbtool.8.xml235
-rw-r--r--lib/tdb/tdb.mk15
-rw-r--r--lib/tdb/tdb.signatures2
-rw-r--r--lib/tevent/tevent_signal.c76
-rw-r--r--lib/tsocket/tsocket_bsd.c12
-rw-r--r--libcli/auth/ntlmssp_ndr.c (renamed from source3/libsmb/ntlmssp_ndr.c)2
-rw-r--r--libcli/auth/ntlmssp_ndr.h (renamed from source3/libsmb/ntlmssp_ndr.h)0
-rw-r--r--librpc/ndr/uuid.c10
-rw-r--r--nsswitch/libwbclient/wbc_pam.c45
-rw-r--r--nsswitch/libwbclient/wbc_util.c2
-rw-r--r--nsswitch/libwbclient/wbclient.h14
-rw-r--r--nsswitch/wbinfo.c34
-rw-r--r--nsswitch/winbind_struct_protocol.h4
-rw-r--r--source3/Makefile.in10
-rw-r--r--source3/auth/auth_ntlmssp.c6
-rw-r--r--source3/include/async_smb.h5
-rw-r--r--source3/include/client.h4
-rw-r--r--source3/include/includes.h4
-rw-r--r--source3/include/ntlmssp.h34
-rw-r--r--source3/include/proto.h62
-rw-r--r--source3/include/smb.h2
-rw-r--r--source3/include/smb_macros.h3
-rw-r--r--source3/lib/util_sid.c17
-rw-r--r--source3/libads/sasl.c1
-rw-r--r--source3/librpc/gen_ndr/cli_wbint.c130
-rw-r--r--source3/librpc/gen_ndr/cli_wbint.h8
-rw-r--r--source3/librpc/gen_ndr/ndr_wbint.c51
-rw-r--r--source3/librpc/gen_ndr/ndr_wbint.h11
-rw-r--r--source3/librpc/gen_ndr/srv_wbint.c80
-rw-r--r--source3/librpc/gen_ndr/srv_wbint.h2
-rw-r--r--source3/librpc/gen_ndr/wbint.h8
-rw-r--r--source3/librpc/idl/wbint.idl3
-rw-r--r--source3/libsmb/async_smb.c219
-rw-r--r--source3/libsmb/cliconnect.c943
-rw-r--r--source3/libsmb/clidfs.c6
-rw-r--r--source3/libsmb/clifsinfo.c1
-rw-r--r--source3/libsmb/conncache.c82
-rw-r--r--source3/libsmb/errormap.c6
-rw-r--r--source3/libsmb/libsmb_cache.c4
-rw-r--r--source3/libsmb/ntlmssp.c88
-rw-r--r--source3/libsmb/ntlmssp_sign.c53
-rw-r--r--source3/libsmb/smb_seal.c5
-rw-r--r--source3/locale/net/de.po720
-rw-r--r--source3/modules/vfs_acl_common.c106
-rw-r--r--source3/rpc_client/cli_pipe.c3
-rw-r--r--source3/rpc_server/srv_pipe.c1
-rw-r--r--source3/smbd/error.c50
-rw-r--r--source3/smbd/mangle_hash.c9
-rw-r--r--source3/smbd/message.c8
-rw-r--r--source3/smbd/nttrans.c84
-rw-r--r--source3/smbd/pipes.c14
-rw-r--r--source3/smbd/posix_acls.c22
-rw-r--r--source3/smbd/process.c186
-rw-r--r--source3/smbd/reply.c121
-rw-r--r--source3/smbd/seal.c1
-rw-r--r--source3/smbd/sesssetup.c1
-rw-r--r--source3/smbd/smb2_sesssetup.c1
-rw-r--r--source3/smbd/trans2.c34
-rw-r--r--source3/torture/torture.c41
-rw-r--r--source3/utils/net_ads.c4
-rw-r--r--source3/utils/net_rpc.c10
-rw-r--r--source3/utils/ntlm_auth.c9
-rw-r--r--source3/winbindd/wb_getgrsid.c11
-rw-r--r--source3/winbindd/wb_gettoken.c7
-rw-r--r--source3/winbindd/wb_sid2gid.c2
-rw-r--r--source3/winbindd/wb_sid2uid.c2
-rw-r--r--source3/winbindd/winbindd.c17
-rw-r--r--source3/winbindd/winbindd.h23
-rw-r--r--source3/winbindd/winbindd_ads.c233
-rw-r--r--source3/winbindd/winbindd_async.c549
-rw-r--r--source3/winbindd/winbindd_cache.c119
-rw-r--r--source3/winbindd/winbindd_ccache_access.c33
-rw-r--r--source3/winbindd/winbindd_check_machine_acct.c2
-rw-r--r--source3/winbindd/winbindd_domain.c30
-rw-r--r--source3/winbindd/winbindd_dual.c94
-rw-r--r--source3/winbindd/winbindd_dual_srv.c48
-rw-r--r--source3/winbindd/winbindd_getgrnam.c23
-rw-r--r--source3/winbindd/winbindd_getgroups.c24
-rw-r--r--source3/winbindd/winbindd_group.c284
-rw-r--r--source3/winbindd/winbindd_idmap.c321
-rw-r--r--source3/winbindd/winbindd_misc.c192
-rw-r--r--source3/winbindd/winbindd_passdb.c72
-rw-r--r--source3/winbindd/winbindd_ping_dc.c96
-rw-r--r--source3/winbindd/winbindd_proto.h169
-rw-r--r--source3/winbindd/winbindd_reconnect.c12
-rw-r--r--source3/winbindd/winbindd_rpc.c57
-rw-r--r--source3/winbindd/winbindd_user.c73
-rw-r--r--source3/winbindd/winbindd_util.c138
-rw-r--r--source4/Makefile2
-rw-r--r--source4/auth/auth.h23
-rw-r--r--source4/auth/credentials/config.mk2
-rw-r--r--source4/auth/gensec/config.mk2
-rw-r--r--source4/auth/gensec/gensec.c117
-rw-r--r--source4/auth/gensec/gensec.h22
-rw-r--r--source4/auth/ntlm/auth.c271
-rw-r--r--source4/auth/ntlm/auth_proto.h50
-rw-r--r--source4/auth/ntlm/auth_server.c7
-rw-r--r--source4/auth/ntlm/auth_util.c12
-rw-r--r--source4/auth/ntlm/auth_winbind.c6
-rw-r--r--source4/auth/ntlm/config.mk4
-rw-r--r--source4/auth/ntlmssp/ntlmssp.h34
-rw-r--r--source4/auth/ntlmssp/ntlmssp_server.c103
-rw-r--r--source4/auth/ntlmssp/ntlmssp_sign.c31
-rw-r--r--source4/build/smb_build/summary.pm1
-rw-r--r--source4/dsdb/common/dsdb_dn.c69
-rw-r--r--source4/dsdb/common/dsdb_dn.h5
-rw-r--r--source4/dsdb/common/util.c293
-rw-r--r--source4/dsdb/config.mk5
-rw-r--r--source4/dsdb/kcc/kcc_connection.c6
-rw-r--r--source4/dsdb/kcc/kcc_deleted.c156
-rw-r--r--source4/dsdb/kcc/kcc_periodic.c5
-rw-r--r--source4/dsdb/kcc/kcc_service.h2
-rw-r--r--source4/dsdb/repl/drepl_notify.c2
-rw-r--r--source4/dsdb/repl/drepl_partitions.c7
-rw-r--r--source4/dsdb/repl/replicated_objects.c20
-rw-r--r--source4/dsdb/samdb/ldb_modules/config.mk17
-rw-r--r--source4/dsdb/samdb/ldb_modules/descriptor.c8
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn_in.c5
-rw-r--r--source4/dsdb/samdb/ldb_modules/linked_attributes.c1270
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c1807
-rw-r--r--source4/dsdb/samdb/ldb_modules/samba_dsdb.c98
-rw-r--r--source4/dsdb/samdb/ldb_modules/schema_data.c175
-rw-r--r--source4/dsdb/samdb/ldb_modules/simple_ldap_map.c6
-rw-r--r--source4/dsdb/samdb/ldb_modules/util.c109
-rw-r--r--source4/dsdb/samdb/ldb_modules/util.h4
-rw-r--r--source4/dsdb/schema/prefixmap.h11
-rw-r--r--source4/dsdb/schema/schema_init.c23
-rw-r--r--source4/dsdb/schema/schema_prefixmap.c24
-rw-r--r--source4/dsdb/schema/schema_query.c3
-rw-r--r--source4/dsdb/schema/schema_set.c12
-rw-r--r--source4/dsdb/schema/schema_syntax.c38
-rw-r--r--source4/heimdal_build/external.m48
-rw-r--r--source4/kdc/config.mk3
-rw-r--r--source4/kdc/hdb-samba4.c239
-rw-r--r--source4/kdc/hdb-samba4.h8
-rw-r--r--source4/kdc/kdc.c458
-rw-r--r--source4/kdc/kdc.h12
-rw-r--r--source4/kdc/kpasswdd.c216
-rw-r--r--source4/kdc/pac-glue.c30
-rw-r--r--source4/kdc/pac-glue.h6
-rw-r--r--source4/lib/ldb-samba/ldif_handlers.c55
-rw-r--r--source4/lib/ldb/common/attrib_handlers.c61
-rw-r--r--source4/lib/ldb/common/ldb_modules.c10
-rw-r--r--source4/lib/ldb/common/ldb_msg.c27
-rw-r--r--source4/lib/ldb/config.mk13
-rw-r--r--source4/lib/ldb/external/libtalloc.m42
-rw-r--r--source4/lib/ldb/include/ldb.h6
-rw-r--r--source4/lib/ldb/include/ldb_module.h1
-rw-r--r--source4/lib/ldb/ldb.mk28
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_cache.c2
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c17
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.h2
-rw-r--r--source4/lib/ldb/pyldb.c4
-rw-r--r--source4/lib/ldb/pyldb.h1
-rwxr-xr-xsource4/lib/ldb/tests/python/ldap.py160
-rwxr-xr-xsource4/lib/ldb/tests/python/ldap_schema.py500
-rw-r--r--source4/lib/ldb/tests/sample_module.c30
-rwxr-xr-xsource4/lib/ldb/tests/test-controls.sh46
-rwxr-xr-xsource4/lib/ldb/tests/test-tdb.sh2
-rw-r--r--source4/lib/ldb/tools/config.mk13
-rw-r--r--source4/lib/ldb/tools/ldbadd.c14
-rw-r--r--source4/lib/ldb/tools/ldbdel.c25
-rw-r--r--source4/lib/ldb/tools/ldbmodify.c17
-rw-r--r--source4/lib/ldb/tools/ldbutil.c149
-rw-r--r--source4/lib/ldb/tools/ldbutil.h41
-rw-r--r--source4/lib/ldb_wrap.c2
-rw-r--r--source4/lib/registry/util.c2
-rw-r--r--source4/lib/socket/config.mk2
-rw-r--r--source4/lib/socket/socket.c72
-rw-r--r--source4/lib/socket/socket.h7
-rw-r--r--source4/libcli/finddcs.c3
-rw-r--r--source4/libcli/security/sddl.c2
-rw-r--r--source4/libcli/security/tests/bindings.py11
-rw-r--r--source4/libnet/libnet.c3
-rw-r--r--source4/libnet/libnet_passwd.c8
-rw-r--r--source4/libnet/py_net.c78
-rw-r--r--source4/librpc/ndr/py_security.c36
-rw-r--r--source4/min_versions.m42
-rw-r--r--source4/param/config.mk2
-rw-r--r--source4/param/provision.c31
-rw-r--r--source4/param/pyparam.c3
-rw-r--r--source4/param/tests/bindings.py10
-rw-r--r--source4/rpc_server/drsuapi/addentry.c3
-rw-r--r--source4/rpc_server/drsuapi/dcesrv_drsuapi.c5
-rw-r--r--source4/rpc_server/drsuapi/dcesrv_drsuapi.h1
-rw-r--r--source4/rpc_server/drsuapi/drsutil.c22
-rw-r--r--source4/rpc_server/drsuapi/getncchanges.c421
-rw-r--r--source4/rpc_server/drsuapi/updaterefs.c4
-rwxr-xr-xsource4/script/installmisc.sh42
-rw-r--r--source4/scripting/python/modules.c43
-rw-r--r--source4/scripting/python/modules.h2
-rw-r--r--source4/scripting/python/pyglue.c23
-rw-r--r--source4/scripting/python/samba/__init__.py62
-rw-r--r--source4/scripting/python/samba/getopt.py14
-rw-r--r--source4/scripting/python/samba/netcmd/__init__.py145
-rw-r--r--source4/scripting/python/samba/netcmd/domainlevel.py229
-rwxr-xr-xsource4/scripting/python/samba/netcmd/enableaccount.py65
-rwxr-xr-xsource4/scripting/python/samba/netcmd/newuser.py70
-rw-r--r--source4/scripting/python/samba/netcmd/pwsettings.py190
-rw-r--r--source4/scripting/python/samba/netcmd/setexpiry.py72
-rw-r--r--source4/scripting/python/samba/netcmd/setpassword.py77
-rw-r--r--source4/scripting/python/samba/provision.py2
-rw-r--r--source4/scripting/python/samba/tests/netcmd.py34
-rwxr-xr-xsource4/selftest/tests.sh2
-rwxr-xr-xsource4/setup/domainlevel250
-rwxr-xr-xsource4/setup/enableaccount65
-rwxr-xr-xsource4/setup/newuser69
-rwxr-xr-xsource4/setup/pwsettings198
-rwxr-xr-xsource4/setup/setexpiry72
-rwxr-xr-xsource4/setup/setpassword74
-rwxr-xr-xsource4/setup/tests/blackbox_newuser.sh11
-rwxr-xr-xsource4/setup/tests/blackbox_setpassword.sh10
-rw-r--r--source4/smb_server/smb/negprot.c5
-rw-r--r--source4/smb_server/smb/sesssetup.c74
-rw-r--r--source4/smb_server/smb2/sesssetup.c17
-rw-r--r--source4/smbd/config.mk2
-rw-r--r--source4/smbd/server.c2
-rw-r--r--source4/smbd/service_stream.c32
-rw-r--r--source4/smbd/service_stream.h3
-rw-r--r--source4/torture/drs/unit/prefixmap_tests.c45
-rw-r--r--source4/torture/libnet/python/samr-test.py62
-rw-r--r--source4/torture/ndr/ndr.c13
-rw-r--r--source4/torture/raw/oplock.c265
-rw-r--r--source4/torture/raw/qfileinfo.c2
-rw-r--r--source4/torture/raw/setfileinfo.c153
-rw-r--r--source4/torture/raw/streams.c3
-rw-r--r--source4/utils/net/net.c178
-rwxr-xr-xtestprogs/blackbox/test_export_keytab.sh2
-rwxr-xr-xtestprogs/blackbox/test_kinit.sh2
-rwxr-xr-xtestprogs/blackbox/test_passwords.sh45
252 files changed, 10500 insertions, 7002 deletions
diff --git a/.gitignore b/.gitignore
index e88fad08d2..4f93726a6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -119,7 +119,7 @@ source3/samba4-data.mk
source3/samba4-config.mk
source3/torture.tdb
source4/apidocs
-source4/auth/auth_proto.h
+source4/auth/ntlm/auth_proto.h
source4/auth/auth_sam.h
source4/auth/auth_sam_reply.h
source4/auth/credentials/credentials_krb5_proto.h
diff --git a/docs-xml/build/DTD/samba.entities b/docs-xml/build/DTD/samba.entities
index 2e924d46ba..4ad65ca7c5 100644
--- a/docs-xml/build/DTD/samba.entities
+++ b/docs-xml/build/DTD/samba.entities
@@ -50,8 +50,8 @@
<!ENTITY person.gd '
<firstname>Guenther</firstname><surname>Deschner</surname>
<affiliation>
- <orgname>SuSE</orgname>
- <address><email>gd@suse.de</email></address>
+ <orgname>Samba Team</orgname>
+ <address><email>gd@samba.org</email></address>
</affiliation>'>
<!ENTITY author.gd '<author>&person.gd;</author>'>
@@ -214,7 +214,7 @@ in the &smb.conf; file.</para>
<!ENTITY stdarg.configfile '
<varlistentry>
-<term>-s &lt;configuration file&gt;</term>
+<term>-s|--configfile &lt;configuration file&gt;</term>
<listitem><para>The file specified contains the
configuration details required by the server. The
information in this file includes server-specific
@@ -227,7 +227,7 @@ compile time.</para></listitem>
<!ENTITY stdarg.version '
<varlistentry>
-<term>-V</term>
+<term>-V|--version</term>
<listitem><para>Prints the program version number.
</para></listitem>
</varlistentry>'>
@@ -249,7 +249,7 @@ log.smbd, etc...). The log file is never removed by the client.
<!ENTITY stdarg.resolve.order '
<varlistentry>
-<term>-R &lt;name resolve order&gt;</term>
+<term>-R|--name-resolve &lt;name resolve order&gt;</term>
<listitem><para>This option is used to determine what naming
services and in what order to resolve
host names to IP addresses. The option takes a space-separated
@@ -307,7 +307,7 @@ resolution methods will be attempted in this order. </para></listitem>
<!ENTITY stdarg.netbios.name '
<varlistentry>
-<term>-n &lt;primary NetBIOS name&gt;</term>
+<term>-n|--netbiosname &lt;primary NetBIOS name&gt;</term>
<listitem><para>This option allows you to override
the NetBIOS name that Samba uses for itself. This is identical
to setting the <smbconfoption><name>netbios name</name></smbconfoption> parameter in the &smb.conf; file.
@@ -318,7 +318,7 @@ line setting will take precedence over settings in
<!ENTITY stdarg.scope '
<varlistentry>
-<term>-i &lt;scope&gt;</term>
+<term>-i|--scope &lt;scope&gt;</term>
<listitem><para>This specifies a NetBIOS scope that
<command>nmblookup</command> will use to communicate with when
generating NetBIOS names. For details on the use of NetBIOS
@@ -340,7 +340,7 @@ SAM (as opposed to the Domain SAM). </para></listitem>
<!ENTITY stdarg.socket.options '
<varlistentry>
-<term>-O socket options</term>
+<term>-O|--socket-options socket options</term>
<listitem><para>TCP socket options to set on the client
socket. See the socket options parameter in
the &smb.conf; manual page for the list of valid
@@ -357,7 +357,7 @@ options. </para></listitem>
<!ENTITY stdarg.nopass '
<varlistentry>
-<term>-N</term>
+<term>-N|--no-pass</term>
<listitem><para>If specified, this parameter suppresses the normal
password prompt from the client to the user. This is useful when
accessing a service that does not require a password. </para>
@@ -420,7 +420,7 @@ access from unwanted users. </para></listitem>
<!ENTITY stdarg.kerberos '
<varlistentry>
-<term>-k</term>
+<term>-k|--kerberos</term>
<listitem><para>
Try to authenticate with kerberos. Only useful in
an Active Directory environment.
diff --git a/docs-xml/manpages-3/mount.cifs.8.xml b/docs-xml/manpages-3/mount.cifs.8.xml
index 372b4772f1..d930600437 100644
--- a/docs-xml/manpages-3/mount.cifs.8.xml
+++ b/docs-xml/manpages-3/mount.cifs.8.xml
@@ -477,12 +477,35 @@ permissions in memory that can't be stored on the server. This information can d
<varlistentry>
<term>noserverino</term>
- <listitem><para>client generates inode numbers (rather than using the actual one
- from the server) by default.
+ <listitem>
+ <para>
+ Client generates inode numbers (rather than
+ using the actual one from the server) by default.
+ </para>
+ <para>
+ See section <emphasis>INODE NUMBERS</emphasis> for
+ more information.
</para></listitem>
</varlistentry>
<varlistentry>
+ <term>nounix</term>
+ <listitem>
+ <para>
+ Disable the CIFS Unix Extensions for this mount. This
+ can be useful in order to turn off multiple settings at once.
+ This includes POSIX acls, POSIX locks, POSIX paths, symlink
+ support and retrieving uids/gids/mode from the server. This
+ can also be useful to work around a bug in a server that
+ supports Unix Extensions.
+ </para>
+ <para>
+ See section <emphasis>INODE NUMBERS</emphasis> for
+ more information.
+ </para> </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>nouser_xattr</term>
<listitem><para>(default) Do not allow getfattr/setfattr to get/set xattrs, even if server would support it otherwise. </para></listitem>
</varlistentry>
@@ -533,6 +556,33 @@ permissions in memory that can't be stored on the server. This information can d
</refsect1>
<refsect1>
+ <title>INODE NUMBERS</title>
+ <para>
+ When Unix Extensions are enabled, we use the actual inode
+ number provided by the server in response to the POSIX calls as an
+ inode number.
+ </para>
+ <para>
+ When Unix Extensions are disabled and "serverino" mount option
+ is enabled there is no way to get the server inode number. The
+ client typically maps the server-assigned "UniqueID" onto an inode
+ number.
+ </para>
+ <para>
+ Note that the UniqueID is a different value from the server
+ inode number. The UniqueID value is unique over the scope of the entire
+ server and is often greater than 2 power 32. This value often makes
+ programs that are not compiled with LFS (Large File Support), to
+ trigger a glibc EOVERFLOW error as this won't fit in the target
+ structure field. It is strongly recommended to compile your programs
+ with LFS support (i.e. with -D_FILE_OFFSET_BITS=64) to prevent this
+ problem. You can also use "noserverino" mount option to generate inode
+ numbers smaller than 2 power 32 on the client. But you may not be able
+ to detect hardlinks properly.
+ </para>
+</refsect1>
+
+<refsect1>
<title>FILE AND DIRECTORY OWNERSHIP AND PERMISSIONS</title>
<para> The core CIFS protocol does not provide unix ownership
diff --git a/docs-xml/manpages-3/pdbedit.8.xml b/docs-xml/manpages-3/pdbedit.8.xml
index d0ea811838..2d074d922d 100644
--- a/docs-xml/manpages-3/pdbedit.8.xml
+++ b/docs-xml/manpages-3/pdbedit.8.xml
@@ -19,30 +19,40 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>pdbedit</command>
- <arg choice="opt">-L</arg>
- <arg choice="opt">-v</arg>
- <arg choice="opt">-w</arg>
- <arg choice="opt">-u username</arg>
- <arg choice="opt">-f fullname</arg>
- <arg choice="opt">-h homedir</arg>
- <arg choice="opt">-D drive</arg>
- <arg choice="opt">-S script</arg>
- <arg choice="opt">-p profile</arg>
- <arg choice="opt">-a</arg>
- <arg choice="opt">-t, --password-from-stdin</arg>
- <arg choice="opt">-m</arg>
- <arg choice="opt">-r</arg>
- <arg choice="opt">-x</arg>
- <arg choice="opt">-i passdb-backend</arg>
- <arg choice="opt">-e passdb-backend</arg>
+ <arg choice="opt">-a</arg>
<arg choice="opt">-b passdb-backend</arg>
- <arg choice="opt">-g</arg>
+ <arg choice="opt">-c account-control</arg>
+ <arg choice="opt">-C value</arg>
<arg choice="opt">-d debuglevel</arg>
- <arg choice="opt">-s configfile</arg>
+ <arg choice="opt">-D drive</arg>
+ <arg choice="opt">-e passdb-backend</arg>
+ <arg choice="opt">-f fullname</arg>
+ <arg choice="opt">--force-initialized-passwords</arg>
+ <arg choice="opt">-g</arg>
+ <arg choice="opt">-h homedir</arg>
+ <arg choice="opt">-i passdb-backend</arg>
+ <arg choice="opt">-I domain</arg>
+ <arg choice="opt">-L </arg>
+ <arg choice="opt">-m</arg>
+ <arg choice="opt">-M SID|RID</arg>
+ <arg choice="opt">-N description</arg>
<arg choice="opt">-P account-policy</arg>
- <arg choice="opt">-C value</arg>
- <arg choice="opt">-c account-control</arg>
+ <arg choice="opt">-p profile</arg>
+ <arg choice="opt">--policies-reset</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-s configfile</arg>
+ <arg choice="opt">-S script</arg>
+ <arg choice="opt">-t</arg>
+ <arg choice="opt">--time-format</arg>
+ <arg choice="opt">-u username</arg>
+ <arg choice="opt">-U SID|RID</arg>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-V</arg>
+ <arg choice="opt">-w</arg>
+ <arg choice="opt">-x</arg>
<arg choice="opt">-y</arg>
+ <arg choice="opt">-z</arg>
+ <arg choice="opt">-Z</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -69,7 +79,7 @@
<title>OPTIONS</title>
<variablelist>
<varlistentry>
- <term>-L</term>
+ <term>-L|--list</term>
<listitem><para>This option lists all the user accounts
present in the users database.
This option prints a list of user/uid pairs separated by
@@ -85,7 +95,7 @@ samba:45:Test User
<varlistentry>
- <term>-v</term>
+ <term>-v|--verbose</term>
<listitem><para>This option enables the verbose listing format.
It causes pdbedit to list the users in the database, printing
out the account fields in a descriptive format.</para>
@@ -117,7 +127,7 @@ Profile Path: \\BERSERKER\profile
<varlistentry>
- <term>-w</term>
+ <term>-w|--smbpasswd-style</term>
<listitem><para>This option sets the "smbpasswd" listing format.
It will make pdbedit list the users in the database, printing
out the account fields in a format compatible with the
@@ -139,7 +149,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
<varlistentry>
- <term>-u username</term>
+ <term>-u|--user username</term>
<listitem><para>This option specifies the username to be
used for the operation requested (listing, adding, removing).
It is <emphasis>required</emphasis> in add, remove and modify
@@ -149,7 +159,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
</varlistentry>
<varlistentry>
- <term>-f fullname</term>
+ <term>-f|--fullname fullname</term>
<listitem><para>This option can be used while adding or
modifing a user account. It will specify the user's full
name. </para>
@@ -159,7 +169,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
</varlistentry>
<varlistentry>
- <term>-h homedir</term>
+ <term>-h|--homedir homedir</term>
<listitem><para>This option can be used while adding or
modifing a user account. It will specify the user's home
directory network path.</para>
@@ -170,7 +180,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
</varlistentry>
<varlistentry>
- <term>-D drive</term>
+ <term>-D|--drive drive</term>
<listitem><para>This option can be used while adding or
modifing a user account. It will specify the windows drive
letter to be used to map the home directory.</para>
@@ -182,7 +192,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
<varlistentry>
- <term>-S script</term>
+ <term>-S|--script script</term>
<listitem><para>This option can be used while adding or
modifing a user account. It will specify the user's logon
script path.</para>
@@ -194,7 +204,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
<varlistentry>
- <term>-p profile</term>
+ <term>-p|--profile profile</term>
<listitem><para>This option can be used while adding or
modifing a user account. It will specify the user's profile
directory.</para>
@@ -205,29 +215,32 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
</varlistentry>
<varlistentry>
- <term>-G SID|rid</term>
+ <term>-M|'--machine SID' SID|rid</term>
<listitem><para>
- This option can be used while adding or modifying a user account. It
- will specify the users' new primary group SID (Security Identifier) or
+ This option can be used while adding or modifying a machine account. It
+ will specify the machines' new primary group SID (Security Identifier) or
rid. </para>
- <para>Example: <command>-G S-1-5-21-2447931902-1787058256-3961074038-1201</command></para>
+ <para>Example: <command>-M S-1-5-21-2447931902-1787058256-3961074038-1201</command></para>
</listitem>
</varlistentry>
<varlistentry>
- <term>-U SID|rid</term>
+ <term>-U|'--user SID' SID|rid</term>
<listitem><para>
This option can be used while adding or modifying a user account. It
will specify the users' new SID (Security Identifier) or
rid. </para>
<para>Example: <command>-U S-1-5-21-2447931902-1787058256-3961074038-5004</command></para>
+ <para>Example: <command>'--user SID' S-1-5-21-2447931902-1787058256-3961074038-5004</command></para>
+ <para>Example: <command>-U 5004</command></para>
+ <para>Example: <command>'--user SID' 5004</command></para>
</listitem>
</varlistentry>
<varlistentry>
- <term>-c account-control</term>
+ <term>-c|--account-control account-control</term>
<listitem><para>This option can be used while adding or modifying a user
account. It will specify the users' account control property. Possible flags are listed below.
</para>
@@ -263,7 +276,7 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE:
</varlistentry>
<varlistentry>
- <term>-a</term>
+ <term>-a|--create</term>
<listitem><para>This option is used to add a user into the
database. This command needs a user name specified with
the -u switch. When adding a new user, pdbedit will also
@@ -289,7 +302,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-t, --password-from-stdin</term>
+ <term>-t|--password-from-stdin</term>
<listitem><para>This option causes pdbedit to read the password
from standard input, rather than from /dev/tty (like the
<command>passwd(1)</command> program does). The password has
@@ -298,7 +311,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-r</term>
+ <term>-r|--modify</term>
<listitem><para>This option is used to modify an existing user
in the database. This command needs a user name specified with the -u
switch. Other options can be specified to modify the properties of
@@ -308,7 +321,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-m</term>
+ <term>-m|--machine</term>
<listitem><para>This option may only be used in conjunction
with the <parameter>-a</parameter> option. It will make
pdbedit to add a machine trust account instead of a user
@@ -321,7 +334,7 @@ retype new password
<varlistentry>
- <term>-x</term>
+ <term>-x|--delete</term>
<listitem><para>This option causes pdbedit to delete an account
from the database. It needs a username specified with the
-u switch.</para>
@@ -332,7 +345,7 @@ retype new password
<varlistentry>
- <term>-i passdb-backend</term>
+ <term>-i|--import passdb-backend</term>
<listitem><para>Use a different passdb backend to retrieve users
than the one specified in smb.conf. Can be used to import data into
your local user database.</para>
@@ -346,7 +359,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-e passdb-backend</term>
+ <term>-e|--export passdb-backend</term>
<listitem><para>Exports all currently available users to the
specified password database backend.</para>
@@ -358,7 +371,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-g</term>
+ <term>-g|--group</term>
<listitem><para>If you specify <parameter>-g</parameter>,
then <parameter>-i in-backend -e out-backend</parameter>
applies to the group mapping instead of the user database.</para>
@@ -370,7 +383,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-b passdb-backend</term>
+ <term>-b|--backend passdb-backend</term>
<listitem><para>Use a different default passdb backend. </para>
<para>Example: <command>pdbedit -b xml:/root/pdb-backup.xml -l</command></para>
@@ -378,7 +391,7 @@ retype new password
</varlistentry>
<varlistentry>
- <term>-P account-policy</term>
+ <term>-P|--account-policy account-policy</term>
<listitem><para>Display an account policy</para>
<para>Valid policies are: minimum password age, reset count minutes, disconnect time,
user must logon to change password, password history, lockout duration, min password length,
@@ -394,7 +407,7 @@ account policy value for bad lockout attempt is 0
<varlistentry>
- <term>-C account-policy-value</term>
+ <term>-C|--value account-policy-value</term>
<listitem><para>Sets an account policy to a specified value.
This option may only be used in conjunction
with the <parameter>-P</parameter> option.
@@ -409,7 +422,7 @@ account policy value for bad lockout attempt is now 3
</varlistentry>
<varlistentry>
- <term>-y</term>
+ <term>-y|--policies</term>
<listitem><para>If you specify <parameter>-y</parameter>,
then <parameter>-i in-backend -e out-backend</parameter>
applies to the account policies instead of the user database.</para>
@@ -422,6 +435,73 @@ account policy value for bad lockout attempt is now 3
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>--force-initialized-passwords</term>
+ <listitem><para>This option forces all users to change their
+ password upon next login.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-N|--account-desc description</term>
+ <listitem><para>This option can be used while adding or
+ modifing a user account. It will specify the user's description
+ field.</para>
+
+ <para>Example: <command>-N "test description"</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-Z|--logon-hours-reset</term>
+ <listitem><para>This option can be used while adding or
+ modifing a user account. It will reset the user's allowed logon
+ hours. A user may login at any time afterwards.</para>
+
+ <para>Example: <command>-Z</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-z|--bad-password-count-reset</term>
+ <listitem><para>This option can be used while adding or
+ modifing a user account. It will reset the stored bad login
+ counter from a specified user.</para>
+
+ <para>Example: <command>-z</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--policies-reset</term>
+ <listitem><para>This option can be used to reset the general
+ password policies stored for a domain to their
+ default values.</para>
+ <para>Example: <command>--policies-reset</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-I|--domain</term>
+ <listitem><para>This option can be used while adding or
+ modifing a user account. It will specify the user's domain field.</para>
+
+ <para>Example: <command>-I "MYDOMAIN"</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--time-format</term>
+ <listitem><para>This option is currently not being used.</para>
+ </listitem>
+ </varlistentry>
+
&stdarg.help;
&stdarg.server.debug;
&popt.common.samba;
diff --git a/docs-xml/manpages-3/rpcclient.1.xml b/docs-xml/manpages-3/rpcclient.1.xml
index f7cef5f1fb..1a546a9598 100644
--- a/docs-xml/manpages-3/rpcclient.1.xml
+++ b/docs-xml/manpages-3/rpcclient.1.xml
@@ -29,7 +29,6 @@
<arg choice="opt">-s &lt;smb config file&gt;</arg>
<arg choice="opt">-U username[%password]</arg>
<arg choice="opt">-W workgroup</arg>
- <arg choice="opt">-N</arg>
<arg choice="opt">-I destinationIP</arg>
<arg choice="req">server</arg>
</cmdsynopsis>
@@ -70,7 +69,7 @@
<varlistentry>
- <term>-I IP-address</term>
+ <term>-I|--dest-ip IP-address</term>
<listitem><para><replaceable>IP address</replaceable> is the address of the server to connect to.
It should be specified in standard "a.b.c.d" notation. </para>
@@ -87,6 +86,14 @@
above. </para></listitem>
</varlistentry>
+ <varlistentry>
+ <term>-p|--port port</term>
+ <listitem><para>This number is the TCP port number that will be used
+ when making connections to the server. The standard (well-known)
+ TCP port number for an SMB/CIFS server is 139, which is the
+ default. </para></listitem>
+ </varlistentry>
+
&stdarg.server.debug;
&popt.common.samba;
&popt.common.credentials;
diff --git a/docs-xml/manpages-3/smbcacls.1.xml b/docs-xml/manpages-3/smbcacls.1.xml
index 30b389e9d0..3e63b9b0d4 100644
--- a/docs-xml/manpages-3/smbcacls.1.xml
+++ b/docs-xml/manpages-3/smbcacls.1.xml
@@ -55,7 +55,7 @@
<variablelist>
<varlistentry>
- <term>-a acls</term>
+ <term>-a|--add acls</term>
<listitem><para>Add the ACLs specified to the ACL list. Existing
access control entries are unchanged. </para></listitem>
</varlistentry>
@@ -63,7 +63,7 @@
<varlistentry>
- <term>-M acls</term>
+ <term>-M|--modify acls</term>
<listitem><para>Modify the mask value (permissions) for the ACLs
specified on the command line. An error will be printed for each
ACL specified that was not already present in the ACL list
@@ -73,7 +73,7 @@
<varlistentry>
- <term>-D acls</term>
+ <term>-D|--delete acls</term>
<listitem><para>Delete any ACLs specified on the command line.
An error will be printed for each ACL specified that was not
already present in the ACL list. </para></listitem>
@@ -82,7 +82,7 @@
<varlistentry>
- <term>-S acls</term>
+ <term>-S|--set acls</term>
<listitem><para>This command sets the ACLs on the file with
only the ones specified on the command line. All other ACLs are
erased. Note that the ACL specified must contain at least a revision,
@@ -92,20 +92,7 @@
<varlistentry>
- <term>-U username</term>
- <listitem><para>Specifies a username used to connect to the
- specified service. The username may be of the form "username" in
- which case the user is prompted to enter in a password and the
- workgroup specified in the <citerefentry><refentrytitle>smb.conf</refentrytitle>
- <manvolnum>5</manvolnum></citerefentry> file is
- used, or "username%password" or "DOMAIN\username%password" and the
- password and workgroup names are used as provided. </para></listitem>
- </varlistentry>
-
-
-
- <varlistentry>
- <term>-C name</term>
+ <term>-C|--chown name</term>
<listitem><para>The owner of a file or directory can be changed
to the name given using the <parameter>-C</parameter> option.
The name can be a sid in the form S-1-x-y-z or a name resolved
@@ -118,7 +105,7 @@
<varlistentry>
- <term>-G name</term>
+ <term>-G|--chgrp name</term>
<listitem><para>The group owner of a file or directory can
be changed to the name given using the <parameter>-G</parameter>
option. The name can be a sid in the form S-1-x-y-z or a name
@@ -138,7 +125,7 @@
</varlistentry>
<varlistentry>
- <term>-t</term>
+ <term>-t|--test-args</term>
<listitem><para>
Don't actually do anything, only validate the correctness of
the arguments.
@@ -148,6 +135,7 @@
&stdarg.help;
&stdarg.server.debug;
&popt.common.samba;
+ &popt.common.credentials;
</variablelist>
</refsect1>
diff --git a/docs-xml/manpages-3/smbclient.1.xml b/docs-xml/manpages-3/smbclient.1.xml
index 6b4311d933..9c3a97f6de 100644
--- a/docs-xml/manpages-3/smbclient.1.xml
+++ b/docs-xml/manpages-3/smbclient.1.xml
@@ -144,7 +144,7 @@
</varlistentry>
<varlistentry>
- <term>-R &lt;name resolve order&gt;</term>
+ <term>-R|--name-resolve &lt;name resolve order&gt;</term>
<listitem><para>This option is used by the programs in the Samba
suite to determine what naming services and in what order to resolve
host names to IP addresses. The option takes a space-separated
@@ -201,7 +201,7 @@
<varlistentry>
- <term>-M NetBIOS name</term>
+ <term>-M|--message NetBIOS name</term>
<listitem><para>This options allows you to send messages, using
the "WinPopup" protocol, to another computer. Once a connection is
established you then type your message, pressing ^D (control-D) to
@@ -237,7 +237,7 @@
</varlistentry>
<varlistentry>
- <term>-p port</term>
+ <term>-p|--port port</term>
<listitem><para>This number is the TCP port number that will be used
when making connections to the server. The standard (well-known)
TCP port number for an SMB/CIFS server is 139, which is the
@@ -245,7 +245,7 @@
</varlistentry>
<varlistentry>
- <term>-g</term>
+ <term>-g|--grepable</term>
<listitem><para>This parameter provides combined with
<parameter>-L</parameter> easy parseable output that allows processing
with utilities such as grep and cut.
@@ -253,6 +253,12 @@
</varlistentry>
<varlistentry>
+ <term>-m|--max-protocol protocol</term>
+ <listitem><para>This parameter sets the maximum protocol version announced by the client.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-P</term>
<listitem><para>
Make queries to the external server using the machine account of the local server.
@@ -262,7 +268,7 @@
&stdarg.help;
<varlistentry>
- <term>-I IP-address</term>
+ <term>-I|--ip-address IP-address</term>
<listitem><para><replaceable>IP address</replaceable> is the address of the server to connect to.
It should be specified in standard "a.b.c.d" notation. </para>
@@ -280,7 +286,7 @@
</varlistentry>
<varlistentry>
- <term>-E</term>
+ <term>-E|--stderr</term>
<listitem><para>This parameter causes the client to write messages
to the standard error stream (stderr) rather than to the standard
output stream. </para>
@@ -290,7 +296,7 @@
</varlistentry>
<varlistentry>
- <term>-L</term>
+ <term>-L|--list</term>
<listitem><para>This option allows you to look at what services
are available on a server. You use it as <command>smbclient -L
host</command> and a list should appear. The <parameter>-I
@@ -300,7 +306,7 @@
</varlistentry>
<varlistentry>
- <term>-b buffersize</term>
+ <term>-b|--send-buffer buffersize</term>
<listitem><para>This option changes the transmit/send buffer
size when getting or putting a file from/to the server. The default
is 65520 bytes. Setting this value smaller (to 1200 bytes) has been
@@ -326,7 +332,7 @@
&popt.common.connection;
<varlistentry>
- <term>-T tar options</term>
+ <term>-T|--tar tar options</term>
<listitem><para>smbclient may be used to create <command>tar(1)
</command> compatible backups of all the files on an SMB/CIFS
share. The secondary tar flags that can be given to this option
@@ -455,13 +461,13 @@
</varlistentry>
<varlistentry>
- <term>-D initial directory</term>
+ <term>-D|--directory initial directory</term>
<listitem><para>Change to initial directory before starting. Probably
only of any use with the tar -T option. </para></listitem>
</varlistentry>
<varlistentry>
- <term>-c command string</term>
+ <term>-c|--comand command string</term>
<listitem><para>command string is a semicolon-separated list of
commands to be executed instead of prompting from stdin. <parameter>
-N</parameter> is implied by <parameter>-c</parameter>.</para>
diff --git a/docs-xml/manpages-3/smbget.1.xml b/docs-xml/manpages-3/smbget.1.xml
index 1260ad1d88..e4094ab096 100644
--- a/docs-xml/manpages-3/smbget.1.xml
+++ b/docs-xml/manpages-3/smbget.1.xml
@@ -34,6 +34,7 @@
<arg choice="opt">-q, --quiet</arg>
<arg choice="opt">-v, --verbose</arg>
<arg choice="opt">-b, --blocksize</arg>
+ <arg choice="opt">-O, --stdout</arg>
<arg choice="opt">-?, --help</arg>
<arg choice="opt">--usage</arg>
<arg choice="req">smb://host/share/path/to/file</arg>
@@ -112,7 +113,12 @@
<varlistentry>
<term>-o, --outputfile</term>
- <listitem><para>Write the file that is being download to the specified file. Can not be used together with -R.</para></listitem>
+ <listitem><para>Write the file that is being downloaded to the specified file. Can not be used together with -R.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O, --stdout</term>
+ <listitem><para>Write the file that is being downloaded to standard output.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/docs-xml/manpages-3/smbtree.1.xml b/docs-xml/manpages-3/smbtree.1.xml
index 3864a61620..d69aef13ba 100644
--- a/docs-xml/manpages-3/smbtree.1.xml
+++ b/docs-xml/manpages-3/smbtree.1.xml
@@ -46,21 +46,21 @@
<variablelist>
<varlistentry>
- <term>-b</term>
+ <term>-b|--broadcast</term>
<listitem><para>Query network nodes by sending requests
as broadcasts instead of querying the local master browser.
</para></listitem>
</varlistentry>
<varlistentry>
- <term>-D</term>
+ <term>-D|--domains</term>
<listitem><para>Only print a list of all
the domains known on broadcast or by the
master browser</para></listitem>
</varlistentry>
<varlistentry>
- <term>-S</term>
+ <term>-S|--servers</term>
<listitem><para>Only print a list of
all the domains and servers responding on broadcast or
known by the master browser.
diff --git a/docs-xml/manpages-3/tdbbackup.8.xml b/docs-xml/manpages-3/tdbbackup.8.xml
index 5c42371ea2..78fe32eb8e 100644
--- a/docs-xml/manpages-3/tdbbackup.8.xml
+++ b/docs-xml/manpages-3/tdbbackup.8.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="tdbbackup.8">
<refmeta>
diff --git a/docs-xml/manpages-3/tdbdump.8.xml b/docs-xml/manpages-3/tdbdump.8.xml
index 8e42e08622..90465e53e8 100644
--- a/docs-xml/manpages-3/tdbdump.8.xml
+++ b/docs-xml/manpages-3/tdbdump.8.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="tdbdump.8">
<refmeta>
diff --git a/docs-xml/manpages-3/tdbtool.8.xml b/docs-xml/manpages-3/tdbtool.8.xml
index 042c88cdc6..9f96db277d 100644
--- a/docs-xml/manpages-3/tdbtool.8.xml
+++ b/docs-xml/manpages-3/tdbtool.8.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="tdbtool.8">
<refmeta>
diff --git a/lib/replace/libreplace.m4 b/lib/replace/libreplace.m4
index af8587938d..1353c1f7d2 100644
--- a/lib/replace/libreplace.m4
+++ b/lib/replace/libreplace.m4
@@ -228,6 +228,8 @@ AC_HAVE_DECL(environ, [#include <unistd.h>])
AC_CHECK_FUNCS(strnlen)
AC_CHECK_FUNCS(strtoull __strtoull strtouq strtoll __strtoll strtoq)
+AC_CHECK_FUNCS(memmem)
+
# this test disabled as we don't actually need __VA_ARGS__ yet
AC_TRY_CPP([
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index fc15717349..17fd46bcc8 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -681,3 +681,26 @@ char *rep_realpath(const char *path, char *resolved_path)
return NULL;
}
#endif
+
+
+#ifndef HAVE_MEMMEM
+void *rep_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ if (needlelen == 0) {
+ return discard_const(haystack);
+ }
+ while (haystacklen >= needlelen) {
+ char *p = memchr(haystack, *(const char *)needle,
+ haystacklen-(needlelen-1));
+ if (!p) return NULL;
+ if (memcmp(p, needle, needlelen) == 0) {
+ return p;
+ }
+ haystack = p+1;
+ haystacklen -= (p - (const char *)haystack) + 1;
+ }
+ return NULL;
+}
+#endif
+
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index 6424d10c0f..baf2368130 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -140,6 +140,12 @@ char *rep_strdup(const char *s);
void *rep_memmove(void *dest,const void *src,int size);
#endif
+#ifndef HAVE_MEMMEM
+#define memmem rep_memmem
+void *rep_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
#ifndef HAVE_MKTIME
#define mktime rep_mktime
/* prototype is in "system/time.h" */
diff --git a/lib/replace/snprintf.c b/lib/replace/snprintf.c
index c54d721ce5..bca774263e 100644
--- a/lib/replace/snprintf.c
+++ b/lib/replace/snprintf.c
@@ -504,6 +504,7 @@ static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in
break;
case 'p':
cnk->type = CNK_PTR;
+ cnk->flags |= DP_F_UNSIGNED;
break;
case 'n':
cnk->type = CNK_NUM;
diff --git a/lib/replace/test/testsuite.c b/lib/replace/test/testsuite.c
index 7929f11add..caa70d68e3 100644
--- a/lib/replace/test/testsuite.c
+++ b/lib/replace/test/testsuite.c
@@ -1015,6 +1015,42 @@ static int test_utimes(void)
return true;
}
+static int test_memmem(void)
+{
+ char *s;
+
+ printf("test: memmem\n");
+
+ s = memmem("foo", 3, "fo", 2);
+ if (strcmp(s, "foo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = memmem("foo", 3, "", 0);
+ if (strcmp(s, "foo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = memmem("foo", 4, "o", 1);
+ if (strcmp(s, "oo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = memmem("foobarfodx", 11, "fod", 3);
+ if (strcmp(s, "fodx") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ printf("success: memmem\n");
+
+ return true;
+}
+
+
struct torture_context;
bool torture_local_replace(struct torture_context *ctx)
{
@@ -1065,6 +1101,7 @@ bool torture_local_replace(struct torture_context *ctx)
ret &= test_getifaddrs();
ret &= test_utime();
ret &= test_utimes();
+ ret &= test_memmem();
return ret;
}
diff --git a/lib/tdb/Makefile.in b/lib/tdb/Makefile.in
index 93bfe37f4f..3abeec3258 100644
--- a/lib/tdb/Makefile.in
+++ b/lib/tdb/Makefile.in
@@ -31,18 +31,22 @@ PYTHON_CHECK_TARGET = @PYTHON_CHECK_TARGET@
LIB_PATH_VAR = @LIB_PATH_VAR@
tdbdir = @tdbdir@
+EXTRA_TARGETS = @DOC_TARGET@
+
TDB_OBJ = @TDB_OBJ@ @LIBREPLACEOBJ@
SONAMEFLAG = @SONAMEFLAG@
VERSIONSCRIPT = @VERSIONSCRIPT@
EXPORTSFILE = @EXPORTSFILE@
+XSLTPROC = @XSLTPROC@
+
default: all
include $(tdbdir)/tdb.mk
include $(tdbdir)/rules.mk
-all:: showflags dirs $(PROGS) $(TDB_SOLIB) libtdb.a $(PYTHON_BUILD_TARGET)
+all:: showflags dirs $(PROGS) $(TDB_SOLIB) libtdb.a $(PYTHON_BUILD_TARGET) $(EXTRA_TARGETS)
install:: all
$(TDB_SOLIB): $(TDB_OBJ)
diff --git a/lib/tdb/configure.ac b/lib/tdb/configure.ac
index 779f596e18..dac7bb2673 100644
--- a/lib/tdb/configure.ac
+++ b/lib/tdb/configure.ac
@@ -38,6 +38,13 @@ AC_ARG_ENABLE(python,
fi
])
+AC_PATH_PROG(XSLTPROC,xsltproc)
+DOC_TARGET=""
+if test -n "$XSLTPROC"; then
+ DOC_TARGET=doc
+fi
+AC_SUBST(DOC_TARGET)
+
m4_include(build_macros.m4)
BUILD_WITH_SHARED_BUILD_DIR
diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h
index db9ce4ad27..c9e946a885 100644
--- a/lib/tdb/include/tdb.h
+++ b/lib/tdb/include/tdb.h
@@ -143,7 +143,7 @@ void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
void tdb_enable_seqnum(struct tdb_context *tdb);
void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
int tdb_check(struct tdb_context *tdb,
- int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+ int (*check) (TDB_DATA key, TDB_DATA data, void *private_data),
void *private_data);
/* Low level locking functions: use with care */
diff --git a/lib/tdb/manpages/tdbbackup.8.xml b/lib/tdb/manpages/tdbbackup.8.xml
new file mode 100644
index 0000000000..5c42371ea2
--- /dev/null
+++ b/lib/tdb/manpages/tdbbackup.8.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="tdbbackup.8">
+
+<refmeta>
+ <refentrytitle>tdbbackup</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbbackup</refname>
+ <refpurpose>tool for backing up and for validating the integrity of samba .tdb files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>tdbbackup</command>
+ <arg choice="opt">-s suffix</arg>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-h</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbbackup</command> is a tool that may be used to backup samba .tdb
+ files. This tool may also be used to verify the integrity of the .tdb files prior
+ to samba startup or during normal operation. If it finds file damage and it finds
+ a prior backup the backup file will be restored.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Get help information.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s suffix</term>
+ <listitem><para>
+ The <command>-s</command> option allows the adminisistrator to specify a file
+ backup extension. This way it is possible to keep a history of tdb backup
+ files by using a new suffix for each backup.
+ </para> </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>
+ The <command>-v</command> will check the database for damages (currupt data)
+ which if detected causes the backup to be restored.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>COMMANDS</title>
+
+ <para><emphasis>GENERAL INFORMATION</emphasis></para>
+
+ <para>
+ The <command>tdbbackup</command> utility can safely be run at any time. It was designed so
+ that it can be used at any time to validate the integrity of tdb files, even during Samba
+ operation. Typical usage for the command will be:
+ </para>
+
+ <para>tdbbackup [-s suffix] *.tdb</para>
+
+ <para>
+ Before restarting samba the following command may be run to validate .tdb files:
+ </para>
+
+ <para>tdbbackup -v [-s suffix] *.tdb</para>
+
+ <para>
+ Samba .tdb files are stored in various locations, be sure to run backup all
+ .tdb file on the system. Important files includes:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <command>secrets.tdb</command> - usual location is in the /usr/local/samba/private
+ directory, or on some systems in /etc/samba.
+ </para></listitem>
+
+ <listitem><para>
+ <command>passdb.tdb</command> - usual location is in the /usr/local/samba/private
+ directory, or on some systems in /etc/samba.
+ </para></listitem>
+
+ <listitem><para>
+ <command>*.tdb</command> located in the /usr/local/samba/var directory or on some
+ systems in the /var/cache or /var/lib/samba directories.
+ </para></listitem>
+ </itemizedlist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities were created by Andrew Tridgell.
+ Samba is now developed by the Samba Team as an Open Source project similar to the way
+ the Linux kernel is developed.
+ </para>
+
+ <para>The tdbbackup man page was written by John H Terpstra.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/manpages/tdbdump.8.xml b/lib/tdb/manpages/tdbdump.8.xml
new file mode 100644
index 0000000000..8e42e08622
--- /dev/null
+++ b/lib/tdb/manpages/tdbdump.8.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="tdbdump.8">
+
+<refmeta>
+ <refentrytitle>tdbdump</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbdump</refname>
+ <refpurpose>tool for printing the contents of a TDB file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>tdbdump</command>
+ <arg choice="req">filename</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbdump</command> is a very simple utility that 'dumps' the
+ contents of a TDB (Trivial DataBase) file to standard output in a
+ human-readable format.
+ </para>
+
+ <para>This tool can be used when debugging problems with TDB files. It is
+ intended for those who are somewhat familiar with Samba internals.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities were created by Andrew Tridgell.
+ Samba is now developed by the Samba Team as an Open Source project similar to the way
+ the Linux kernel is developed.
+ </para>
+
+ <para>The tdbdump man page was written by Jelmer Vernooij.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/manpages/tdbtool.8.xml b/lib/tdb/manpages/tdbtool.8.xml
new file mode 100644
index 0000000000..042c88cdc6
--- /dev/null
+++ b/lib/tdb/manpages/tdbtool.8.xml
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="tdbtool.8">
+
+<refmeta>
+ <refentrytitle>tdbtool</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbtool</refname>
+ <refpurpose>manipulate the contents TDB files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+
+ <cmdsynopsis>
+ <command>tdbtool</command>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>tdbtool</command>
+ <arg choice="plain">
+ <replaceable>TDBFILE</replaceable>
+ </arg>
+ <arg rep="repeat" choice="opt">
+ <replaceable>COMMANDS</replaceable>
+ </arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the
+ <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbtool</command> a tool for displaying and
+ altering the contents of Samba TDB (Trivial DataBase) files. Each
+ of the commands listed below can be entered interactively or
+ provided on the command line.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>COMMANDS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><option>create</option>
+ <replaceable>TDBFILE</replaceable></term>
+ <listitem><para>Create a new database named
+ <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>open</option>
+ <replaceable>TDBFILE</replaceable></term>
+ <listitem><para>Open an existing database named
+ <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>erase</option></term>
+ <listitem><para>Erase the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>dump</option></term>
+ <listitem><para>Dump the current database as strings.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>cdump</option></term>
+ <listitem><para>Dump the current database as connection records.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>keys</option></term>
+ <listitem><para>Dump the current database keys as strings.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>hexkeys</option></term>
+ <listitem><para>Dump the current database keys as hex values.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>info</option></term>
+ <listitem><para>Print summary information about the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>insert</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Insert a record into the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>move</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>TDBFILE</replaceable>
+ </term>
+ <listitem><para>Move a record from the
+ current database into <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>store</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Store (replace) a record in the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>show</option>
+ <replaceable>KEY</replaceable>
+ </term>
+ <listitem><para>Show a record by key.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>delete</option>
+ <replaceable>KEY</replaceable>
+ </term>
+ <listitem><para>Delete a record by key.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>list</option>
+ </term>
+ <listitem><para>Print the current database hash table and free list.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>free</option>
+ </term>
+ <listitem><para>Print the current database and free list.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>!</option>
+ <replaceable>COMMAND</replaceable>
+ </term>
+ <listitem><para>Execute the given system command.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>first</option>
+ </term>
+ <listitem><para>Print the first record in the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>next</option>
+ </term>
+ <listitem><para>Print the next record in the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>check</option>
+ </term>
+ <listitem><para>Check the integrity of the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>quit</option>
+ </term>
+ <listitem><para>Exit <command>tdbtool</command>.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>CAVEATS</title>
+ <para>The contents of the Samba TDB files are private
+ to the implementation and should not be altered with
+ <command>tdbtool</command>.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+ <para>This man page is correct for version 3.0.25 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> The original Samba software and related utilities were
+ created by Andrew Tridgell. Samba is now developed by the
+ Samba Team as an Open Source project similar to the way the
+ Linux kernel is developed.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/tdb.mk b/lib/tdb/tdb.mk
index 267c2d1c85..93aa899480 100644
--- a/lib/tdb/tdb.mk
+++ b/lib/tdb/tdb.mk
@@ -51,7 +51,20 @@ tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) pytdb.o
$(SHLD) $(SHLD_FLAGS) -o $@ pytdb.o -L. -ltdb `$(PYTHON_CONFIG) --ldflags`
install:: installdirs installbin installheaders installlibs \
- $(PYTHON_INSTALL_TARGET)
+ $(PYTHON_INSTALL_TARGET) installdocs
+
+doc:: manpages/tdbbackup.8 manpages/tdbdump.8 manpages/tdbtool.8
+
+.SUFFIXES: .8.xml .8
+
+.8.xml.8:
+ -test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+installdocs::
+ ${INSTALLCMD} -d $(DESTDIR)$(mandir)/man1
+ for I in manpages/*.1; do \
+ ${INSTALLCMD} -m 644 $$I $(DESTDIR)$(mandir)/man1 \
+ done
install-python:: build-python
mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`
diff --git a/lib/tdb/tdb.signatures b/lib/tdb/tdb.signatures
index 93edb071be..61b8c1dac4 100644
--- a/lib/tdb/tdb.signatures
+++ b/lib/tdb/tdb.signatures
@@ -56,5 +56,5 @@ void tdb_remove_flags (struct tdb_context *, unsigned int);
void tdb_setalarm_sigptr (struct tdb_context *, volatile sig_atomic_t *);
void tdb_set_logging_function (struct tdb_context *, const struct tdb_logging_context *);
void tdb_set_max_dead (struct tdb_context *, int);
-int tdb_check (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *);
+int tdb_check (struct tdb_context *, int (*) (TDB_DATA, TDB_DATA, void *), void *);
TDB_DATA tdb_null;
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index ab170a66cf..0f3d83e877 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -30,23 +30,23 @@
#include "tevent_internal.h"
#include "tevent_util.h"
-#define NUM_SIGNALS 64
+#define TEVENT_NUM_SIGNALS 64
/* maximum number of SA_SIGINFO signals to hold in the queue.
NB. This *MUST* be a power of 2, in order for the ring buffer
wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
for this. */
-#define SA_INFO_QUEUE_COUNT 64
+#define TEVENT_SA_INFO_QUEUE_COUNT 64
-struct sigcounter {
+struct tevent_sigcounter {
uint32_t count;
uint32_t seen;
};
-#define SIG_INCREMENT(s) (s).count++
-#define SIG_SEEN(s, n) (s).seen += (n)
-#define SIG_PENDING(s) ((s).seen != (s).count)
+#define TEVENT_SIG_INCREMENT(s) (s).count++
+#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
+#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
struct tevent_common_signal_list {
struct tevent_common_signal_list *prev, *next;
@@ -56,22 +56,22 @@ struct tevent_common_signal_list {
/*
the poor design of signals means that this table must be static global
*/
-static struct sig_state {
- struct tevent_common_signal_list *sig_handlers[NUM_SIGNALS+1];
- struct sigaction *oldact[NUM_SIGNALS+1];
- struct sigcounter signal_count[NUM_SIGNALS+1];
- struct sigcounter got_signal;
+static struct tevent_sig_state {
+ struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
+ struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter got_signal;
#ifdef SA_SIGINFO
/* with SA_SIGINFO we get quite a lot of info per signal */
- siginfo_t *sig_info[NUM_SIGNALS+1];
- struct sigcounter sig_blocked[NUM_SIGNALS+1];
+ siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
#endif
} *sig_state;
/*
return number of sigcounter events not processed yet
*/
-static uint32_t sig_count(struct sigcounter s)
+static uint32_t tevent_sig_count(struct tevent_sigcounter s)
{
return s.count - s.seen;
}
@@ -87,8 +87,8 @@ static void tevent_common_signal_handler(int signum)
struct tevent_context *ev = NULL;
int saved_errno = errno;
- SIG_INCREMENT(sig_state->signal_count[signum]);
- SIG_INCREMENT(sig_state->got_signal);
+ TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
+ TEVENT_SIG_INCREMENT(sig_state->got_signal);
/* Write to each unique event context. */
for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
@@ -109,24 +109,24 @@ static void tevent_common_signal_handler(int signum)
static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
void *uctx)
{
- uint32_t count = sig_count(sig_state->signal_count[signum]);
- /* sig_state->signal_count[signum].seen % SA_INFO_QUEUE_COUNT
+ uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
+ /* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
* is the base of the unprocessed signals in the ringbuffer. */
uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
- SA_INFO_QUEUE_COUNT;
+ TEVENT_SA_INFO_QUEUE_COUNT;
sig_state->sig_info[signum][ofs] = *info;
tevent_common_signal_handler(signum);
/* handle SA_SIGINFO */
- if (count+1 == SA_INFO_QUEUE_COUNT) {
+ if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
/* we've filled the info array - block this signal until
these ones are delivered */
sigset_t set;
sigemptyset(&set);
sigaddset(&set, signum);
sigprocmask(SIG_BLOCK, &set, NULL);
- SIG_INCREMENT(sig_state->sig_blocked[signum]);
+ TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
}
}
#endif
@@ -196,7 +196,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
struct tevent_common_signal_list *sl;
sigset_t set, oldset;
- if (signum >= NUM_SIGNALS) {
+ if (signum >= TEVENT_NUM_SIGNALS) {
errno = EINVAL;
return NULL;
}
@@ -204,7 +204,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
/* the sig_state needs to be on a global context as it can last across
multiple event contexts */
if (sig_state == NULL) {
- sig_state = talloc_zero(talloc_autofree_context(), struct sig_state);
+ sig_state = talloc_zero(talloc_autofree_context(), struct tevent_sig_state);
if (sig_state == NULL) {
return NULL;
}
@@ -267,7 +267,9 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
act.sa_handler = NULL;
act.sa_sigaction = tevent_common_signal_handler_info;
if (sig_state->sig_info[signum] == NULL) {
- sig_state->sig_info[signum] = talloc_zero_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT);
+ sig_state->sig_info[signum] =
+ talloc_zero_array(sig_state, siginfo_t,
+ TEVENT_SA_INFO_QUEUE_COUNT);
if (sig_state->sig_info[signum] == NULL) {
talloc_free(se);
return NULL;
@@ -310,14 +312,14 @@ int tevent_common_check_signal(struct tevent_context *ev)
{
int i;
- if (!sig_state || !SIG_PENDING(sig_state->got_signal)) {
+ if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
return 0;
}
- for (i=0;i<NUM_SIGNALS+1;i++) {
+ for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
struct tevent_common_signal_list *sl, *next;
- struct sigcounter counter = sig_state->signal_count[i];
- uint32_t count = sig_count(counter);
+ struct tevent_sigcounter counter = sig_state->signal_count[i];
+ uint32_t count = tevent_sig_count(counter);
#ifdef SA_SIGINFO
/* Ensure we null out any stored siginfo_t entries
* after processing for debugging purposes. */
@@ -338,11 +340,11 @@ int tevent_common_check_signal(struct tevent_context *ev)
for (j=0;j<count;j++) {
/* sig_state->signal_count[i].seen
- * % SA_INFO_QUEUE_COUNT is
+ * % TEVENT_SA_INFO_QUEUE_COUNT is
* the base position of the unprocessed
* signals in the ringbuffer. */
uint32_t ofs = (counter.seen + j)
- % SA_INFO_QUEUE_COUNT;
+ % TEVENT_SA_INFO_QUEUE_COUNT;
se->handler(ev, se, i, 1,
(void*)&sig_state->sig_info[i][ofs],
se->private_data);
@@ -364,7 +366,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
uint32_t j;
for (j=0;j<count;j++) {
uint32_t ofs = (counter.seen + j)
- % SA_INFO_QUEUE_COUNT;
+ % TEVENT_SA_INFO_QUEUE_COUNT;
memset((void*)&sig_state->sig_info[i][ofs],
'\0',
sizeof(siginfo_t));
@@ -372,23 +374,23 @@ int tevent_common_check_signal(struct tevent_context *ev)
}
#endif
- SIG_SEEN(sig_state->signal_count[i], count);
- SIG_SEEN(sig_state->got_signal, count);
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
+ TEVENT_SIG_SEEN(sig_state->got_signal, count);
#ifdef SA_SIGINFO
- if (SIG_PENDING(sig_state->sig_blocked[i])) {
+ if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
/* We'd filled the queue, unblock the
signal now the queue is empty again.
Note we MUST do this after the
- SIG_SEEN(sig_state->signal_count[i], count)
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
call to prevent a new signal running
out of room in the sig_state->sig_info[i][]
ring buffer. */
sigset_t set;
sigemptyset(&set);
sigaddset(&set, i);
- SIG_SEEN(sig_state->sig_blocked[i],
- sig_count(sig_state->sig_blocked[i]));
+ TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
+ tevent_sig_count(sig_state->sig_blocked[i]));
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
#endif
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 1c1e58099b..7c0255742c 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -210,11 +210,15 @@ int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
struct tsocket_address *addr;
struct tsocket_address_bsd *bsda;
+ if (sa_socklen < sizeof(sa->sa_family)) {
+ errno = EINVAL;
+ return -1;
+ }
+
switch (sa->sa_family) {
case AF_UNIX:
- if (sa_socklen < sizeof(struct sockaddr_un)) {
- errno = EINVAL;
- return -1;
+ if (sa_socklen > sizeof(struct sockaddr_un)) {
+ sa_socklen = sizeof(struct sockaddr_un);
}
break;
case AF_INET:
@@ -222,6 +226,7 @@ int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
errno = EINVAL;
return -1;
}
+ sa_socklen = sizeof(struct sockaddr_in);
break;
#ifdef HAVE_IPV6
case AF_INET6:
@@ -229,6 +234,7 @@ int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
errno = EINVAL;
return -1;
}
+ sa_socklen = sizeof(struct sockaddr_in6);
break;
#endif
default:
diff --git a/source3/libsmb/ntlmssp_ndr.c b/libcli/auth/ntlmssp_ndr.c
index 92cd677572..53a2378e20 100644
--- a/source3/libsmb/ntlmssp_ndr.c
+++ b/libcli/auth/ntlmssp_ndr.c
@@ -20,7 +20,7 @@
#include "includes.h"
#include "../librpc/gen_ndr/ndr_ntlmssp.h"
-#include "libsmb/ntlmssp_ndr.h"
+#include "../libcli/auth/ntlmssp_ndr.h"
#define NTLMSSP_PULL_MESSAGE(type, blob, mem_ctx, ic, r) \
do { \
diff --git a/source3/libsmb/ntlmssp_ndr.h b/libcli/auth/ntlmssp_ndr.h
index 52990b2a56..52990b2a56 100644
--- a/source3/libsmb/ntlmssp_ndr.h
+++ b/libcli/auth/ntlmssp_ndr.h
diff --git a/librpc/ndr/uuid.c b/librpc/ndr/uuid.c
index 429a1b1ac9..1899afbbca 100644
--- a/librpc/ndr/uuid.c
+++ b/librpc/ndr/uuid.c
@@ -241,23 +241,23 @@ _PUBLIC_ bool GUID_equal(const struct GUID *u1, const struct GUID *u2)
_PUBLIC_ int GUID_compare(const struct GUID *u1, const struct GUID *u2)
{
if (u1->time_low != u2->time_low) {
- return u1->time_low - u2->time_low;
+ return u1->time_low > u2->time_low ? 1 : -1;
}
if (u1->time_mid != u2->time_mid) {
- return u1->time_mid - u2->time_mid;
+ return u1->time_mid > u2->time_mid ? 1 : -1;
}
if (u1->time_hi_and_version != u2->time_hi_and_version) {
- return u1->time_hi_and_version - u2->time_hi_and_version;
+ return u1->time_hi_and_version > u2->time_hi_and_version ? 1 : -1;
}
if (u1->clock_seq[0] != u2->clock_seq[0]) {
- return u1->clock_seq[0] - u2->clock_seq[0];
+ return u1->clock_seq[0] > u2->clock_seq[0] ? 1 : -1;
}
if (u1->clock_seq[1] != u2->clock_seq[1]) {
- return u1->clock_seq[1] - u2->clock_seq[1];
+ return u1->clock_seq[1] > u2->clock_seq[1] ? 1 : -1;
}
return memcmp(u1->node, u2->node, 6);
diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c
index 7a66a7fe82..00863a0d54 100644
--- a/nsswitch/libwbclient/wbc_pam.c
+++ b/nsswitch/libwbclient/wbc_pam.c
@@ -5,6 +5,7 @@
Copyright (C) Gerald (Jerry) Carter 2007
Copyright (C) Guenther Deschner 2008
+ Copyright (C) Volker Lendecke 2009
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -570,6 +571,50 @@ wbcErr wbcChangeTrustCredentials(const char *domain,
return wbc_status;
}
+/*
+ * Trigger a no-op NETLOGON call. Lightweight version of
+ * wbcCheckTrustCredentials
+ */
+wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (domain) {
+ /*
+ * the current protocol doesn't support
+ * specifying a domain
+ */
+ wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_PING_DC,
+ &request,
+ &response);
+ if (response.data.auth.nt_status != 0) {
+ if (error) {
+ wbc_status = wbc_create_error_info(NULL,
+ &response,
+ error);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = WBC_ERR_AUTH_ERROR;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
/* Trigger an extended logoff notification to Winbind for a specific user */
wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
struct wbcAuthErrorInfo **error)
diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c
index 16828ae5df..24699e91c4 100644
--- a/nsswitch/libwbclient/wbc_util.c
+++ b/nsswitch/libwbclient/wbc_util.c
@@ -669,7 +669,7 @@ wbcErr wbcAddNamedBlob(size_t *num_blobs,
wbc_status = WBC_ERR_SUCCESS;
done:
- if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
wbcFreeMemory(*blobs);
}
return wbc_status;
diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h
index eea71ab86b..33a4ace75c 100644
--- a/nsswitch/libwbclient/wbclient.h
+++ b/nsswitch/libwbclient/wbclient.h
@@ -4,6 +4,7 @@
Winbind client API
Copyright (C) Gerald (Jerry) Carter 2007
+ Copyright (C) Volker Lendecke 2009
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -1214,6 +1215,19 @@ wbcErr wbcCheckTrustCredentials(const char *domain,
wbcErr wbcChangeTrustCredentials(const char *domain,
struct wbcAuthErrorInfo **error);
+/**
+ * @brief Trigger a no-op call through the NETLOGON pipe. Low-cost
+ * version of wbcCheckTrustCredentials
+ *
+ * @param *domain The name of the domain, only NULL for the default domain is
+ * supported yet. Other values than NULL will result in
+ * WBC_ERR_NOT_IMPLEMENTED.
+ * @param error Output details on WBC_ERR_AUTH_ERROR
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error);
+
/**********************************************************
* Helper functions
**********************************************************/
diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
index d3d9250e81..45d8684bad 100644
--- a/nsswitch/wbinfo.c
+++ b/nsswitch/wbinfo.c
@@ -5,6 +5,7 @@
Copyright (C) Tim Potter 2000-2003
Copyright (C) Andrew Bartlett 2002-2007
+ Copyright (C) Volker Lendecke 2009
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
@@ -779,6 +780,30 @@ static bool wbinfo_change_secret(const char *domain)
return true;
}
+/* Check DC connection */
+
+static bool wbinfo_ping_dc(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcAuthErrorInfo *error = NULL;
+
+ wbc_status = wbcPingDc(NULL, &error);
+
+ d_printf("checking the NETLOGON dc connection %s\n",
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ if (wbc_status == WBC_ERR_AUTH_ERROR) {
+ d_fprintf(stderr, "error code was %s (0x%x)\n",
+ error->nt_string, error->nt_status);
+ wbcFreeMemory(error);
+ }
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ return true;
+}
+
/* Convert uid to sid */
static bool wbinfo_uid_to_sid(uid_t uid)
@@ -1710,6 +1735,7 @@ enum {
OPT_VERBOSE,
OPT_ONLINESTATUS,
OPT_CHANGE_USER_PASSWORD,
+ OPT_PING_DC,
OPT_SID_TO_FULLNAME,
OPT_NTLMV2,
OPT_LANMAN
@@ -1759,6 +1785,8 @@ int main(int argc, char **argv, char **envp)
{ "remove-gid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_REMOVE_GID_MAPPING, "Remove gid to sid mapping in idmap", "GID,SID" },
{ "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
{ "change-secret", 'c', POPT_ARG_NONE, 0, 'c', "Change shared secret" },
+ { "ping-dc", 0, POPT_ARG_NONE, 0, OPT_PING_DC,
+ "Check the NETLOGON connection" },
{ "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
{ "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" },
{ "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" },
@@ -1995,6 +2023,12 @@ int main(int argc, char **argv, char **envp)
goto done;
}
break;
+ case OPT_PING_DC:
+ if (!wbinfo_ping_dc()) {
+ d_fprintf(stderr, "Could not ping our DC\n");
+ goto done;
+ }
+ break;
case 'm':
if (!wbinfo_list_domains(false, verbose)) {
d_fprintf(stderr,
diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h
index 3056e25905..4d27d5283c 100644
--- a/nsswitch/winbind_struct_protocol.h
+++ b/nsswitch/winbind_struct_protocol.h
@@ -47,8 +47,9 @@ typedef char fstring[FSTRING_LEN];
/* Update this when you change the interface.
* 21: added WINBINDD_GETPWSID
* added WINBINDD_GETSIDALIASES
+ * 22: added WINBINDD_PING_DC
*/
-#define WINBIND_INTERFACE_VERSION 21
+#define WINBIND_INTERFACE_VERSION 22
/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
On a 64bit Linux box, we have to support a constant structure size
@@ -119,6 +120,7 @@ enum winbindd_cmd {
WINBINDD_CHECK_MACHACC, /* Check machine account pw works */
WINBINDD_CHANGE_MACHACC, /* Change machine account pw */
+ WINBINDD_PING_DC, /* Ping the DC through NETLOGON */
WINBINDD_PING, /* Just tell me winbind is running */
WINBINDD_INFO, /* Various bit of info. Currently just tidbits */
WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */
diff --git a/source3/Makefile.in b/source3/Makefile.in
index b1f1658c68..1376f4c07a 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -482,7 +482,7 @@ LIBSMB_OBJ0 = \
libsmb/ntlmssp.o \
libsmb/ntlmssp_sign.o \
$(LIBNDR_NTLMSSP_OBJ) \
- libsmb/ntlmssp_ndr.o
+ ../libcli/auth/ntlmssp_ndr.o
LIBSAMBA_OBJ = $(LIBSMB_OBJ0) \
$(LIBSMB_ERR_OBJ)
@@ -862,10 +862,8 @@ STATUS_OBJ = utils/status.o utils/status_profile.o \
$(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
$(LIBSAMBA_OBJ) $(FNAME_UTIL_OBJ)
-SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
- $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
- $(LIBSAMBA_OBJ) $(FNAME_UTIL_OBJ) \
- $(PRINTBASE_OBJ)
+SMBCONTROL_OBJ = utils/smbcontrol.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSMB_ERR_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
$(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
@@ -1148,7 +1146,6 @@ IDMAP_ADEX_OBJ = \
WINBINDD_OBJ1 = \
winbindd/winbindd.o \
- winbindd/winbindd_user.o \
winbindd/winbindd_group.o \
winbindd/winbindd_util.o \
winbindd/winbindd_cache.o \
@@ -1226,6 +1223,7 @@ WINBINDD_OBJ1 = \
winbindd/winbindd_list_groups.o \
winbindd/winbindd_check_machine_acct.o \
winbindd/winbindd_change_machine_acct.o \
+ winbindd/winbindd_ping_dc.o \
winbindd/winbindd_set_mapping.o \
winbindd/winbindd_remove_mapping.o \
winbindd/winbindd_set_hwm.o \
diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
index 034d354a33..4243a24ca7 100644
--- a/source3/auth/auth_ntlmssp.c
+++ b/source3/auth/auth_ntlmssp.c
@@ -21,19 +21,21 @@
*/
#include "includes.h"
+#include "ntlmssp.h"
/**
* Return the challenge as determined by the authentication subsystem
* @return an 8 byte random challenge
*/
-static void auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
- uint8_t chal[8])
+static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
+ uint8_t chal[8])
{
AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
(AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
auth_ntlmssp_state->auth_context->get_ntlm_challenge(
auth_ntlmssp_state->auth_context, chal);
+ return NT_STATUS_OK;
}
/**
diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h
index 03dd274539..47fed92739 100644
--- a/source3/include/async_smb.h
+++ b/source3/include/async_smb.h
@@ -22,11 +22,6 @@
#include "includes.h"
-bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command,
- uint8_t wct, const uint16_t *vwv,
- size_t bytes_alignment,
- uint32_t num_bytes, const uint8_t *bytes);
-
/*
* Fetch an error out of a NBT packet
*/
diff --git a/source3/include/client.h b/source3/include/client.h
index 82d94b055f..d5030c1cb2 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -56,7 +56,7 @@ struct cli_pipe_auth_data {
union {
struct schannel_state *schannel_auth;
- NTLMSSP_STATE *ntlmssp_state;
+ struct ntlmssp_state *ntlmssp_state;
struct kerberos_auth_struct *kerberos_auth;
} a_u;
};
@@ -172,7 +172,7 @@ struct smb_trans_enc_state {
uint16 enc_ctx_num;
bool enc_on;
union {
- NTLMSSP_STATE *ntlmssp_state;
+ struct ntlmssp_state *ntlmssp_state;
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
struct smb_tran_enc_state_gss *gss_state;
#endif
diff --git a/source3/include/includes.h b/source3/include/includes.h
index cf0979592c..d9d51a8a99 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -659,7 +659,9 @@ struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx);
#include "../lib/crypto/arcfour.h"
#include "../lib/crypto/crc32.h"
#include "../lib/crypto/hmacmd5.h"
-#include "ntlmssp.h"
+
+struct ntlmssp_state;
+
#include "auth.h"
#include "ntdomain.h"
#include "reg_objects.h"
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
index 9f47c9c555..d3de59835f 100644
--- a/source3/include/ntlmssp.h
+++ b/source3/include/ntlmssp.h
@@ -20,14 +20,14 @@
*/
/* NTLMSSP mode */
-enum NTLMSSP_ROLE
+enum ntlmssp_role
{
NTLMSSP_SERVER,
NTLMSSP_CLIENT
};
/* NTLMSSP message types */
-enum NTLM_MESSAGE_TYPE
+enum ntlmssp_message_type
{
NTLMSSP_INITIAL = 0 /* samba internal state */,
NTLMSSP_NEGOTIATE = 1,
@@ -41,12 +41,11 @@ enum NTLM_MESSAGE_TYPE
#define NTLMSSP_FEATURE_SIGN 0x00000002
#define NTLMSSP_FEATURE_SEAL 0x00000004
-typedef struct ntlmssp_state
+struct ntlmssp_state
{
- unsigned int ref_count;
- enum NTLMSSP_ROLE role;
+ enum ntlmssp_role role;
enum server_types server_role;
- uint32 expected_state;
+ uint32_t expected_state;
bool unicode;
bool use_ntlmv2;
@@ -60,11 +59,11 @@ typedef struct ntlmssp_state
DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */
- DATA_BLOB lm_resp;
+ DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DATA_BLOB session_key;
- uint32 neg_flags; /* the current state of negotiation with the NTLMSSP partner */
+ uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
void *auth_context;
@@ -72,11 +71,11 @@ typedef struct ntlmssp_state
* Callback to get the 'challenge' used for NTLM authentication.
*
* @param ntlmssp_state This structure
- * @return 8 bytes of challnege data, determined by the server to be the challenge for NTLM authentication
+ * @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication
*
*/
- void (*get_challenge)(const struct ntlmssp_state *ntlmssp_state,
- uint8_t challenge[8]);
+ NTSTATUS (*get_challenge)(const struct ntlmssp_state *ntlmssp_state,
+ uint8_t challenge[8]);
/**
* Callback to find if the challenge used by NTLM authentication may be modified
@@ -126,15 +125,10 @@ typedef struct ntlmssp_state
struct arcfour_state send_seal_arc4_state;
struct arcfour_state recv_seal_arc4_state;
- uint32 ntlm2_send_seq_num;
- uint32 ntlm2_recv_seq_num;
+ uint32_t ntlm2_send_seq_num;
+ uint32_t ntlm2_recv_seq_num;
/* ntlmv1 */
struct arcfour_state ntlmv1_arc4_state;
- uint32 ntlmv1_seq_num;
-
- /* it turns out that we don't always get the
- response in at the time we want to process it.
- Store it here, until we need it */
- DATA_BLOB stored_response;
-} NTLMSSP_STATE;
+ uint32_t ntlmv1_seq_num;
+};
diff --git a/source3/include/proto.h b/source3/include/proto.h
index ab74c9cb95..b3921c468e 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2165,7 +2165,11 @@ struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct cli_state *cli);
NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req);
-bool cli_ulogoff(struct cli_state *cli);
+struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli);
+NTSTATUS cli_ulogoff_recv(struct tevent_req *req);
+NTSTATUS cli_ulogoff(struct cli_state *cli);
struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct cli_state *cli,
@@ -2180,7 +2184,11 @@ struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
NTSTATUS cli_tcon_andx_recv(struct tevent_req *req);
NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
const char *dev, const char *pass, int passlen);
-bool cli_tdis(struct cli_state *cli);
+struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli);
+NTSTATUS cli_tdis_recv(struct tevent_req *req);
+NTSTATUS cli_tdis(struct cli_state *cli);
void cli_negprot_sendsync(struct cli_state *cli);
NTSTATUS cli_negprot(struct cli_state *cli);
struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
@@ -3057,8 +3065,6 @@ NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
NTSTATUS check_negative_conn_cache_timeout( const char *domain, const char *server, unsigned int failed_cache_timeout );
NTSTATUS check_negative_conn_cache( const char *domain, const char *server);
void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result) ;
-void delete_negative_conn_cache(const char *domain, const char *server);
-void flush_negative_conn_cache( void );
void flush_negative_conn_cache_for_domain(const char *domain);
/* The following definitions come from ../librpc/rpc/dcerpc_error.c */
@@ -3213,43 +3219,41 @@ NTSTATUS nt_status_squash(NTSTATUS nt_status);
/* The following definitions come from libsmb/ntlmssp.c */
void debug_ntlmssp_flags(uint32 neg_flags);
-NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user) ;
-NTSTATUS ntlmssp_set_hashes(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) ;
+NTSTATUS ntlmssp_set_hashes(struct ntlmssp_state *ntlmssp_state,
const unsigned char lm_hash[16],
const unsigned char nt_hash[16]) ;
-NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password) ;
-NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain) ;
-NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation) ;
-NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
- DATA_BLOB response) ;
-void ntlmssp_want_feature_list(NTLMSSP_STATE *ntlmssp_state, char *feature_list);
-void ntlmssp_want_feature(NTLMSSP_STATE *ntlmssp_state, uint32 feature);
-NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) ;
+NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) ;
+NTSTATUS ntlmssp_set_workstation(struct ntlmssp_state *ntlmssp_state, const char *workstation) ;
+void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list);
+void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32 feature);
+NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
const DATA_BLOB in, DATA_BLOB *out) ;
-void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state);
-DATA_BLOB ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state, TALLOC_CTX *mem_ctx);
-NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state);
-NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state);
+void ntlmssp_end(struct ntlmssp_state **ntlmssp_state);
+DATA_BLOB ntlmssp_weaken_keys(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx);
+NTSTATUS ntlmssp_server_start(struct ntlmssp_state **ntlmssp_state);
+NTSTATUS ntlmssp_client_start(struct ntlmssp_state **ntlmssp_state);
/* The following definitions come from libsmb/ntlmssp_sign.c */
-NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
const uchar *data, size_t length,
const uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig) ;
-NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
const uchar *data, size_t length,
const uchar *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig) ;
-NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
uchar *data, size_t length,
uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig);
-NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
uchar *data, size_t length,
uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig);
-NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state);
+NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state);
/* The following definitions come from libsmb/passchange.c */
@@ -3270,8 +3274,8 @@ bool netsamlogon_cache_have(const DOM_SID *user_sid);
NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num);
bool common_encryption_on(struct smb_trans_enc_state *es);
-NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf);
-NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS common_ntlm_decrypt_buffer(struct ntlmssp_state *ntlmssp_state, char *buf);
+NTSTATUS common_ntlm_encrypt_buffer(struct ntlmssp_state *ntlmssp_state,
uint16 enc_ctx_num,
char *buf,
char **ppbuf_out);
@@ -6277,9 +6281,7 @@ void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatu
int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file);
void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
int line, const char *file);
-void reply_force_nt_error(struct smb_request *req, NTSTATUS ntstatus,
- int line, const char *file);
-void reply_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+void reply_force_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
int line, const char *file);
void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
NTSTATUS status, int line, const char *file);
@@ -6737,6 +6739,10 @@ void reply_pipe_close(connection_struct *conn, struct smb_request *req);
void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid);
bool nt4_compatible_acls(void);
+uint32_t map_canon_ace_perms(int snum,
+ enum security_ace_type *pacl_type,
+ mode_t perms,
+ bool directory_ace);
NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd);
SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl);
NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 4affd4a8cf..b23ea647ec 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -27,7 +27,7 @@
#define _SMB_H
/* logged when starting the various Samba daemons */
-#define COPYRIGHT_STARTUP_MESSAGE "Copyright Andrew Tridgell and the Samba Team 1992-2009"
+#define COPYRIGHT_STARTUP_MESSAGE "Copyright Andrew Tridgell and the Samba Team 1992-2010"
#if defined(LARGE_SMB_OFF_T)
diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
index 10ee78b394..bc5d9a7fe1 100644
--- a/source3/include/smb_macros.h
+++ b/source3/include/smb_macros.h
@@ -112,8 +112,7 @@
#define ERROR_BOTH(status,class,code) error_packet(outbuf,class,code,status,__LINE__,__FILE__)
#define reply_nterror(req,status) reply_nt_error(req,status,__LINE__,__FILE__)
-#define reply_force_nterror(req,status) reply_force_nt_error(req,status,__LINE__,__FILE__)
-#define reply_doserror(req,eclass,ecode) reply_dos_error(req,eclass,ecode,__LINE__,__FILE__)
+#define reply_force_doserror(req,eclass,ecode) reply_force_dos_error(req,eclass,ecode,__LINE__,__FILE__)
#define reply_botherror(req,status,eclass,ecode) reply_both_error(req,eclass,ecode,status,__LINE__,__FILE__)
#if 0
diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c
index 639269cac2..1f47bf35f0 100644
--- a/source3/lib/util_sid.c
+++ b/source3/lib/util_sid.c
@@ -557,17 +557,18 @@ char *sid_binstring_hex(const DOM_SID *sid)
Tallocs a duplicate SID.
********************************************************************/
-DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src)
+struct dom_sid *sid_dup_talloc(TALLOC_CTX *ctx, const struct dom_sid *src)
{
- DOM_SID *dst;
-
- if(!src)
+ struct dom_sid *dst;
+
+ if (src == NULL) {
return NULL;
-
- if((dst = TALLOC_ZERO_P(ctx, DOM_SID)) != NULL) {
- sid_copy( dst, src);
}
-
+ dst = talloc_zero(ctx, struct dom_sid);
+ if (dst == NULL) {
+ return NULL;
+ }
+ sid_copy(dst, src);
return dst;
}
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 9b4d8bd2d4..6a0a1ae3d2 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -19,6 +19,7 @@
#include "includes.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
#ifdef HAVE_LDAP
diff --git a/source3/librpc/gen_ndr/cli_wbint.c b/source3/librpc/gen_ndr/cli_wbint.c
index 3115a20d9d..592b27b50d 100644
--- a/source3/librpc/gen_ndr/cli_wbint.c
+++ b/source3/librpc/gen_ndr/cli_wbint.c
@@ -2901,6 +2901,136 @@ NTSTATUS rpccli_wbint_ChangeMachineAccount(struct rpc_pipe_client *cli,
return r.out.result;
}
+struct rpccli_wbint_PingDc_state {
+ struct wbint_PingDc orig;
+ struct wbint_PingDc tmp;
+ TALLOC_CTX *out_mem_ctx;
+ NTSTATUS (*dispatch_recv)(struct tevent_req *req, TALLOC_CTX *mem_ctx);
+};
+
+static void rpccli_wbint_PingDc_done(struct tevent_req *subreq);
+
+struct tevent_req *rpccli_wbint_PingDc_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct rpc_pipe_client *cli)
+{
+ struct tevent_req *req;
+ struct rpccli_wbint_PingDc_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct rpccli_wbint_PingDc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->out_mem_ctx = NULL;
+ state->dispatch_recv = cli->dispatch_recv;
+
+ /* In parameters */
+
+ /* Out parameters */
+
+ /* Result */
+ ZERO_STRUCT(state->orig.out.result);
+
+ /* make a temporary copy, that we pass to the dispatch function */
+ state->tmp = state->orig;
+
+ subreq = cli->dispatch_send(state, ev, cli,
+ &ndr_table_wbint,
+ NDR_WBINT_PINGDC,
+ &state->tmp);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, rpccli_wbint_PingDc_done, req);
+ return req;
+}
+
+static void rpccli_wbint_PingDc_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct rpccli_wbint_PingDc_state *state = tevent_req_data(
+ req, struct rpccli_wbint_PingDc_state);
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ if (state->out_mem_ctx) {
+ mem_ctx = state->out_mem_ctx;
+ } else {
+ mem_ctx = state;
+ }
+
+ status = state->dispatch_recv(subreq, mem_ctx);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ /* Copy out parameters */
+
+ /* Copy result */
+ state->orig.out.result = state->tmp.out.result;
+
+ /* Reset temporary structure */
+ ZERO_STRUCT(state->tmp);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS rpccli_wbint_PingDc_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ NTSTATUS *result)
+{
+ struct rpccli_wbint_PingDc_state *state = tevent_req_data(
+ req, struct rpccli_wbint_PingDc_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ /* Steal possbile out parameters to the callers context */
+ talloc_steal(mem_ctx, state->out_mem_ctx);
+
+ /* Return result */
+ *result = state->orig.out.result;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_wbint_PingDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct wbint_PingDc r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ status = cli->dispatch(cli,
+ mem_ctx,
+ &ndr_table_wbint,
+ NDR_WBINT_PINGDC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
struct rpccli_wbint_SetMapping_state {
struct wbint_SetMapping orig;
struct wbint_SetMapping tmp;
diff --git a/source3/librpc/gen_ndr/cli_wbint.h b/source3/librpc/gen_ndr/cli_wbint.h
index b08ef3fef1..4528d43efc 100644
--- a/source3/librpc/gen_ndr/cli_wbint.h
+++ b/source3/librpc/gen_ndr/cli_wbint.h
@@ -248,6 +248,14 @@ NTSTATUS rpccli_wbint_ChangeMachineAccount_recv(struct tevent_req *req,
NTSTATUS *result);
NTSTATUS rpccli_wbint_ChangeMachineAccount(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx);
+struct tevent_req *rpccli_wbint_PingDc_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct rpc_pipe_client *cli);
+NTSTATUS rpccli_wbint_PingDc_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ NTSTATUS *result);
+NTSTATUS rpccli_wbint_PingDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
struct tevent_req *rpccli_wbint_SetMapping_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct rpc_pipe_client *cli,
diff --git a/source3/librpc/gen_ndr/ndr_wbint.c b/source3/librpc/gen_ndr/ndr_wbint.c
index 97b29761ee..50f781cc20 100644
--- a/source3/librpc/gen_ndr/ndr_wbint.c
+++ b/source3/librpc/gen_ndr/ndr_wbint.c
@@ -2232,6 +2232,47 @@ _PUBLIC_ void ndr_print_wbint_ChangeMachineAccount(struct ndr_print *ndr, const
ndr->depth--;
}
+static enum ndr_err_code ndr_push_wbint_PingDc(struct ndr_push *ndr, int flags, const struct wbint_PingDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wbint_PingDc(struct ndr_pull *ndr, int flags, struct wbint_PingDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wbint_PingDc(struct ndr_print *ndr, const char *name, int flags, const struct wbint_PingDc *r)
+{
+ ndr_print_struct(ndr, name, "wbint_PingDc");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wbint_PingDc");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wbint_PingDc");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
static enum ndr_err_code ndr_push_wbint_SetMapping(struct ndr_push *ndr, int flags, const struct wbint_SetMapping *r)
{
if (flags & NDR_IN) {
@@ -2567,6 +2608,14 @@ static const struct ndr_interface_call wbint_calls[] = {
false,
},
{
+ "wbint_PingDc",
+ sizeof(struct wbint_PingDc),
+ (ndr_push_flags_fn_t) ndr_push_wbint_PingDc,
+ (ndr_pull_flags_fn_t) ndr_pull_wbint_PingDc,
+ (ndr_print_function_t) ndr_print_wbint_PingDc,
+ false,
+ },
+ {
"wbint_SetMapping",
sizeof(struct wbint_SetMapping),
(ndr_push_flags_fn_t) ndr_push_wbint_SetMapping,
@@ -2619,7 +2668,7 @@ const struct ndr_interface_table ndr_table_wbint = {
NDR_WBINT_VERSION
},
.helpstring = NDR_WBINT_HELPSTRING,
- .num_calls = 23,
+ .num_calls = 24,
.calls = wbint_calls,
.endpoints = &wbint_endpoints,
.authservices = &wbint_authservices
diff --git a/source3/librpc/gen_ndr/ndr_wbint.h b/source3/librpc/gen_ndr/ndr_wbint.h
index e163ff3674..4a381ccfb2 100644
--- a/source3/librpc/gen_ndr/ndr_wbint.h
+++ b/source3/librpc/gen_ndr/ndr_wbint.h
@@ -51,13 +51,15 @@ extern const struct ndr_interface_table ndr_table_wbint;
#define NDR_WBINT_CHANGEMACHINEACCOUNT (0x13)
-#define NDR_WBINT_SETMAPPING (0x14)
+#define NDR_WBINT_PINGDC (0x14)
-#define NDR_WBINT_REMOVEMAPPING (0x15)
+#define NDR_WBINT_SETMAPPING (0x15)
-#define NDR_WBINT_SETHWM (0x16)
+#define NDR_WBINT_REMOVEMAPPING (0x16)
-#define NDR_WBINT_CALL_COUNT (23)
+#define NDR_WBINT_SETHWM (0x17)
+
+#define NDR_WBINT_CALL_COUNT (24)
enum ndr_err_code ndr_push_wbint_userinfo(struct ndr_push *ndr, int ndr_flags, const struct wbint_userinfo *r);
enum ndr_err_code ndr_pull_wbint_userinfo(struct ndr_pull *ndr, int ndr_flags, struct wbint_userinfo *r);
void ndr_print_wbint_userinfo(struct ndr_print *ndr, const char *name, const struct wbint_userinfo *r);
@@ -99,6 +101,7 @@ void ndr_print_wbint_DsGetDcName(struct ndr_print *ndr, const char *name, int fl
void ndr_print_wbint_LookupRids(struct ndr_print *ndr, const char *name, int flags, const struct wbint_LookupRids *r);
void ndr_print_wbint_CheckMachineAccount(struct ndr_print *ndr, const char *name, int flags, const struct wbint_CheckMachineAccount *r);
void ndr_print_wbint_ChangeMachineAccount(struct ndr_print *ndr, const char *name, int flags, const struct wbint_ChangeMachineAccount *r);
+void ndr_print_wbint_PingDc(struct ndr_print *ndr, const char *name, int flags, const struct wbint_PingDc *r);
void ndr_print_wbint_SetMapping(struct ndr_print *ndr, const char *name, int flags, const struct wbint_SetMapping *r);
void ndr_print_wbint_RemoveMapping(struct ndr_print *ndr, const char *name, int flags, const struct wbint_RemoveMapping *r);
void ndr_print_wbint_SetHWM(struct ndr_print *ndr, const char *name, int flags, const struct wbint_SetHWM *r);
diff --git a/source3/librpc/gen_ndr/srv_wbint.c b/source3/librpc/gen_ndr/srv_wbint.c
index 0f39cd93e1..efd9be6b7a 100644
--- a/source3/librpc/gen_ndr/srv_wbint.c
+++ b/source3/librpc/gen_ndr/srv_wbint.c
@@ -1610,6 +1610,79 @@ static bool api_wbint_ChangeMachineAccount(pipes_struct *p)
return true;
}
+static bool api_wbint_PingDc(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wbint_PingDc *r;
+
+ call = &ndr_table_wbint.calls[NDR_WBINT_PINGDC];
+
+ r = talloc(talloc_tos(), struct wbint_PingDc);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r, NULL);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wbint_PingDc, r);
+ }
+
+ r->out.result = _wbint_PingDc(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wbint_PingDc, r);
+ }
+
+ push = ndr_push_init_ctx(r, NULL);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
static bool api_wbint_SetMapping(pipes_struct *p)
{
const struct ndr_interface_call *call;
@@ -1853,6 +1926,7 @@ static struct api_struct api_wbint_cmds[] =
{"WBINT_LOOKUPRIDS", NDR_WBINT_LOOKUPRIDS, api_wbint_LookupRids},
{"WBINT_CHECKMACHINEACCOUNT", NDR_WBINT_CHECKMACHINEACCOUNT, api_wbint_CheckMachineAccount},
{"WBINT_CHANGEMACHINEACCOUNT", NDR_WBINT_CHANGEMACHINEACCOUNT, api_wbint_ChangeMachineAccount},
+ {"WBINT_PINGDC", NDR_WBINT_PINGDC, api_wbint_PingDc},
{"WBINT_SETMAPPING", NDR_WBINT_SETMAPPING, api_wbint_SetMapping},
{"WBINT_REMOVEMAPPING", NDR_WBINT_REMOVEMAPPING, api_wbint_RemoveMapping},
{"WBINT_SETHWM", NDR_WBINT_SETHWM, api_wbint_SetHWM},
@@ -2115,6 +2189,12 @@ NTSTATUS rpc_wbint_dispatch(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, co
return NT_STATUS_OK;
}
+ case NDR_WBINT_PINGDC: {
+ struct wbint_PingDc *r = (struct wbint_PingDc *)_r;
+ r->out.result = _wbint_PingDc(cli->pipes_struct, r);
+ return NT_STATUS_OK;
+ }
+
case NDR_WBINT_SETMAPPING: {
struct wbint_SetMapping *r = (struct wbint_SetMapping *)_r;
r->out.result = _wbint_SetMapping(cli->pipes_struct, r);
diff --git a/source3/librpc/gen_ndr/srv_wbint.h b/source3/librpc/gen_ndr/srv_wbint.h
index c8c04fb3cc..716f1ac9d1 100644
--- a/source3/librpc/gen_ndr/srv_wbint.h
+++ b/source3/librpc/gen_ndr/srv_wbint.h
@@ -21,6 +21,7 @@ NTSTATUS _wbint_DsGetDcName(pipes_struct *p, struct wbint_DsGetDcName *r);
NTSTATUS _wbint_LookupRids(pipes_struct *p, struct wbint_LookupRids *r);
NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p, struct wbint_CheckMachineAccount *r);
NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p, struct wbint_ChangeMachineAccount *r);
+NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r);
NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r);
NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r);
NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r);
@@ -46,6 +47,7 @@ NTSTATUS _wbint_DsGetDcName(pipes_struct *p, struct wbint_DsGetDcName *r);
NTSTATUS _wbint_LookupRids(pipes_struct *p, struct wbint_LookupRids *r);
NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p, struct wbint_CheckMachineAccount *r);
NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p, struct wbint_ChangeMachineAccount *r);
+NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r);
NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r);
NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r);
NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r);
diff --git a/source3/librpc/gen_ndr/wbint.h b/source3/librpc/gen_ndr/wbint.h
index 962a87ea26..96b7800624 100644
--- a/source3/librpc/gen_ndr/wbint.h
+++ b/source3/librpc/gen_ndr/wbint.h
@@ -303,6 +303,14 @@ struct wbint_ChangeMachineAccount {
};
+struct wbint_PingDc {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
struct wbint_SetMapping {
struct {
struct dom_sid *sid;/* [ref] */
diff --git a/source3/librpc/idl/wbint.idl b/source3/librpc/idl/wbint.idl
index e44f179723..432d59e086 100644
--- a/source3/librpc/idl/wbint.idl
+++ b/source3/librpc/idl/wbint.idl
@@ -150,6 +150,9 @@ interface wbint
NTSTATUS wbint_ChangeMachineAccount(
);
+ NTSTATUS wbint_PingDc(
+ );
+
typedef [public] enum {
WBINT_ID_TYPE_NOT_SPECIFIED,
WBINT_ID_TYPE_UID,
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
index 6edfe514b8..f5000e4730 100644
--- a/source3/libsmb/async_smb.c
+++ b/source3/libsmb/async_smb.c
@@ -153,180 +153,6 @@ void cli_set_error(struct cli_state *cli, NTSTATUS status)
}
/**
- * @brief Find the smb_cmd offset of the last command pushed
- * @param[in] buf The buffer we're building up
- * @retval Where can we put our next andx cmd?
- *
- * While chaining requests, the "next" request we're looking at needs to put
- * its SMB_Command before the data the previous request already built up added
- * to the chain. Find the offset to the place where we have to put our cmd.
- */
-
-static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs)
-{
- uint8_t cmd;
- size_t ofs;
-
- cmd = CVAL(buf, smb_com);
-
- SMB_ASSERT(is_andx_req(cmd));
-
- ofs = smb_vwv0;
-
- while (CVAL(buf, ofs) != 0xff) {
-
- if (!is_andx_req(CVAL(buf, ofs))) {
- return false;
- }
-
- /*
- * ofs is from start of smb header, so add the 4 length
- * bytes. The next cmd is right after the wct field.
- */
- ofs = SVAL(buf, ofs+2) + 4 + 1;
-
- SMB_ASSERT(ofs+4 < talloc_get_size(buf));
- }
-
- *pofs = ofs;
- return true;
-}
-
-/**
- * @brief Do the smb chaining at a buffer level
- * @param[in] poutbuf Pointer to the talloc'ed buffer to be modified
- * @param[in] smb_command The command that we want to issue
- * @param[in] wct How many words?
- * @param[in] vwv The words, already in network order
- * @param[in] bytes_alignment How shall we align "bytes"?
- * @param[in] num_bytes How many bytes?
- * @param[in] bytes The data the request ships
- *
- * smb_splice_chain() adds the vwv and bytes to the request already present in
- * *poutbuf.
- */
-
-bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command,
- uint8_t wct, const uint16_t *vwv,
- size_t bytes_alignment,
- uint32_t num_bytes, const uint8_t *bytes)
-{
- uint8_t *outbuf;
- size_t old_size, new_size;
- size_t ofs;
- size_t chain_padding = 0;
- size_t bytes_padding = 0;
- bool first_request;
-
- old_size = talloc_get_size(*poutbuf);
-
- /*
- * old_size == smb_wct means we're pushing the first request in for
- * libsmb/
- */
-
- first_request = (old_size == smb_wct);
-
- if (!first_request && ((old_size % 4) != 0)) {
- /*
- * Align the wct field of subsequent requests to a 4-byte
- * boundary
- */
- chain_padding = 4 - (old_size % 4);
- }
-
- /*
- * After the old request comes the new wct field (1 byte), the vwv's
- * and the num_bytes field. After at we might need to align the bytes
- * given to us to "bytes_alignment", increasing the num_bytes value.
- */
-
- new_size = old_size + chain_padding + 1 + wct * sizeof(uint16_t) + 2;
-
- if ((bytes_alignment != 0) && ((new_size % bytes_alignment) != 0)) {
- bytes_padding = bytes_alignment - (new_size % bytes_alignment);
- }
-
- new_size += bytes_padding + num_bytes;
-
- if ((smb_command != SMBwriteX) && (new_size > 0xffff)) {
- DEBUG(1, ("splice_chain: %u bytes won't fit\n",
- (unsigned)new_size));
- return false;
- }
-
- outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size);
- if (outbuf == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return false;
- }
- *poutbuf = outbuf;
-
- if (first_request) {
- SCVAL(outbuf, smb_com, smb_command);
- } else {
- size_t andx_cmd_ofs;
-
- if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) {
- DEBUG(1, ("invalid command chain\n"));
- *poutbuf = TALLOC_REALLOC_ARRAY(
- NULL, *poutbuf, uint8_t, old_size);
- return false;
- }
-
- if (chain_padding != 0) {
- memset(outbuf + old_size, 0, chain_padding);
- old_size += chain_padding;
- }
-
- SCVAL(outbuf, andx_cmd_ofs, smb_command);
- SSVAL(outbuf, andx_cmd_ofs + 2, old_size - 4);
- }
-
- ofs = old_size;
-
- /*
- * Push the chained request:
- *
- * wct field
- */
-
- SCVAL(outbuf, ofs, wct);
- ofs += 1;
-
- /*
- * vwv array
- */
-
- memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct);
- ofs += sizeof(uint16_t) * wct;
-
- /*
- * bcc (byte count)
- */
-
- SSVAL(outbuf, ofs, num_bytes + bytes_padding);
- ofs += sizeof(uint16_t);
-
- /*
- * padding
- */
-
- if (bytes_padding != 0) {
- memset(outbuf + ofs, 0, bytes_padding);
- ofs += bytes_padding;
- }
-
- /*
- * The bytes field
- */
-
- memcpy(outbuf + ofs, bytes, num_bytes);
-
- return true;
-}
-
-/**
* Figure out if there is an andx command behind the current one
* @param[in] buf The smb buffer to look at
* @param[in] ofs The offset to the wct field that is followed by the cmd
@@ -556,6 +382,7 @@ struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
{
struct tevent_req *result;
struct cli_smb_state *state;
+ struct timeval endtime;
if (iov_count > MAX_SMB_IOV) {
/*
@@ -596,6 +423,10 @@ struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
}
state->iov_count = iov_count + 3;
+ endtime = timeval_current_ofs(0, cli->timeout * 1000);
+ if (!tevent_req_set_endtime(result, ev, endtime)) {
+ tevent_req_nomem(NULL, result);
+ }
return result;
}
@@ -679,12 +510,10 @@ static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req,
}
iov[0].iov_base = (void *)buf;
iov[0].iov_len = talloc_get_size(buf);
- subreq = writev_send(state, state->ev, state->cli->outgoing,
- state->cli->fd, false, iov, 1);
- } else {
- subreq = writev_send(state, state->ev, state->cli->outgoing,
- state->cli->fd, false, iov, iov_count);
+ iov_count = 1;
}
+ subreq = writev_send(state, state->ev, state->cli->outgoing,
+ state->cli->fd, false, iov, iov_count);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -986,16 +815,30 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct,
status = cli_pull_error((char *)state->inbuf);
- if (!have_andx_command((char *)state->inbuf, wct_ofs)
- && NT_STATUS_IS_ERR(status)) {
- /*
- * The last command takes the error code. All further commands
- * down the requested chain will get a
- * NT_STATUS_REQUEST_ABORTED.
- */
- return status;
+ if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
+
+ if ((cmd == SMBsesssetupX)
+ && NT_STATUS_EQUAL(
+ status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /*
+ * NT_STATUS_MORE_PROCESSING_REQUIRED is a
+ * valid return code for session setup
+ */
+ goto no_err;
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ /*
+ * The last command takes the error code. All
+ * further commands down the requested chain
+ * will get a NT_STATUS_REQUEST_ABORTED.
+ */
+ return status;
+ }
}
+no_err:
+
wct = CVAL(state->inbuf, wct_ofs);
bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
num_bytes = SVAL(state->inbuf, bytes_offset);
@@ -1027,7 +870,7 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct,
*pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
}
- return NT_STATUS_OK;
+ return status;
}
size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs)
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 112143ca96..31216b8240 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -3,17 +3,17 @@
client connect/disconnect routines
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Andrew Bartlett 2001-2003
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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/>.
*/
@@ -22,6 +22,7 @@
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
#include "smb_krb5.h"
+#include "ntlmssp.h"
static const struct {
int prot;
@@ -104,7 +105,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
cli_set_message(cli->outbuf,10, 0, True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
SSVAL(cli->outbuf,smb_vwv3,2);
@@ -130,7 +131,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
if (cli_is_error(cli)) {
return cli_nt_error(cli);
}
-
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
status = cli_set_username(cli, user);
@@ -359,14 +360,14 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
char *p;
NTSTATUS status;
fstring lanman;
-
+
fstr_sprintf( lanman, "Samba %s", samba_version_string());
memset(cli->outbuf, '\0', smb_size);
cli_set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
SSVAL(cli->outbuf,smb_vwv3,2);
@@ -375,9 +376,9 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
SSVAL(cli->outbuf,smb_vwv8,0);
SIVAL(cli->outbuf,smb_vwv11,capabilities);
p = smb_buf(cli->outbuf);
-
+
/* check wether to send the ASCII or UNICODE version of the password */
-
+
if ( (capabilities & CAP_UNICODE) == 0 ) {
p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
@@ -393,7 +394,7 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
}
-
+
p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
@@ -403,9 +404,9 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
return cli_nt_error(cli);
}
-
+
show_msg(cli->inbuf);
-
+
if (cli_is_error(cli)) {
return cli_nt_error(cli);
}
@@ -524,7 +525,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
cli_set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
SSVAL(cli->outbuf,smb_vwv3,2);
@@ -574,7 +575,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
-
+
p = smb_buf(cli->inbuf);
p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
-1, STR_TERMINATE);
@@ -605,172 +606,212 @@ end:
return result;
}
-/****************************************************************************
- Send a extended security session setup blob
-****************************************************************************/
+/* The following is calculated from :
+ * (smb_size-4) = 35
+ * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
+ * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
+ * end of packet.
+ */
-static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
-{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- char *p;
+#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
- capabilities |= CAP_EXTENDED_SECURITY;
+struct cli_sesssetup_blob_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ DATA_BLOB blob;
+ uint16_t max_blob_size;
+ uint16_t vwv[12];
+ uint8_t *buf;
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
+ NTSTATUS status;
+ char *inbuf;
+ DATA_BLOB ret_blob;
+};
- cli_set_message(cli->outbuf,12,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq);
+static void cli_sesssetup_blob_done(struct tevent_req *subreq);
- cli_setup_packet(cli);
+static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ DATA_BLOB blob)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_sesssetup_blob_state *state;
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,1);
- SIVAL(cli->outbuf,smb_vwv5,0);
- SSVAL(cli->outbuf,smb_vwv7,blob.length);
- SIVAL(cli->outbuf,smb_vwv10,capabilities);
- p = smb_buf(cli->outbuf);
- memcpy(p, blob.data, blob.length);
- p += blob.length;
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
- return cli_send_smb(cli);
-}
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_sesssetup_blob_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->blob = blob;
+ state->cli = cli;
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
+ if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
+ DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
+ "(was %u, need minimum %u)\n",
+ (unsigned int)cli->max_xmit,
+ BASE_SESSSETUP_BLOB_PACKET_SIZE));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ state->max_blob_size =
+ MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
-static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nomem(NULL, req);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return req;
+}
+
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq)
{
- DATA_BLOB blob2 = data_blob_null;
- char *p;
- size_t len;
+ struct tevent_req *subreq;
+ uint16_t thistime;
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+0, 1, 0);
+ SSVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(state->vwv+3, 0, 2);
+ SSVAL(state->vwv+4, 0, 1);
+ SIVAL(state->vwv+5, 0, 0);
+
+ thistime = MIN(state->blob.length, state->max_blob_size);
+ SSVAL(state->vwv+7, 0, thistime);
+
+ SSVAL(state->vwv+8, 0, 0);
+ SSVAL(state->vwv+9, 0, 0);
+ SIVAL(state->vwv+10, 0,
+ cli_session_setup_capabilities(state->cli)
+ | CAP_EXTENDED_SECURITY);
+
+ state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
+ thistime);
+ if (state->buf == NULL) {
+ return false;
+ }
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
- if (!cli_receive_smb(cli))
- return blob2;
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Unix", 5, NULL);
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Samba", 6, NULL);
+ if (state->buf == NULL) {
+ return false;
+ }
+ subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
+ 12, state->vwv,
+ talloc_get_size(state->buf), state->buf);
+ if (subreq == NULL) {
+ return false;
+ }
+ *psubreq = subreq;
+ return true;
+}
- show_msg(cli->inbuf);
+static void cli_sesssetup_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ struct cli_state *cli = state->cli;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint8_t *p;
+ uint16_t blob_length;
- if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- return blob2;
+ status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
}
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ state->status = status;
+ TALLOC_FREE(state->buf);
- p = smb_buf(cli->inbuf);
+ state->inbuf = (char *)cli_smb_inbuf(subreq);
+ cli->vuid = SVAL(state->inbuf, smb_uid);
+
+ blob_length = SVAL(vwv+3, 0);
+ if (blob_length > num_bytes) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ state->ret_blob = data_blob_const(bytes, blob_length);
- blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
+ p = bytes + blob_length;
- p += blob2.length;
- p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
- -1, STR_TERMINATE);
+ p += clistr_pull(state->inbuf, cli->server_os,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(state->inbuf, cli->server_type,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(state->inbuf, cli->server_domain,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
- /* w2k with kerberos doesn't properly null terminate this field */
- len = smb_bufrem(cli->inbuf, p);
- if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) {
- char *end_of_buf = p + len;
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
- SSVAL(p, len, 0);
- /* Now it's null terminated. */
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- -1, STR_TERMINATE);
+ if (state->blob.length != 0) {
+ TALLOC_FREE(subreq);
/*
- * See if there's another string. If so it's the
- * server domain (part of the 'standard' Samba
- * server signature).
+ * More to send
*/
- if (p < end_of_buf) {
- p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
- -1, STR_TERMINATE);
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nomem(NULL, req);
+ return;
}
- } else {
- /*
- * No room to null terminate so we can't see if there
- * is another string (server_domain) afterwards.
- */
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- len, 0);
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return;
}
- return blob2;
+ tevent_req_done(req);
}
-#ifdef HAVE_KRB5
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
-
-/* The following is calculated from :
- * (smb_size-4) = 35
- * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
- * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
- * end of packet.
- */
-
-#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-
-static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
+static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob,
+ char **pinbuf)
{
- int32 remaining = blob.length;
- int32 cur = 0;
- DATA_BLOB send_blob = data_blob_null;
- int32 max_blob_size = 0;
- DATA_BLOB receive_blob = data_blob_null;
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ NTSTATUS status;
+ char *inbuf;
- if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
- DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
- "(was %u, need minimum %u)\n",
- (unsigned int)cli->max_xmit,
- BASE_SESSSETUP_BLOB_PACKET_SIZE));
- cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
- return False;
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
}
- max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
-
- while ( remaining > 0) {
- if (remaining >= max_blob_size) {
- send_blob.length = max_blob_size;
- remaining -= max_blob_size;
- } else {
- send_blob.length = remaining;
- remaining = 0;
- }
-
- send_blob.data = &blob.data[cur];
- cur += send_blob.length;
-
- DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
- (unsigned int)remaining,
- (unsigned int)send_blob.length,
- (unsigned int)cur ));
-
- if (!cli_session_setup_blob_send(cli, send_blob)) {
- DEBUG(0, ("cli_session_setup_blob: send failed\n"));
- return False;
- }
-
- receive_blob = cli_session_setup_blob_receive(cli);
- data_blob_free(&receive_blob);
-
- if (cli_is_error(cli) &&
- !NT_STATUS_EQUAL( cli_get_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DEBUG(0, ("cli_session_setup_blob: receive failed "
- "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
- cli->vuid = 0;
- return False;
- }
+ inbuf = talloc_move(mem_ctx, &state->inbuf);
+ if (pblob != NULL) {
+ *pblob = state->ret_blob;
}
-
- return True;
+ if (pinbuf != NULL) {
+ *pinbuf = inbuf;
+ }
+ /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
+ return state->status;
}
+#ifdef HAVE_KRB5
+
/****************************************************************************
Use in-memory credentials cache
****************************************************************************/
@@ -783,187 +824,358 @@ static void use_in_memory_ccache(void) {
Do a spnego/kerberos encrypted session setup.
****************************************************************************/
-static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
-{
+struct cli_session_setup_kerberos_state {
+ struct cli_state *cli;
DATA_BLOB negTokenTarg;
DATA_BLOB session_key_krb5;
- NTSTATUS nt_status;
- int rc;
+ ADS_STATUS ads_status;
+};
- cli_temp_set_signing(cli);
+static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_kerberos_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *principal, const char *workgroup)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_kerberos_state *state;
+ int rc;
DEBUG(2,("Doing kerberos session setup\n"));
- /* generate the encapsulated kerberos5 ticket */
- rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_kerberos_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->ads_status = ADS_SUCCESS;
+
+ cli_temp_set_signing(cli);
+ /*
+ * Ok, this is cheated: spnego_gen_negTokenTarg can block if
+ * we have to acquire a ticket. To be fixed later :-)
+ */
+ rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
+ &state->session_key_krb5, 0, NULL);
if (rc) {
- DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
- error_message(rc)));
- return ADS_ERROR_KRB5(rc);
+ DEBUG(1, ("cli_session_setup_kerberos: "
+ "spnego_gen_negTokenTarg failed: %s\n",
+ error_message(rc)));
+ state->ads_status = ADS_ERROR_KRB5(rc);
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return tevent_req_post(req, ev);
}
#if 0
- file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+ file_save("negTokenTarg.dat", state->negTokenTarg.data,
+ state->negTokenTarg.length);
#endif
- if (!cli_session_setup_blob(cli, negTokenTarg)) {
- nt_status = cli_nt_error(cli);
- goto nt_error;
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
+ return req;
+}
- if (cli_is_error(cli)) {
- nt_status = cli_nt_error(cli);
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- goto nt_error;
- }
+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);
+ char *inbuf = NULL;
+ NTSTATUS status;
- cli_set_session_key(cli, session_key_krb5);
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (cli_simple_set_signing(
- cli, session_key_krb5, data_blob_null)) {
+ cli_set_session_key(state->cli, state->session_key_krb5);
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- goto nt_error;
- }
+ if (cli_simple_set_signing(state->cli, state->session_key_krb5,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
}
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+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;
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
+ if (tevent_req_is_nterror(req, &status)) {
+ return ADS_ERROR_NT(status);
+ }
+ return state->ads_status;
+}
- return ADS_ERROR_NT(NT_STATUS_OK);
+static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
+ const char *principal,
+ const char *workgroup)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-nt_error:
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
- cli->vuid = 0;
- return ADS_ERROR_NT(nt_status);
+ if (cli_has_async_calls(cli)) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll(req, ev)) {
+ status = ADS_ERROR_SYSTEM(errno);
+ goto fail;
+ }
+ status = cli_session_setup_kerberos_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
#endif /* HAVE_KRB5 */
-
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
- const char *pass, const char *domain)
-{
+struct cli_session_setup_ntlmssp_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
struct ntlmssp_state *ntlmssp_state;
- NTSTATUS nt_status;
- int turn = 1;
- DATA_BLOB msg1;
- DATA_BLOB blob = data_blob_null;
- DATA_BLOB blob_in = data_blob_null;
- DATA_BLOB blob_out = data_blob_null;
+ int turn;
+ DATA_BLOB blob_out;
+};
- cli_temp_set_signing(cli);
+static int cli_session_setup_ntlmssp_state_destructor(
+ struct cli_session_setup_ntlmssp_state *state)
+{
+ if (state->ntlmssp_state != NULL) {
+ ntlmssp_end(&state->ntlmssp_state);
+ }
+ return 0;
+}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
- return nt_status;
+static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+
+static struct tevent_req *cli_session_setup_ntlmssp_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *user, const char *pass, const char *domain)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_ntlmssp_state *state;
+ NTSTATUS status;
+ DATA_BLOB blob_out;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_ntlmssp_state);
+ if (req == NULL) {
+ return NULL;
}
- ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+ state->ev = ev;
+ state->cli = cli;
+ state->turn = 1;
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
- return nt_status;
+ state->ntlmssp_state = NULL;
+ talloc_set_destructor(
+ state, cli_session_setup_ntlmssp_state_destructor);
+
+ cli_temp_set_signing(cli);
+
+ status = ntlmssp_client_start(&state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
- return nt_status;
+ ntlmssp_want_feature(state->ntlmssp_state,
+ NTLMSSP_FEATURE_SESSION_KEY);
+ status = ntlmssp_set_username(state->ntlmssp_state, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
- return nt_status;
+ status = ntlmssp_set_domain(state->ntlmssp_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ 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;
}
- do {
- nt_status = ntlmssp_update(ntlmssp_state,
- 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)) {
- if (turn == 1) {
- /* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
- } else {
- /* wrap it in SPNEGO */
- msg1 = spnego_gen_auth(blob_out);
- }
-
- /* now send that blob on its way */
- if (!cli_session_setup_blob_send(cli, msg1)) {
- DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
- nt_status = NT_STATUS_UNSUCCESSFUL;
- } else {
- blob = cli_session_setup_blob_receive(cli);
-
- nt_status = cli_nt_error(cli);
- if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
- if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- } else {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- }
- }
- data_blob_free(&msg1);
- }
+ state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ data_blob_free(&blob_out);
- if (!blob.length) {
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- } else if ((turn == 1) &&
- NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DATA_BLOB tmp_blob = data_blob_null;
- /* the server might give us back two challenges */
- if (!spnego_parse_challenge(blob, &blob_in,
- &tmp_blob)) {
- DEBUG(3,("Failed to parse challenges\n"));
- nt_status = NT_STATUS_INVALID_PARAMETER;
- }
- data_blob_free(&tmp_blob);
- } else {
- if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
- &blob_in)) {
- DEBUG(3,("Failed to parse auth response\n"));
- if (NT_STATUS_IS_OK(nt_status)
- || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
- nt_status = NT_STATUS_INVALID_PARAMETER;
- }
- }
- data_blob_free(&blob);
- data_blob_free(&blob_out);
- turn++;
- } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
+ if (tevent_req_nomem(subreq, 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);
+}
- data_blob_free(&blob_in);
+static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ DATA_BLOB blob_in, msg_in, blob_out;
+ char *inbuf = NULL;
+ bool parse_ret;
+ NTSTATUS status;
- if (NT_STATUS_IS_OK(nt_status)) {
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
+ &inbuf);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
- if (cli->server_domain[0] == '\0') {
- fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
+ if (NT_STATUS_IS_OK(status)) {
+ if (state->cli->server_domain[0] == '\0') {
+ fstrcpy(state->cli->server_domain,
+ state->ntlmssp_state->server_domain);
}
- cli_set_session_key(cli, ntlmssp_state->session_key);
+ cli_set_session_key(
+ state->cli, state->ntlmssp_state->session_key);
if (cli_simple_set_signing(
- cli, ntlmssp_state->session_key, data_blob_null)) {
+ state->cli, state->ntlmssp_state->session_key,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ TALLOC_FREE(subreq);
+ ntlmssp_end(&state->ntlmssp_state);
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- }
+ if (blob_in.length == 0) {
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ if ((state->turn == 1)
+ && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB tmp_blob = data_blob_null;
+ /* the server might give us back two challenges */
+ parse_ret = spnego_parse_challenge(blob_in, &msg_in,
+ &tmp_blob);
+ data_blob_free(&tmp_blob);
+ } else {
+ parse_ret = spnego_parse_auth_response(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;
}
}
- /* we have a reference conter on ntlmssp_state, if we are signing
- then the state will be kept by the signing engine */
+ status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
- ntlmssp_end(&ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ ntlmssp_end(&state->ntlmssp_state);
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (!NT_STATUS_IS_OK(nt_status)) {
- cli->vuid = 0;
+ state->blob_out = spnego_gen_auth(blob_out);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nomem(state->blob_out.data, req)) {
+ return;
+ }
+
+ subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
+ state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+}
+
+static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
+ const char *user,
+ const char *pass,
+ const char *domain)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
+ if (req == NULL) {
+ goto fail;
}
- return nt_status;
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_ntlmssp_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
@@ -1251,25 +1463,88 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
Send a uloggoff.
*****************************************************************************/
-bool cli_ulogoff(struct cli_state *cli)
+struct cli_ulogoff_state {
+ struct cli_state *cli;
+ uint16_t vwv[2];
+};
+
+static void cli_ulogoff_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,2,0,True);
- SCVAL(cli->outbuf,smb_com,SMBulogoffX);
- cli_setup_packet(cli);
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ struct tevent_req *req, *subreq;
+ struct cli_ulogoff_state *state;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
- if (cli_is_error(cli)) {
- return False;
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, 0);
+
+ subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_ulogoff_done, req);
+ return req;
+}
+
+static void cli_ulogoff_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_ulogoff_state *state = tevent_req_data(
+ req, struct cli_ulogoff_state);
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ state->cli->vuid = -1;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_ulogoff(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- cli->vuid = -1;
- return True;
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_ulogoff_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_ulogoff_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
@@ -1536,24 +1811,83 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
Send a tree disconnect.
****************************************************************************/
-bool cli_tdis(struct cli_state *cli)
+struct cli_tdis_state {
+ struct cli_state *cli;
+};
+
+static void cli_tdis_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,0,0,True);
- SCVAL(cli->outbuf,smb_com,SMBtdis);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ struct tevent_req *req, *subreq;
+ struct cli_tdis_state *state;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
- if (cli_is_error(cli)) {
- return False;
+ subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_tdis_done, req);
+ return req;
+}
- cli->cnum = -1;
- return True;
+static void cli_tdis_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_tdis_state *state = tevent_req_data(
+ req, struct cli_tdis_state);
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ state->cli->cnum = -1;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_tdis(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_tdis_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_tdis_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
@@ -1671,6 +2005,7 @@ static void cli_negprot_done(struct tevent_req *subreq)
status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
return;
}
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index afae4ff2ab..99f52f4ca7 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -993,6 +993,7 @@ bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
bool res;
uint16 cnum;
char *newextrapath = NULL;
+ NTSTATUS status;
if (!cli || !sharename) {
return false;
@@ -1020,7 +1021,7 @@ bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
}
if (force_encrypt) {
- NTSTATUS status = cli_cm_force_encryption(cli,
+ status = cli_cm_force_encryption(cli,
username,
password,
lp_workgroup(),
@@ -1032,7 +1033,8 @@ bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
- if (!cli_tdis(cli)) {
+ status = cli_tdis(cli);
+ if (!NT_STATUS_IS_OK(status)) {
return false;
}
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index ec690b4d82..38382e4af7 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -20,6 +20,7 @@
#include "includes.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
/****************************************************************************
Get UNIX extensions version info.
diff --git a/source3/libsmb/conncache.c b/source3/libsmb/conncache.c
index b440d61048..85a09cc9ce 100644
--- a/source3/libsmb/conncache.c
+++ b/source3/libsmb/conncache.c
@@ -7,17 +7,18 @@
Copyright (C) Andrew Bartlett 2002
Copyright (C) Gerald (Jerry) Carter 2003
Copyright (C) Marc VanHeyningen 2008
-
+ Copyright (C) Volker Lendecke 2009
+
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/>.
*/
@@ -37,11 +38,6 @@
/**
- * prefix used for all entries put into the general cache
- */
-static const char NEGATIVE_CONN_CACHE_PREFIX[] = "NEG_CONN_CACHE";
-
-/**
* Marshalls the domain and server name into the key for the gencache
* record
*
@@ -53,15 +49,16 @@ static const char NEGATIVE_CONN_CACHE_PREFIX[] = "NEG_CONN_CACHE";
*/
static char *negative_conn_cache_keystr(const char *domain, const char *server)
{
- const char NEGATIVE_CONN_CACHE_KEY_FMT[] = "%s/%s,%s";
char *keystr = NULL;
- SMB_ASSERT(domain != NULL);
+ if (domain == NULL) {
+ return NULL;
+ }
if (server == NULL)
server = "";
- keystr = talloc_asprintf(talloc_tos(),NEGATIVE_CONN_CACHE_KEY_FMT,
- NEGATIVE_CONN_CACHE_PREFIX, domain, server);
+ keystr = talloc_asprintf(talloc_tos(), "NEG_CONN_CACHE/%s,%s",
+ domain, server);
if (keystr == NULL) {
DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
}
@@ -100,13 +97,16 @@ static char *negative_conn_cache_valuestr(NTSTATUS status)
*/
static NTSTATUS negative_conn_cache_valuedecode(const char *value)
{
- NTSTATUS result = NT_STATUS_OK;
+ unsigned int v = NT_STATUS_V(NT_STATUS_INTERNAL_ERROR);;
- SMB_ASSERT(value != NULL);
- if (sscanf(value, "%x", &(NT_STATUS_V(result))) != 1)
- DEBUG(0, ("negative_conn_cache_valuestr: unable to parse "
+ if (value != NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (sscanf(value, "%x", &v) != 1) {
+ DEBUG(0, ("negative_conn_cache_valuedecode: unable to parse "
"value field '%s'\n", value));
- return result;
+ }
+ return NT_STATUS(v);
}
/**
@@ -143,7 +143,7 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
if (key == NULL)
goto done;
- if (gencache_get(key, &value, (time_t *) NULL))
+ if (gencache_get(key, &value, NULL))
result = negative_conn_cache_valuedecode(value);
done:
DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
@@ -154,29 +154,6 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
}
/**
- * Delete any negative cache entry for the given domain/server
- *
- * @param[in] domain
- * @param[in] server may be either a FQDN or an IP address
- */
-void delete_negative_conn_cache(const char *domain, const char *server)
-{
- char *key = NULL;
-
- key = negative_conn_cache_keystr(domain, server);
- if (key == NULL)
- goto done;
-
- gencache_del(key);
- DEBUG(9,("delete_negative_conn_cache removing domain %s server %s\n",
- domain, server));
- done:
- TALLOC_FREE(key);
- return;
-}
-
-
-/**
* Add an entry to the failed connection cache
*
* @param[in] domain
@@ -189,7 +166,10 @@ void add_failed_connection_entry(const char *domain, const char *server,
char *key = NULL;
char *value = NULL;
- SMB_ASSERT(!NT_STATUS_IS_OK(result));
+ if (NT_STATUS_IS_OK(result)) {
+ /* Nothing failed here */
+ return;
+ }
key = negative_conn_cache_keystr(domain, server);
if (key == NULL) {
@@ -204,15 +184,14 @@ void add_failed_connection_entry(const char *domain, const char *server,
}
if (gencache_set(key, value,
- time((time_t *) NULL)
- + FAILED_CONNECTION_CACHE_TIMEOUT))
+ time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT))
DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
"to failed conn cache\n", domain, server ));
else
DEBUG(1,("add_failed_connection_entry: failed to add "
"domain %s (%s) to failed conn cache\n",
domain, server));
-
+
done:
TALLOC_FREE(key);
TALLOC_FREE(value);
@@ -220,15 +199,6 @@ void add_failed_connection_entry(const char *domain, const char *server,
}
/**
- * Deletes all records from the negative connection cache in all domains
- */
-void flush_negative_conn_cache( void )
-{
- flush_negative_conn_cache_for_domain("*");
-}
-
-
-/**
* Deletes all records for a specified domain from the negative connection
* cache
*
@@ -246,10 +216,10 @@ void flush_negative_conn_cache_for_domain(const char *domain)
goto done;
}
- gencache_iterate(delete_matches, (void *) NULL, key_pattern);
+ gencache_iterate(delete_matches, NULL, key_pattern);
DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
domain));
-
+
done:
TALLOC_FREE(key_pattern);
return;
diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c
index 0285f22be4..48b3eb32d9 100644
--- a/source3/libsmb/errormap.c
+++ b/source3/libsmb/errormap.c
@@ -146,7 +146,7 @@ static const struct {
{ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT},
{ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP},
{ERRDOS, 87, NT_STATUS_SECTION_PROTECTION},
- {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED},
{ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
{ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY},
{ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE},
@@ -708,7 +708,7 @@ static const struct {
{ERRDOS, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
{ERRDOS, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
{ERRDOS, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
- {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED},
{ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
{ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
{ERRDOS, 299, NT_STATUS(0x8000000d)},
@@ -841,7 +841,7 @@ static const struct {
{ERRHRD, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
{ERRHRD, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
{ERRHRD, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
- {ERRHRD, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRHRD, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED},
{ERRHRD, 288, NT_STATUS_MUTANT_NOT_OWNED},
{ERRHRD, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
{ERRHRD, 299, NT_STATUS(0x8000000d)},
diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c
index 53cd3d5a77..f9770d363c 100644
--- a/source3/libsmb/libsmb_cache.c
+++ b/source3/libsmb/libsmb_cache.c
@@ -151,12 +151,14 @@ SMBC_get_cached_server(SMBCCTX * context,
* attribute server connection) is cool.
*/
if (smbc_getOptionOneSharePerServer(context)) {
+ NTSTATUS status;
/*
* The currently connected share name
* doesn't match the requested share, so
* disconnect from the current share.
*/
- if (! cli_tdis(srv->server->cli)) {
+ status = cli_tdis(srv->server->cli);
+ if (!NT_STATUS_IS_OK(status)) {
/* Sigh. Couldn't disconnect. */
cli_shutdown(srv->server->cli);
srv->server->cli = NULL;
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 60c1d49bb0..7fffe7cea3 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -22,9 +22,10 @@
*/
#include "includes.h"
+#include "ntlmssp.h"
#include "../libcli/auth/libcli_auth.h"
#include "../librpc/gen_ndr/ndr_ntlmssp.h"
-#include "libsmb/ntlmssp_ndr.h"
+#include "../libcli/auth/ntlmssp_ndr.h"
static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
DATA_BLOB reply, DATA_BLOB *next_request);
@@ -41,8 +42,8 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
*/
static const struct ntlmssp_callbacks {
- enum NTLMSSP_ROLE role;
- enum NTLM_MESSAGE_TYPE ntlmssp_command;
+ enum ntlmssp_role role;
+ enum ntlmssp_message_type ntlmssp_command;
NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state,
DATA_BLOB in, DATA_BLOB *out);
} ntlmssp_callbacks[] = {
@@ -111,10 +112,11 @@ void debug_ntlmssp_flags(uint32 neg_flags)
*
*/
-static void get_challenge(const struct ntlmssp_state *ntlmssp_state,
- uint8_t chal[8])
+static NTSTATUS get_challenge(const struct ntlmssp_state *ntlmssp_state,
+ uint8_t chal[8])
{
generate_random_buffer(chal, 8);
+ return NT_STATUS_OK;
}
/**
@@ -145,7 +147,7 @@ static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *ch
*
*/
-NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user)
+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) {
@@ -158,7 +160,7 @@ NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user)
* Store NT and LM hashes on an NTLMSSP context - ensures they are talloc()ed
*
*/
-NTSTATUS ntlmssp_set_hashes(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_set_hashes(struct ntlmssp_state *ntlmssp_state,
const unsigned char lm_hash[16],
const unsigned char nt_hash[16])
{
@@ -178,7 +180,7 @@ NTSTATUS ntlmssp_set_hashes(NTLMSSP_STATE *ntlmssp_state,
* Converts a password to the hashes on an NTLMSSP context.
*
*/
-NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password)
+NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password)
{
if (!password) {
ntlmssp_state->lm_hash = NULL;
@@ -198,7 +200,7 @@ NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password
* Set a domain on an NTLMSSP context - ensures it is talloc()ed
*
*/
-NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain)
+NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain)
{
ntlmssp_state->domain = talloc_strdup(ntlmssp_state,
domain ? domain : "" );
@@ -212,7 +214,7 @@ NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain)
* Set a workstation on an NTLMSSP context - ensures it is talloc()ed
*
*/
-NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation)
+NTSTATUS ntlmssp_set_workstation(struct ntlmssp_state *ntlmssp_state, const char *workstation)
{
ntlmssp_state->workstation = talloc_strdup(ntlmssp_state, workstation);
if (!ntlmssp_state->workstation) {
@@ -222,26 +224,12 @@ NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *works
}
/**
- * Store a DATA_BLOB containing an NTLMSSP response, for use later.
- * This copies the data blob
- */
-
-NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
- DATA_BLOB response)
-{
- ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state,
- response.data,
- response.length);
- return NT_STATUS_OK;
-}
-
-/**
* Request features for the NTLMSSP negotiation
*
* @param ntlmssp_state NTLMSSP state
* @param feature_list List of space seperated features requested from NTLMSSP.
*/
-void ntlmssp_want_feature_list(NTLMSSP_STATE *ntlmssp_state, char *feature_list)
+void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list)
{
/*
* We need to set this to allow a later SetPassword
@@ -265,7 +253,7 @@ void ntlmssp_want_feature_list(NTLMSSP_STATE *ntlmssp_state, char *feature_list)
* @param ntlmssp_state NTLMSSP state
* @param feature Bit flag specifying the requested feature
*/
-void ntlmssp_want_feature(NTLMSSP_STATE *ntlmssp_state, uint32 feature)
+void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32 feature)
{
/* As per JRA's comment above */
if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
@@ -288,10 +276,9 @@ void ntlmssp_want_feature(NTLMSSP_STATE *ntlmssp_state, uint32 feature)
* @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
*/
-NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
- const DATA_BLOB in, DATA_BLOB *out)
+NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB input, DATA_BLOB *out)
{
- DATA_BLOB input;
uint32 ntlmssp_command;
int i;
@@ -303,15 +290,6 @@ NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
*out = data_blob_null;
- if (!in.length && ntlmssp_state->stored_response.length) {
- input = ntlmssp_state->stored_response;
-
- /* we only want to read the stored response once - overwrite it */
- ntlmssp_state->stored_response = data_blob_null;
- } else {
- input = in;
- }
-
if (!input.length) {
switch (ntlmssp_state->role) {
case NTLMSSP_CLIENT:
@@ -356,16 +334,12 @@ NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
* @param ntlmssp_state NTLMSSP State, free()ed by this function
*/
-void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state)
+void ntlmssp_end(struct ntlmssp_state **ntlmssp_state)
{
- (*ntlmssp_state)->ref_count--;
-
- if ((*ntlmssp_state)->ref_count == 0) {
- data_blob_free(&(*ntlmssp_state)->chal);
- data_blob_free(&(*ntlmssp_state)->lm_resp);
- data_blob_free(&(*ntlmssp_state)->nt_resp);
- TALLOC_FREE(*ntlmssp_state);
- }
+ data_blob_free(&(*ntlmssp_state)->chal);
+ data_blob_free(&(*ntlmssp_state)->lm_resp);
+ data_blob_free(&(*ntlmssp_state)->nt_resp);
+ TALLOC_FREE(*ntlmssp_state);
*ntlmssp_state = NULL;
return;
@@ -466,7 +440,7 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
by the client lanman auth/lanman auth parameters, it isn't too bad.
*/
-DATA_BLOB ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state, TALLOC_CTX *mem_ctx)
+DATA_BLOB ntlmssp_weaken_keys(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx)
{
DATA_BLOB weakened_key = data_blob_talloc(mem_ctx,
ntlmssp_state->session_key.data,
@@ -520,6 +494,7 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
const char *target_name;
struct NEGOTIATE_MESSAGE negotiate;
struct CHALLENGE_MESSAGE challenge;
+ NTSTATUS status;
/* parse the NTLMSSP packet */
#if 0
@@ -552,7 +527,10 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());
/* Ask our caller what challenge they would like in the packet */
- ntlmssp_state->get_challenge(ntlmssp_state, cryptkey);
+ status = ntlmssp_state->get_challenge(ntlmssp_state, cryptkey);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
/* Check if we may set the challenge */
if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
@@ -902,9 +880,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
* @param ntlmssp_state NTLMSSP State, allocated by this function
*/
-NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+NTSTATUS ntlmssp_server_start(struct ntlmssp_state **ntlmssp_state)
{
- *ntlmssp_state = TALLOC_ZERO_P(NULL, NTLMSSP_STATE);
+ *ntlmssp_state = TALLOC_ZERO_P(NULL, struct ntlmssp_state);
if (!*ntlmssp_state) {
DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
talloc_destroy(*ntlmssp_state);
@@ -923,8 +901,6 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
(*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
- (*ntlmssp_state)->ref_count = 1;
-
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_56 |
@@ -1239,9 +1215,9 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
return nt_status;
}
-NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
+NTSTATUS ntlmssp_client_start(struct ntlmssp_state **ntlmssp_state)
{
- *ntlmssp_state = TALLOC_ZERO_P(NULL, NTLMSSP_STATE);
+ *ntlmssp_state = TALLOC_ZERO_P(NULL, struct ntlmssp_state);
if (!*ntlmssp_state) {
DEBUG(0,("ntlmssp_client_start: talloc failed!\n"));
talloc_destroy(*ntlmssp_state);
@@ -1259,8 +1235,6 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
(*ntlmssp_state)->expected_state = NTLMSSP_INITIAL;
- (*ntlmssp_state)->ref_count = 1;
-
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
index 752749cdd8..3fd22ce73f 100644
--- a/source3/libsmb/ntlmssp_sign.c
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include "ntlmssp.h"
#include "../libcli/auth/libcli_auth.h"
#define CLI_SIGN "session key to client-to-server signing key magic constant"
@@ -58,7 +59,7 @@ enum ntlmssp_direction {
NTLMSSP_RECEIVE
};
-static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
+static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_state,
const uchar *data, size_t length,
const uchar *whole_pdu, size_t pdu_length,
enum ntlmssp_direction direction,
@@ -76,27 +77,27 @@ static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
}
switch (direction) {
- case NTLMSSP_SEND:
- DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
- ntlmssp_state->ntlm2_send_seq_num,
- (unsigned int)length,
- (unsigned int)pdu_length));
-
- SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
- ntlmssp_state->ntlm2_send_seq_num++;
- hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
- break;
- case NTLMSSP_RECEIVE:
+ case NTLMSSP_SEND:
+ DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_send_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
+
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
+ ntlmssp_state->ntlm2_send_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
+ break;
+ case NTLMSSP_RECEIVE:
- DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
- ntlmssp_state->ntlm2_recv_seq_num,
- (unsigned int)length,
- (unsigned int)pdu_length));
+ DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_recv_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
- SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
- ntlmssp_state->ntlm2_recv_seq_num++;
- hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
- break;
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
+ ntlmssp_state->ntlm2_recv_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
+ break;
}
dump_data_pw("pdu data ", whole_pdu, pdu_length);
@@ -137,7 +138,7 @@ static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
return NT_STATUS_OK;
}
-NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
const uchar *data, size_t length,
const uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
@@ -168,7 +169,7 @@ NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
*
*/
-NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
const uchar *data, size_t length,
const uchar *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig)
@@ -236,7 +237,7 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
*
*/
-NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
uchar *data, size_t length,
uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
@@ -302,7 +303,7 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
*
*/
-NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
uchar *data, size_t length,
uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
@@ -329,11 +330,9 @@ NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
/**
Initialise the state for NTLMSSP signing.
*/
-NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
+NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
{
- unsigned char p24[24];
TALLOC_CTX *mem_ctx;
- ZERO_STRUCT(p24);
mem_ctx = talloc_init("weak_keys");
if (!mem_ctx) {
diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c
index 2f7305c5b6..ec879db5b4 100644
--- a/source3/libsmb/smb_seal.c
+++ b/source3/libsmb/smb_seal.c
@@ -18,6 +18,7 @@
*/
#include "includes.h"
+#include "ntlmssp.h"
/******************************************************************************
Pull out the encryption context for this packet. 0 means global context.
@@ -59,7 +60,7 @@ bool common_encryption_on(struct smb_trans_enc_state *es)
output, so cope with the same for compatibility.
******************************************************************************/
-NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
+NTSTATUS common_ntlm_decrypt_buffer(struct ntlmssp_state *ntlmssp_state, char *buf)
{
NTSTATUS status;
size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
@@ -107,7 +108,7 @@ NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
output, so do the same for compatibility.
******************************************************************************/
-NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
+NTSTATUS common_ntlm_encrypt_buffer(struct ntlmssp_state *ntlmssp_state,
uint16 enc_ctx_num,
char *buf,
char **ppbuf_out)
diff --git a/source3/locale/net/de.po b/source3/locale/net/de.po
index a336936343..0e18172a58 100644
--- a/source3/locale/net/de.po
+++ b/source3/locale/net/de.po
@@ -1,5 +1,6 @@
# net message translation (german).
# Copyright (C) 2009 Kai Blin <kai@samba.org>
+# Copyright (C) 2009 André Hentschel <nerv@dawncrow.de>
# This file is distributed under the same license as the samba package.
#
#, fuzzy
@@ -8,11 +9,12 @@ msgstr ""
"Project-Id-Version: @PACKAGE@\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-11 09:01+0200\n"
-"PO-Revision-Date: 2009-08-06 20:45+0200\n"
-"Last-Translator: Kai Blin <kai@samba.org>\n"
+"PO-Revision-Date: 2009-12-26 19:20+0100\n"
+"Last-Translator: André Hentschel <nerv@dawncrow.de>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language-Team: \n"
#: ../../utils/net.c:103
msgid "Enter machine password: "
@@ -33,12 +35,14 @@ msgid ""
"This function will change the ADS Domain member machine account password in the secrets.tdb file!\n"
msgstr ""
-#: ../../utils/net.c:150 ../../utils/net.c:228
+#: ../../utils/net.c:150
+#: ../../utils/net.c:228
#, c-format
msgid "Unable to open secrets.tdb. Can't fetch domain SID for name: %s\n"
msgstr ""
-#: ../../utils/net.c:163 ../../utils/net.c:251
+#: ../../utils/net.c:163
+#: ../../utils/net.c:251
#, c-format
msgid "SID for domain %s is: %s\n"
msgstr ""
@@ -88,7 +92,7 @@ msgstr ""
#: ../../utils/net.c:317
msgid "Run functions using RPC transport"
-msgstr ""
+msgstr "RPC Protokoll nutzen"
#: ../../utils/net.c:318
msgid " Use 'net help rpc' to get more extensive information about 'net rpc' commands."
@@ -96,7 +100,7 @@ msgstr ""
#: ../../utils/net.c:325
msgid "Run functions using RAP transport"
-msgstr ""
+msgstr "RAP Protokoll nutzen"
#: ../../utils/net.c:326
msgid " Use 'net help rap' to get more extensive information about 'net rap' commands."
@@ -104,7 +108,7 @@ msgstr ""
#: ../../utils/net.c:333
msgid "Run functions using ADS transport"
-msgstr ""
+msgstr "ADS Protokoll nutzen"
#: ../../utils/net.c:334
msgid " Use 'net help ads' to get more extensive information about 'net ads' commands."
@@ -112,7 +116,7 @@ msgstr ""
#: ../../utils/net.c:343
msgid "Functions on remote opened files"
-msgstr ""
+msgstr "Freigegebene Dateien verwalten"
#: ../../utils/net.c:344
msgid " Use 'net help file' to get more information about 'net file' commands."
@@ -120,7 +124,7 @@ msgstr ""
#: ../../utils/net.c:351
msgid "Functions on shares"
-msgstr ""
+msgstr "Freigaben verwalten"
#: ../../utils/net.c:352
msgid " Use 'net help share' to get more information about 'net share' commands."
@@ -128,15 +132,16 @@ msgstr ""
#: ../../utils/net.c:359
msgid "Manage sessions"
-msgstr ""
+msgstr "Sitzungen verwalten"
#: ../../utils/net.c:360
msgid " Use 'net help session' to get more information about 'net session' commands."
msgstr ""
-#: ../../utils/net.c:367 ../../utils/net_rap.c:1291
+#: ../../utils/net.c:367
+#: ../../utils/net_rap.c:1291
msgid "List servers in workgroup"
-msgstr ""
+msgstr "Server der Arbeitsgruppe auflisten"
#: ../../utils/net.c:368
msgid " Use 'net help server' to get more information about 'net server' commands."
@@ -144,7 +149,7 @@ msgstr ""
#: ../../utils/net.c:375
msgid "List domains/workgroups on network"
-msgstr ""
+msgstr "Domänen/Arbeitsgruppen im Netzwerk auflisten"
#: ../../utils/net.c:376
msgid " Use 'net help domain' to get more information about 'net domain' commands."
@@ -160,7 +165,7 @@ msgstr ""
#: ../../utils/net.c:391
msgid "Manage users"
-msgstr ""
+msgstr "Benutzer verwalten"
#: ../../utils/net.c:392
msgid " Use 'net help user' to get more information about 'net user' commands."
@@ -168,7 +173,7 @@ msgstr ""
#: ../../utils/net.c:399
msgid "Manage groups"
-msgstr ""
+msgstr "Gruppen verwalten"
#: ../../utils/net.c:400
msgid " Use 'net help group' to get more information about 'net group' commands."
@@ -176,7 +181,7 @@ msgstr ""
#: ../../utils/net.c:407
msgid "Manage group mappings"
-msgstr ""
+msgstr "Gruppenzuweisungen verwalten"
#: ../../utils/net.c:408
msgid " Use 'net help groupmap' to get more information about 'net groupmap' commands."
@@ -200,7 +205,7 @@ msgstr ""
#: ../../utils/net.c:431
msgid "Modify group memberships"
-msgstr ""
+msgstr "Gruppenzugehörigkeiten verwalten"
#: ../../utils/net.c:432
msgid " Use 'net help groupmember' to get more information about 'net groupmember' commands."
@@ -208,7 +213,7 @@ msgstr ""
#: ../../utils/net.c:438
msgid "Execute remote command on a remote OS/2 server"
-msgstr ""
+msgstr "Befehl auf einem entfernten OS/2 Server ausführen"
#: ../../utils/net.c:439
msgid " Use 'net help admin' to get more information about 'net admin' commands."
@@ -216,7 +221,7 @@ msgstr ""
#: ../../utils/net.c:445
msgid "List/modify running services"
-msgstr ""
+msgstr "Zeige/Ändere laufende Dienste"
#: ../../utils/net.c:446
msgid " Use 'net help service' to get more information about 'net service' commands."
@@ -240,7 +245,7 @@ msgstr ""
#: ../../utils/net.c:467
msgid "Change the secret password"
-msgstr ""
+msgstr "Das geheime Passwort ändern"
#: ../../utils/net.c:468
msgid ""
@@ -252,7 +257,7 @@ msgstr ""
#: ../../utils/net.c:477
msgid "Show/set time"
-msgstr ""
+msgstr "Zeigt/Setzt die Systemzeit"
#: ../../utils/net.c:478
msgid " Use 'net help time' to get more information about 'net time' commands."
@@ -268,7 +273,7 @@ msgstr ""
#: ../../utils/net.c:491
msgid "Join a domain/AD"
-msgstr ""
+msgstr "Einer Domäne/AD beitreten"
#: ../../utils/net.c:492
msgid " Use 'net help join' to get more information about 'net join'."
@@ -340,7 +345,7 @@ msgstr ""
#: ../../utils/net.c:549
msgid "Display server status"
-msgstr ""
+msgstr "Zeigt den Server Status"
#: ../../utils/net.c:550
msgid " Use 'net help status' to get more information about 'net status' commands."
@@ -348,7 +353,7 @@ msgstr ""
#: ../../utils/net.c:556
msgid "Manage user-modifiable shares"
-msgstr ""
+msgstr "Benutzerfreigaben verwalten"
#: ../../utils/net.c:557
msgid " Use 'net help usershare to get more information about 'net usershare' commands."
@@ -356,7 +361,7 @@ msgstr ""
#: ../../utils/net.c:563
msgid "Display list of all users with SID"
-msgstr ""
+msgstr "Zeigt eine Liste aller SID-Benutzer"
#: ../../utils/net.c:564
msgid " Use 'net help usersidlist' to get more information about 'net usersidlist'."
@@ -364,7 +369,7 @@ msgstr ""
#: ../../utils/net.c:570
msgid "Manage Samba registry based configuration"
-msgstr ""
+msgstr "Konfiguration ändern"
#: ../../utils/net.c:571
msgid " Use 'net help conf' to get more information about 'net conf' commands."
@@ -380,7 +385,7 @@ msgstr ""
#: ../../utils/net.c:591
msgid "Process Win32 *.evt eventlog files"
-msgstr ""
+msgstr "Arbeitet mit Win32 *.evt Eventlog Dateien"
#: ../../utils/net.c:592
msgid " Use 'net help eventlog' to get more information about 'net eventlog' commands."
@@ -396,7 +401,7 @@ msgstr ""
#: ../../utils/net.c:609
msgid "Print usage information"
-msgstr ""
+msgstr "Zeigt die Hilfe an"
#: ../../utils/net.c:610
msgid " Use 'net help help' to list usage information for 'net' commands."
@@ -421,7 +426,8 @@ msgstr ""
"\n"
"Ungültige Option %s: %s\n"
-#: ../../utils/net_ads.c:52 ../../utils/net_ads.c:392
+#: ../../utils/net_ads.c:52
+#: ../../utils/net_ads.c:392
msgid "CLDAP query failed!\n"
msgstr ""
@@ -459,15 +465,41 @@ msgid ""
"\tIs NT6 DC that has all secrets: %s\n"
msgstr ""
-#: ../../utils/net_ads.c:87 ../../utils/net_ads.c:88 ../../utils/net_ads.c:89 ../../utils/net_ads.c:90 ../../utils/net_ads.c:91 ../../utils/net_ads.c:92 ../../utils/net_ads.c:93 ../../utils/net_ads.c:94 ../../utils/net_ads.c:95 ../../utils/net_ads.c:96
-#: ../../utils/net_ads.c:97 ../../utils/net_ads.c:98 ../../utils/net_rap.c:376 ../../utils/net_rpc_sh_acct.c:203 ../../utils/net_rpc_sh_acct.c:206
+#: ../../utils/net_ads.c:87
+#: ../../utils/net_ads.c:88
+#: ../../utils/net_ads.c:89
+#: ../../utils/net_ads.c:90
+#: ../../utils/net_ads.c:91
+#: ../../utils/net_ads.c:92
+#: ../../utils/net_ads.c:93
+#: ../../utils/net_ads.c:94
+#: ../../utils/net_ads.c:95
+#: ../../utils/net_ads.c:96
+#: ../../utils/net_ads.c:97
+#: ../../utils/net_ads.c:98
+#: ../../utils/net_rap.c:376
+#: ../../utils/net_rpc_sh_acct.c:203
+#: ../../utils/net_rpc_sh_acct.c:206
msgid "yes"
-msgstr ""
-
-#: ../../utils/net_ads.c:87 ../../utils/net_ads.c:88 ../../utils/net_ads.c:89 ../../utils/net_ads.c:90 ../../utils/net_ads.c:91 ../../utils/net_ads.c:92 ../../utils/net_ads.c:93 ../../utils/net_ads.c:94 ../../utils/net_ads.c:95 ../../utils/net_ads.c:96
-#: ../../utils/net_ads.c:97 ../../utils/net_ads.c:98 ../../utils/net_rap.c:376 ../../utils/net_rpc_sh_acct.c:203 ../../utils/net_rpc_sh_acct.c:206
+msgstr "Ja"
+
+#: ../../utils/net_ads.c:87
+#: ../../utils/net_ads.c:88
+#: ../../utils/net_ads.c:89
+#: ../../utils/net_ads.c:90
+#: ../../utils/net_ads.c:91
+#: ../../utils/net_ads.c:92
+#: ../../utils/net_ads.c:93
+#: ../../utils/net_ads.c:94
+#: ../../utils/net_ads.c:95
+#: ../../utils/net_ads.c:96
+#: ../../utils/net_ads.c:97
+#: ../../utils/net_ads.c:98
+#: ../../utils/net_rap.c:376
+#: ../../utils/net_rpc_sh_acct.c:203
+#: ../../utils/net_rpc_sh_acct.c:206
msgid "no"
-msgstr ""
+msgstr "Nein"
#: ../../utils/net_ads.c:101
#, c-format
@@ -477,7 +509,7 @@ msgstr ""
#: ../../utils/net_ads.c:102
#, c-format
msgid "Domain:\t\t\t%s\n"
-msgstr ""
+msgstr "Domäne:\t\t\t%s\n"
#: ../../utils/net_ads.c:103
#, c-format
@@ -512,7 +544,7 @@ msgstr ""
#: ../../utils/net_ads.c:113
#, c-format
msgid "NT Version: %d\n"
-msgstr ""
+msgstr "NT Version: %d\n"
#: ../../utils/net_ads.c:114
#, c-format
@@ -531,7 +563,8 @@ msgid ""
" Find the ADS DC using CLDAP lookup.\n"
msgstr ""
-#: ../../utils/net_ads.c:137 ../../utils/net_ads.c:381
+#: ../../utils/net_ads.c:137
+#: ../../utils/net_ads.c:381
msgid "Didn't find the cldap server!\n"
msgstr ""
@@ -542,7 +575,8 @@ msgid ""
" Display information about an Active Directory server.\n"
msgstr ""
-#: ../../utils/net_ads.c:168 ../../utils/net_ads.c:173
+#: ../../utils/net_ads.c:168
+#: ../../utils/net_ads.c:173
msgid "Didn't find the ldap server!\n"
msgstr ""
@@ -617,7 +651,8 @@ msgstr ""
msgid "Could not add user %s: %s\n"
msgstr ""
-#: ../../utils/net_ads.c:484 ../../utils/net_ads.c:497
+#: ../../utils/net_ads.c:484
+#: ../../utils/net_ads.c:497
#, c-format
msgid "User %s added\n"
msgstr ""
@@ -699,7 +734,9 @@ msgid ""
" List AD users\n"
msgstr ""
-#: ../../utils/net_ads.c:711 ../../utils/net_rap.c:901 ../../utils/net_rpc.c:852
+#: ../../utils/net_ads.c:711
+#: ../../utils/net_rap.c:901
+#: ../../utils/net_rpc.c:852
msgid ""
"\n"
"User name Comment\n"
@@ -743,23 +780,27 @@ msgstr ""
#: ../../utils/net_ads.c:828
msgid "Add an AD group"
-msgstr ""
+msgstr "AD Gruppe hinzufügen"
#: ../../utils/net_ads.c:829
msgid ""
"net ads group add\n"
" Add an AD group"
msgstr ""
+"net ads group add\n"
+" AD Gruppe hinzufügen"
#: ../../utils/net_ads.c:836
msgid "Delete an AD group"
-msgstr ""
+msgstr "AD Gruppe entfernen"
#: ../../utils/net_ads.c:837
msgid ""
"net ads group delete\n"
" Delete an AD group"
msgstr ""
+"net ads group delete\n"
+" AD Gruppe entfernen"
#: ../../utils/net_ads.c:850
msgid ""
@@ -768,12 +809,16 @@ msgid ""
" List AD groups\n"
msgstr ""
-#: ../../utils/net_ads.c:862 ../../utils/net_rpc.c:2230
+#: ../../utils/net_ads.c:862
+#: ../../utils/net_rpc.c:2230
msgid ""
"\n"
"Group name Comment\n"
"-----------------------------\n"
msgstr ""
+"\n"
+"Gruppenname Kommentar\n"
+"-----------------------------\n"
#: ../../utils/net_ads.c:884
msgid ""
@@ -803,7 +848,8 @@ msgstr ""
msgid "No realm set, are we joined ?\n"
msgstr ""
-#: ../../utils/net_ads.c:938 ../../utils/net_ads.c:1260
+#: ../../utils/net_ads.c:938
+#: ../../utils/net_ads.c:1260
msgid "Could not initialise talloc context.\n"
msgstr ""
@@ -847,15 +893,16 @@ msgid "Join to domain is not valid: %s\n"
msgstr ""
#: ../../utils/net_ads.c:1049
-#, c-format
+#, fuzzy, c-format
msgid "Join is OK\n"
-msgstr ""
+msgstr "Beitritt ist OK\n"
#: ../../utils/net_ads.c:1060
msgid "Host is not configured as a member server.\n"
msgstr ""
-#: ../../utils/net_ads.c:1065 ../../utils/net_rpc.c:436
+#: ../../utils/net_ads.c:1065
+#: ../../utils/net_rpc.c:436
#, c-format
msgid "Our netbios name can be at most 15 chars long, \"%s\" is %u chars long\n"
msgstr ""
@@ -947,12 +994,14 @@ msgstr ""
msgid "Joined '%s' to domain '%s'\n"
msgstr ""
-#: ../../utils/net_ads.c:1377 ../../utils/net_ads.c:1433
+#: ../../utils/net_ads.c:1377
+#: ../../utils/net_ads.c:1433
msgid "DNS update failed!\n"
msgstr ""
#. issue an overall failure message at the end.
-#: ../../utils/net_ads.c:1391 ../../utils/net_dom.c:198
+#: ../../utils/net_ads.c:1391
+#: ../../utils/net_dom.c:198
#, c-format
msgid "Failed to join domain: %s\n"
msgstr ""
@@ -1059,7 +1108,8 @@ msgstr ""
msgid "Server '%s' not found: %s\n"
msgstr ""
-#: ../../utils/net_ads.c:1611 ../../utils/net_ads.c:1794
+#: ../../utils/net_ads.c:1611
+#: ../../utils/net_ads.c:1794
#, c-format
msgid "Printer '%s' not found\n"
msgstr ""
@@ -1083,7 +1133,8 @@ msgstr ""
msgid "Could not find machine account for server %s\n"
msgstr ""
-#: ../../utils/net_ads.c:1704 ../../utils/net_ads.c:1713
+#: ../../utils/net_ads.c:1704
+#: ../../utils/net_ads.c:1713
msgid "Internal error, out of memory!"
msgstr ""
@@ -1171,12 +1222,14 @@ msgstr ""
msgid "Didn't find the kerberos server!\n"
msgstr ""
-#: ../../utils/net_ads.c:1923 ../../utils/net_rpc.c:756
+#: ../../utils/net_ads.c:1923
+#: ../../utils/net_rpc.c:756
#, c-format
msgid "Enter new password for %s:"
msgstr "Bitte neues Passwort für %s eingeben: "
-#: ../../utils/net_ads.c:1933 ../../utils/net_ads.c:1982
+#: ../../utils/net_ads.c:1933
+#: ../../utils/net_ads.c:1982
#, c-format
msgid "Password change failed: %s\n"
msgstr ""
@@ -1224,12 +1277,17 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_ads.c:2046 ../../utils/net_ads.c:2107 ../../utils/net_ads.c:2171 ../../utils/net_ads_gpo.c:250
+#: ../../utils/net_ads.c:2046
+#: ../../utils/net_ads.c:2107
+#: ../../utils/net_ads.c:2171
+#: ../../utils/net_ads_gpo.c:250
#, c-format
msgid "search failed: %s\n"
-msgstr ""
+msgstr "Suche fehlgeschlagen: %s\n"
-#: ../../utils/net_ads.c:2051 ../../utils/net_ads.c:2176 ../../utils/net_ads_gpo.c:256
+#: ../../utils/net_ads.c:2051
+#: ../../utils/net_ads.c:2176
+#: ../../utils/net_ads_gpo.c:256
#, c-format
msgid ""
"Got %d replies\n"
@@ -1469,7 +1527,8 @@ msgid ""
" Display machine account details"
msgstr ""
-#: ../../utils/net_ads.c:2509 ../../utils/net_rpc.c:7110
+#: ../../utils/net_ads.c:2509
+#: ../../utils/net_rpc.c:7110
msgid "List/modify users"
msgstr ""
@@ -1479,7 +1538,8 @@ msgid ""
" List/modify users"
msgstr ""
-#: ../../utils/net_ads.c:2517 ../../utils/net_rpc.c:7127
+#: ../../utils/net_ads.c:2517
+#: ../../utils/net_rpc.c:7127
msgid "List/modify groups"
msgstr ""
@@ -1509,7 +1569,8 @@ msgid ""
" Change user passwords"
msgstr ""
-#: ../../utils/net_ads.c:2541 ../../utils/net_rpc.c:7159
+#: ../../utils/net_ads.c:2541
+#: ../../utils/net_rpc.c:7159
msgid "Change trust account password"
msgstr "Trust account Passwort ändern"
@@ -1640,11 +1701,13 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_ads_gpo.c:71 ../../utils/net_ads_gpo.c:328
+#: ../../utils/net_ads_gpo.c:71
+#: ../../utils/net_ads_gpo.c:328
msgid "machine"
msgstr ""
-#: ../../utils/net_ads_gpo.c:71 ../../utils/net_ads_gpo.c:328
+#: ../../utils/net_ads_gpo.c:71
+#: ../../utils/net_ads_gpo.c:328
msgid "user"
msgstr ""
@@ -1652,12 +1715,20 @@ msgstr ""
msgid "* fetching token "
msgstr ""
-#: ../../utils/net_ads_gpo.c:82 ../../utils/net_ads_gpo.c:90 ../../utils/net_ads_gpo.c:102 ../../utils/net_ads_gpo.c:113 ../../utils/net_ads_gpo.c:158
+#: ../../utils/net_ads_gpo.c:82
+#: ../../utils/net_ads_gpo.c:90
+#: ../../utils/net_ads_gpo.c:102
+#: ../../utils/net_ads_gpo.c:113
+#: ../../utils/net_ads_gpo.c:158
#, c-format
msgid "failed: %s\n"
msgstr ""
-#: ../../utils/net_ads_gpo.c:85 ../../utils/net_ads_gpo.c:94 ../../utils/net_ads_gpo.c:105 ../../utils/net_ads_gpo.c:118 ../../utils/net_ads_gpo.c:163
+#: ../../utils/net_ads_gpo.c:85
+#: ../../utils/net_ads_gpo.c:94
+#: ../../utils/net_ads_gpo.c:105
+#: ../../utils/net_ads_gpo.c:118
+#: ../../utils/net_ads_gpo.c:163
msgid "finished\n"
msgstr ""
@@ -1842,7 +1913,7 @@ msgstr ""
#: ../../utils/net_afs.c:48
#, c-format
msgid "Could not open %s\n"
-msgstr ""
+msgstr "Konnte %s nicht öffnen\n"
#: ../../utils/net_afs.c:53
msgid "Could not read keyfile\n"
@@ -1960,7 +2031,8 @@ msgid ""
" List all cache entries.\n"
msgstr ""
-#: ../../utils/net_cache.c:293 ../../utils/net_cache.c:306
+#: ../../utils/net_cache.c:293
+#: ../../utils/net_cache.c:306
msgid ""
"Usage:\n"
"net cache flush\n"
@@ -2109,8 +2181,18 @@ msgstr ""
msgid "Error getting config: %s\n"
msgstr ""
-#: ../../utils/net_conf.c:305 ../../utils/net_conf.c:318 ../../utils/net_conf.c:614 ../../utils/net_conf.c:742 ../../utils/net_conf.c:780 ../../utils/net_conf.c:786 ../../utils/net_conf.c:860 ../../utils/net_conf.c:866 ../../utils/net_conf.c:916
-#: ../../utils/net_conf.c:970 ../../utils/net_conf.c:1010 ../../utils/net_conf.c:1050
+#: ../../utils/net_conf.c:305
+#: ../../utils/net_conf.c:318
+#: ../../utils/net_conf.c:614
+#: ../../utils/net_conf.c:742
+#: ../../utils/net_conf.c:780
+#: ../../utils/net_conf.c:786
+#: ../../utils/net_conf.c:860
+#: ../../utils/net_conf.c:866
+#: ../../utils/net_conf.c:916
+#: ../../utils/net_conf.c:970
+#: ../../utils/net_conf.c:1010
+#: ../../utils/net_conf.c:1050
msgid "error: out of memory!\n"
msgstr ""
@@ -2126,17 +2208,23 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_conf.c:346 ../../utils/net_conf.c:382 ../../utils/net_conf.c:407 ../../utils/net_conf.c:793
+#: ../../utils/net_conf.c:346
+#: ../../utils/net_conf.c:382
+#: ../../utils/net_conf.c:407
+#: ../../utils/net_conf.c:793
#, c-format
msgid "error starting transaction: %s\n"
msgstr ""
-#: ../../utils/net_conf.c:400 ../../utils/net_conf.c:416 ../../utils/net_conf.c:817
+#: ../../utils/net_conf.c:400
+#: ../../utils/net_conf.c:416
+#: ../../utils/net_conf.c:817
#, c-format
msgid "error committing transaction: %s\n"
msgstr ""
-#: ../../utils/net_conf.c:427 ../../utils/net_conf.c:828
+#: ../../utils/net_conf.c:427
+#: ../../utils/net_conf.c:828
#, c-format
msgid "error cancelling transaction: %s\n"
msgstr ""
@@ -2187,7 +2275,10 @@ msgstr ""
msgid "Error creating share %s: %s\n"
msgstr ""
-#: ../../utils/net_conf.c:690 ../../utils/net_conf.c:699 ../../utils/net_conf.c:707 ../../utils/net_conf.c:715
+#: ../../utils/net_conf.c:690
+#: ../../utils/net_conf.c:699
+#: ../../utils/net_conf.c:707
+#: ../../utils/net_conf.c:715
#, c-format
msgid "Error setting parameter %s: %s\n"
msgstr ""
@@ -2207,12 +2298,14 @@ msgstr ""
msgid "Error setting value '%s': %s\n"
msgstr ""
-#: ../../utils/net_conf.c:874 ../../utils/net_conf.c:930
+#: ../../utils/net_conf.c:874
+#: ../../utils/net_conf.c:930
#, c-format
msgid "Error: given service '%s' does not exist.\n"
msgstr ""
-#: ../../utils/net_conf.c:879 ../../utils/net_conf.c:935
+#: ../../utils/net_conf.c:879
+#: ../../utils/net_conf.c:935
#, c-format
msgid "Error: given parameter '%s' is not set.\n"
msgstr ""
@@ -2242,8 +2335,20 @@ msgstr ""
msgid "error deleting includes: %s\n"
msgstr ""
-#: ../../utils/net_conf.c:1136 ../../utils/net_help.c:36 ../../utils/net_rap.c:161 ../../utils/net_rap.c:302 ../../utils/net_rap.c:467 ../../utils/net_rap.c:750 ../../utils/net_rap.c:891 ../../utils/net_rap.c:1002 ../../utils/net_rap.c:1193
-#: ../../utils/net_rpc.c:960 ../../utils/net_rpc.c:2801 ../../utils/net_rpc.c:4897 ../../utils/net_rpc.c:6933 ../../utils/net_rpc.c:7038
+#: ../../utils/net_conf.c:1136
+#: ../../utils/net_help.c:36
+#: ../../utils/net_rap.c:161
+#: ../../utils/net_rap.c:302
+#: ../../utils/net_rap.c:467
+#: ../../utils/net_rap.c:750
+#: ../../utils/net_rap.c:891
+#: ../../utils/net_rap.c:1002
+#: ../../utils/net_rap.c:1193
+#: ../../utils/net_rpc.c:960
+#: ../../utils/net_rpc.c:2801
+#: ../../utils/net_rpc.c:4897
+#: ../../utils/net_rpc.c:6933
+#: ../../utils/net_rpc.c:7038
msgid "Usage:\n"
msgstr ""
@@ -2400,7 +2505,8 @@ msgstr ""
msgid "Failed to unjoin domain: %s\n"
msgstr ""
-#: ../../utils/net_dom.c:97 ../../utils/net_dom.c:204
+#: ../../utils/net_dom.c:97
+#: ../../utils/net_dom.c:204
msgid "Shutting down due to a domain membership change"
msgstr ""
@@ -2452,12 +2558,14 @@ msgstr ""
msgid "usage: net eventlog dump <file.evt>\n"
msgstr ""
-#: ../../utils/net_eventlog.c:52 ../../utils/net_eventlog.c:108
+#: ../../utils/net_eventlog.c:52
+#: ../../utils/net_eventlog.c:108
#, c-format
msgid "failed to load evt file: %s\n"
msgstr ""
-#: ../../utils/net_eventlog.c:59 ../../utils/net_eventlog.c:129
+#: ../../utils/net_eventlog.c:59
+#: ../../utils/net_eventlog.c:129
#, c-format
msgid "evt pull failed: %s\n"
msgstr ""
@@ -2475,7 +2583,8 @@ msgstr ""
msgid "input file is wrapped, cannot proceed\n"
msgstr ""
-#: ../../utils/net_eventlog.c:138 ../../utils/net_eventlog.c:203
+#: ../../utils/net_eventlog.c:138
+#: ../../utils/net_eventlog.c:203
#, c-format
msgid "can't open the eventlog TDB (%s)\n"
msgstr ""
@@ -2604,11 +2713,13 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_group.c:44 ../../utils/net_user.c:41
+#: ../../utils/net_group.c:44
+#: ../../utils/net_user.c:41
msgid "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"
msgstr ""
-#: ../../utils/net_group.c:46 ../../utils/net_user.c:43
+#: ../../utils/net_group.c:46
+#: ../../utils/net_user.c:43
msgid "\t-c or --container=<container>\tLDAP container, defaults to cn=Users (for add in ADS only)\n"
msgstr ""
@@ -2659,22 +2770,37 @@ msgid ""
" sid\tSID of group to list"
msgstr ""
-#: ../../utils/net_groupmap.c:91 ../../utils/net_groupmap.c:271 ../../utils/net_groupmap.c:356 ../../utils/net_groupmap.c:412 ../../utils/net_groupmap.c:495 ../../utils/net_groupmap.c:522
+#: ../../utils/net_groupmap.c:91
+#: ../../utils/net_groupmap.c:271
+#: ../../utils/net_groupmap.c:356
+#: ../../utils/net_groupmap.c:412
+#: ../../utils/net_groupmap.c:495
+#: ../../utils/net_groupmap.c:522
#, c-format
msgid ""
"Usage:\n"
"%s\n"
msgstr ""
-#: ../../utils/net_groupmap.c:106 ../../utils/net_groupmap.c:213 ../../utils/net_groupmap.c:220 ../../utils/net_groupmap.c:365 ../../utils/net_groupmap.c:372 ../../utils/net_groupmap.c:504
+#: ../../utils/net_groupmap.c:106
+#: ../../utils/net_groupmap.c:213
+#: ../../utils/net_groupmap.c:220
+#: ../../utils/net_groupmap.c:365
+#: ../../utils/net_groupmap.c:372
+#: ../../utils/net_groupmap.c:504
msgid "must supply a name\n"
msgstr ""
-#: ../../utils/net_groupmap.c:113 ../../utils/net_groupmap.c:227 ../../utils/net_groupmap.c:511
+#: ../../utils/net_groupmap.c:113
+#: ../../utils/net_groupmap.c:227
+#: ../../utils/net_groupmap.c:511
msgid "must supply a SID\n"
msgstr ""
-#: ../../utils/net_groupmap.c:118 ../../utils/net_groupmap.c:265 ../../utils/net_groupmap.c:406 ../../utils/net_groupmap.c:516
+#: ../../utils/net_groupmap.c:118
+#: ../../utils/net_groupmap.c:265
+#: ../../utils/net_groupmap.c:406
+#: ../../utils/net_groupmap.c:516
#, c-format
msgid "Bad option: %s\n"
msgstr "Ungültige Option: %s\n"
@@ -2699,7 +2825,8 @@ msgstr ""
msgid "RID must be greater than %d\n"
msgstr ""
-#: ../../utils/net_groupmap.c:235 ../../utils/net_groupmap.c:380
+#: ../../utils/net_groupmap.c:235
+#: ../../utils/net_groupmap.c:380
msgid "must supply a comment string\n"
msgstr ""
@@ -2888,7 +3015,8 @@ msgstr ""
msgid "Usage: net groupmap memberof sid\n"
msgstr ""
-#: ../../utils/net_groupmap.c:820 ../../utils/net_idmap.c:345
+#: ../../utils/net_groupmap.c:820
+#: ../../utils/net_idmap.c:345
msgid "talloc_init failed\n"
msgstr ""
@@ -3001,15 +3129,18 @@ msgstr ""
msgid "net %s usage:\n"
msgstr ""
-#: ../../utils/net_help_common.c:25 ../../utils/net_join.c:28
+#: ../../utils/net_help_common.c:25
+#: ../../utils/net_join.c:28
msgid "Valid methods: (auto-detected if not specified)\n"
msgstr ""
-#: ../../utils/net_help_common.c:26 ../../utils/net_join.c:29
+#: ../../utils/net_help_common.c:26
+#: ../../utils/net_join.c:29
msgid "\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n"
msgstr ""
-#: ../../utils/net_help_common.c:27 ../../utils/net_join.c:30
+#: ../../utils/net_help_common.c:27
+#: ../../utils/net_join.c:30
msgid "\trpc\t\t\t\tDCE-RPC\n"
msgstr ""
@@ -3146,7 +3277,8 @@ msgstr "ignoriere ungültige sid [%s]: %s\n"
msgid "Could not set mapping of %s %lu to sid %s: %s\n"
msgstr ""
-#: ../../utils/net_idmap.c:196 ../../utils/net_idmap.c:202
+#: ../../utils/net_idmap.c:196
+#: ../../utils/net_idmap.c:202
msgid "Not Implemented yet\n"
msgstr ""
@@ -3209,7 +3341,8 @@ msgstr ""
msgid "db_open failed: %s\n"
msgstr ""
-#: ../../utils/net_idmap.c:356 ../../utils/net_idmap.c:361
+#: ../../utils/net_idmap.c:356
+#: ../../utils/net_idmap.c:361
#, c-format
msgid "%s is not a valid sid\n"
msgstr ""
@@ -3247,7 +3380,8 @@ msgid ""
" Restore entries from stdin"
msgstr ""
-#: ../../utils/net_idmap.c:418 ../../utils/net_idmap.c:426
+#: ../../utils/net_idmap.c:418
+#: ../../utils/net_idmap.c:426
msgid "Not implemented yet"
msgstr ""
@@ -3332,7 +3466,8 @@ msgstr ""
msgid "usage: net lookup name <name>\n"
msgstr ""
-#: ../../utils/net_lookup.c:331 ../../utils/net_lookup.c:358
+#: ../../utils/net_lookup.c:331
+#: ../../utils/net_lookup.c:358
#, c-format
msgid "Could not lookup name %s\n"
msgstr ""
@@ -3388,7 +3523,8 @@ msgid ""
"------ --------- ----- ----- ---- \n"
msgstr ""
-#: ../../utils/net_rap.c:120 ../../utils/net_rap.c:180
+#: ../../utils/net_rap.c:120
+#: ../../utils/net_rap.c:180
msgid ""
"\n"
"Operation not supported by server!\n"
@@ -3446,7 +3582,8 @@ msgstr ""
msgid "Server path not specified\n"
msgstr ""
-#: ../../utils/net_rap.c:273 ../../utils/net_rap.c:281
+#: ../../utils/net_rap.c:273
+#: ../../utils/net_rap.c:281
msgid "Delete a share from server"
msgstr ""
@@ -3479,7 +3616,8 @@ msgid ""
" List all shares on remote server\n"
msgstr ""
-#: ../../utils/net_rap.c:314 ../../utils/net_rpc.c:3046
+#: ../../utils/net_rap.c:314
+#: ../../utils/net_rpc.c:3046
msgid ""
"\n"
"Enumerating shared resources (exports) on remote server:\n"
@@ -3539,7 +3677,8 @@ msgid ""
" Display information about session"
msgstr ""
-#: ../../utils/net_rap.c:446 ../../utils/net_rap.c:455
+#: ../../utils/net_rap.c:446
+#: ../../utils/net_rap.c:455
msgid "Close specified session"
msgstr ""
@@ -3673,7 +3812,8 @@ msgstr ""
msgid "*Delete Pending*\n"
msgstr ""
-#: ../../utils/net_rap.c:652 ../../utils/net_rap.c:678
+#: ../../utils/net_rap.c:652
+#: ../../utils/net_rap.c:678
msgid "**UNKNOWN STATUS**\n"
msgstr ""
@@ -3730,7 +3870,8 @@ msgid ""
" List the print queue\n"
msgstr ""
-#: ../../utils/net_rap.c:864 ../../utils/net_rpc.c:909
+#: ../../utils/net_rap.c:864
+#: ../../utils/net_rpc.c:909
msgid "Add specified user"
msgstr ""
@@ -3750,7 +3891,8 @@ msgid ""
" List domain groups of specified user"
msgstr ""
-#: ../../utils/net_rap.c:881 ../../utils/net_rpc.c:925
+#: ../../utils/net_rap.c:881
+#: ../../utils/net_rpc.c:925
msgid "Remove specified user"
msgstr ""
@@ -3781,7 +3923,8 @@ msgid ""
" Add specified group"
msgstr ""
-#: ../../utils/net_rap.c:991 ../../utils/net_rpc.c:2742
+#: ../../utils/net_rap.c:991
+#: ../../utils/net_rpc.c:2742
msgid "Delete specified group"
msgstr ""
@@ -3916,7 +4059,8 @@ msgid ""
"\texecutes a remote command on an os/2 target server\n"
msgstr ""
-#: ../../utils/net_rap.c:1267 ../../utils/net_rpc.c:7143
+#: ../../utils/net_rap.c:1267
+#: ../../utils/net_rpc.c:7143
msgid "List open files"
msgstr ""
@@ -4032,7 +4176,8 @@ msgid ""
" Start/stop remote service"
msgstr ""
-#: ../../utils/net_rap.c:1363 ../../utils/net_rpc.c:933
+#: ../../utils/net_rap.c:1363
+#: ../../utils/net_rpc.c:933
msgid "Change user password"
msgstr ""
@@ -4042,7 +4187,9 @@ msgid ""
" Change user password"
msgstr ""
-#: ../../utils/net_registry.c:94 ../../utils/net_registry.c:197 ../../utils/net_registry.c:250
+#: ../../utils/net_registry.c:94
+#: ../../utils/net_registry.c:197
+#: ../../utils/net_registry.c:250
#, c-format
msgid "open_hive failed: %s\n"
msgstr ""
@@ -4060,7 +4207,11 @@ msgstr ""
msgid "Example: net registry enumerate 'HKLM\\Software\\Samba'\n"
msgstr ""
-#: ../../utils/net_registry.c:141 ../../utils/net_registry.c:286 ../../utils/net_registry.c:356 ../../utils/net_registry.c:390 ../../utils/net_registry.c:439
+#: ../../utils/net_registry.c:141
+#: ../../utils/net_registry.c:286
+#: ../../utils/net_registry.c:356
+#: ../../utils/net_registry.c:390
+#: ../../utils/net_registry.c:439
#, c-format
msgid "open_key failed: %s\n"
msgstr ""
@@ -4073,7 +4224,8 @@ msgstr ""
msgid "Example: net registry createkey 'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n"
msgstr ""
-#: ../../utils/net_registry.c:191 ../../utils/net_registry.c:244
+#: ../../utils/net_registry.c:191
+#: ../../utils/net_registry.c:244
msgid "error: zero length key name given\n"
msgstr ""
@@ -4082,16 +4234,19 @@ msgstr ""
msgid "reg_createkey failed: %s\n"
msgstr ""
-#: ../../utils/net_registry.c:211 ../../utils/net_rpc_registry.c:681
+#: ../../utils/net_registry.c:211
+#: ../../utils/net_rpc_registry.c:681
msgid "createkey did nothing -- huh?\n"
msgstr ""
-#: ../../utils/net_registry.c:214 ../../utils/net_rpc_registry.c:684
+#: ../../utils/net_registry.c:214
+#: ../../utils/net_rpc_registry.c:684
#, c-format
msgid "createkey created %s\n"
msgstr ""
-#: ../../utils/net_registry.c:217 ../../utils/net_rpc_registry.c:687
+#: ../../utils/net_registry.c:217
+#: ../../utils/net_rpc_registry.c:687
#, c-format
msgid "createkey opened existing %s\n"
msgstr ""
@@ -4104,12 +4259,15 @@ msgstr ""
msgid "Example: net registry deletekey 'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n"
msgstr ""
-#: ../../utils/net_registry.c:257 ../../utils/net_registry.c:396
+#: ../../utils/net_registry.c:257
+#: ../../utils/net_registry.c:396
#, c-format
msgid "reg_deletekey failed: %s\n"
msgstr ""
-#: ../../utils/net_registry.c:279 ../../utils/net_rpc_registry.c:601 ../../utils/net_rpc_registry.c:628
+#: ../../utils/net_registry.c:279
+#: ../../utils/net_rpc_registry.c:601
+#: ../../utils/net_rpc_registry.c:628
msgid "usage: net rpc registry getvalue <key> <valuename>\n"
msgstr ""
@@ -4118,16 +4276,19 @@ msgstr ""
msgid "reg_queryvalue failed: %s\n"
msgstr ""
-#: ../../utils/net_registry.c:328 ../../utils/net_rpc_registry.c:433
+#: ../../utils/net_registry.c:328
+#: ../../utils/net_rpc_registry.c:433
msgid "usage: net rpc registry setvalue <key> <valuename> <type> [<val>]+\n"
msgstr ""
-#: ../../utils/net_registry.c:334 ../../utils/net_rpc_registry.c:395
+#: ../../utils/net_registry.c:334
+#: ../../utils/net_rpc_registry.c:395
#, c-format
msgid "Too many args for type %s\n"
msgstr ""
-#: ../../utils/net_registry.c:350 ../../utils/net_rpc_registry.c:409
+#: ../../utils/net_registry.c:350
+#: ../../utils/net_rpc_registry.c:409
#, c-format
msgid "type \"%s\" not implemented\n"
msgstr ""
@@ -4137,7 +4298,8 @@ msgstr ""
msgid "reg_setvalue failed: %s\n"
msgstr ""
-#: ../../utils/net_registry.c:383 ../../utils/net_rpc_registry.c:486
+#: ../../utils/net_registry.c:383
+#: ../../utils/net_rpc_registry.c:486
msgid "usage: net rpc registry deletevalue <key> <valuename>\n"
msgstr ""
@@ -4154,7 +4316,8 @@ msgstr ""
msgid "reg_getkeysecurity failed: %s\n"
msgstr ""
-#: ../../utils/net_registry.c:468 ../../utils/net_rpc_registry.c:1234
+#: ../../utils/net_registry.c:468
+#: ../../utils/net_rpc_registry.c:1234
msgid "Enumerate registry keys and values"
msgstr ""
@@ -4164,7 +4327,8 @@ msgid ""
" Enumerate registry keys and values"
msgstr ""
-#: ../../utils/net_registry.c:476 ../../utils/net_rpc_registry.c:1242
+#: ../../utils/net_registry.c:476
+#: ../../utils/net_rpc_registry.c:1242
msgid "Create a new registry key"
msgstr ""
@@ -4174,7 +4338,8 @@ msgid ""
" Create a new registry key"
msgstr ""
-#: ../../utils/net_registry.c:484 ../../utils/net_rpc_registry.c:1250
+#: ../../utils/net_registry.c:484
+#: ../../utils/net_rpc_registry.c:1250
msgid "Delete a registry key"
msgstr ""
@@ -4184,7 +4349,9 @@ msgid ""
" Delete a registry key"
msgstr ""
-#: ../../utils/net_registry.c:492 ../../utils/net_rpc_registry.c:1258 ../../utils/net_rpc_registry.c:1266
+#: ../../utils/net_registry.c:492
+#: ../../utils/net_rpc_registry.c:1258
+#: ../../utils/net_rpc_registry.c:1266
msgid "Print a registry value"
msgstr ""
@@ -4204,7 +4371,8 @@ msgid ""
" Print a registry value (raw format)"
msgstr ""
-#: ../../utils/net_registry.c:508 ../../utils/net_rpc_registry.c:1274
+#: ../../utils/net_registry.c:508
+#: ../../utils/net_rpc_registry.c:1274
msgid "Set a new registry value"
msgstr ""
@@ -4214,7 +4382,8 @@ msgid ""
" Set a new registry value"
msgstr ""
-#: ../../utils/net_registry.c:516 ../../utils/net_rpc_registry.c:1282
+#: ../../utils/net_registry.c:516
+#: ../../utils/net_rpc_registry.c:1282
msgid "Delete a registry value"
msgstr ""
@@ -4224,7 +4393,8 @@ msgid ""
" Delete a registry value"
msgstr ""
-#: ../../utils/net_registry.c:524 ../../utils/net_rpc_registry.c:1314
+#: ../../utils/net_registry.c:524
+#: ../../utils/net_rpc_registry.c:1314
msgid "Get security descriptor"
msgstr ""
@@ -4253,7 +4423,9 @@ msgstr ""
msgid "Type = %s\n"
msgstr ""
-#: ../../utils/net_registry_util.c:45 ../../utils/net_registry_util.c:76 ../../utils/net_registry_util.c:82
+#: ../../utils/net_registry_util.c:45
+#: ../../utils/net_registry_util.c:76
+#: ../../utils/net_registry_util.c:82
msgid "Value = "
msgstr ""
@@ -4280,11 +4452,13 @@ msgstr ""
msgid "Valuename = %s\n"
msgstr ""
-#: ../../utils/net_rpc.c:66 ../../utils/net_util.c:43
+#: ../../utils/net_rpc.c:66
+#: ../../utils/net_util.c:43
msgid "Could not initialise lsa pipe\n"
msgstr ""
-#: ../../utils/net_rpc.c:74 ../../utils/net_util.c:51
+#: ../../utils/net_rpc.c:74
+#: ../../utils/net_util.c:51
#, c-format
msgid "open_policy failed: %s\n"
msgstr ""
@@ -4301,7 +4475,8 @@ msgid ""
" Change the machine trust password\n"
msgstr ""
-#: ../../utils/net_rpc.c:341 ../../utils/net_rpc_join.c:470
+#: ../../utils/net_rpc.c:341
+#: ../../utils/net_rpc_join.c:470
#, c-format
msgid "Joined domain %s.\n"
msgstr ""
@@ -4487,7 +4662,10 @@ msgstr ""
msgid "Could not lookup %s: %s\n"
msgstr ""
-#: ../../utils/net_rpc.c:1028 ../../utils/net_sam.c:52 ../../utils/net_sam.c:157 ../../utils/net_sam.c:249
+#: ../../utils/net_rpc.c:1028
+#: ../../utils/net_sam.c:52
+#: ../../utils/net_sam.c:157
+#: ../../utils/net_sam.c:249
#, c-format
msgid "%s is a %s, not a user\n"
msgstr ""
@@ -4646,7 +4824,13 @@ msgstr ""
msgid "Remove group member %d..."
msgstr ""
-#: ../../utils/net_rpc.c:1546 ../../utils/net_rpc_registry.c:1053 ../../utils/net_rpc_registry.c:1073 ../../utils/net_rpc_registry.c:1098 ../../utils/net_rpc_registry.c:1105 ../../utils/net_rpc_registry.c:1125 ../../utils/net_rpc_registry.c:1131
+#: ../../utils/net_rpc.c:1546
+#: ../../utils/net_rpc_registry.c:1053
+#: ../../utils/net_rpc_registry.c:1073
+#: ../../utils/net_rpc_registry.c:1098
+#: ../../utils/net_rpc_registry.c:1105
+#: ../../utils/net_rpc_registry.c:1125
+#: ../../utils/net_rpc_registry.c:1131
msgid "ok\n"
msgstr ""
@@ -4693,7 +4877,10 @@ msgstr ""
msgid "Added alias '%s'.\n"
msgstr ""
-#: ../../utils/net_rpc.c:1782 ../../utils/net_rpc.c:1832 ../../utils/net_rpc.c:1989 ../../utils/net_rpc.c:2036
+#: ../../utils/net_rpc.c:1782
+#: ../../utils/net_rpc.c:1832
+#: ../../utils/net_rpc.c:1989
+#: ../../utils/net_rpc.c:2036
#, c-format
msgid "Could not lookup up group member %s\n"
msgstr ""
@@ -4707,12 +4894,14 @@ msgid ""
" member\tMember to add to group\n"
msgstr ""
-#: ../../utils/net_rpc.c:1902 ../../utils/net_rpc.c:2104
+#: ../../utils/net_rpc.c:1902
+#: ../../utils/net_rpc.c:2104
#, c-format
msgid "Could not lookup group name %s\n"
msgstr ""
-#: ../../utils/net_rpc.c:1912 ../../utils/net_rpc.c:1923
+#: ../../utils/net_rpc.c:1912
+#: ../../utils/net_rpc.c:1923
#, c-format
msgid "Could not add %s to %s: %s\n"
msgstr ""
@@ -4731,7 +4920,8 @@ msgid ""
" member\tMember to delete from group\n"
msgstr ""
-#: ../../utils/net_rpc.c:2114 ../../utils/net_rpc.c:2125
+#: ../../utils/net_rpc.c:2114
+#: ../../utils/net_rpc.c:2125
#, c-format
msgid "Could not del %s from %s: %s\n"
msgstr ""
@@ -4773,11 +4963,14 @@ msgstr ""
msgid "Couldn't lookup SIDs\n"
msgstr ""
-#: ../../utils/net_rpc.c:2555 ../../utils/net_rpc.c:2556
+#: ../../utils/net_rpc.c:2555
+#: ../../utils/net_rpc.c:2556
msgid "*unknown*"
msgstr ""
-#: ../../utils/net_rpc.c:2630 ../../utils/net_rpc.c:2643 ../../utils/net_rpc.c:2650
+#: ../../utils/net_rpc.c:2630
+#: ../../utils/net_rpc.c:2643
+#: ../../utils/net_rpc.c:2650
#, c-format
msgid "Couldn't find group %s\n"
msgstr ""
@@ -4837,7 +5030,8 @@ msgid ""
" List groups"
msgstr ""
-#: ../../utils/net_rpc.c:2774 ../../utils/net_sam.c:2053
+#: ../../utils/net_rpc.c:2774
+#: ../../utils/net_sam.c:2053
msgid "List group members"
msgstr ""
@@ -4913,13 +5107,23 @@ msgid ""
" Migrate shares to local server\n"
msgstr ""
-#: ../../utils/net_rpc.c:3210 ../../utils/net_rpc.c:3543 ../../utils/net_rpc.c:3668 ../../utils/net_rpc.c:3701 ../../utils/net_rpc.c:6476 ../../utils/net_rpc.c:6530 ../../utils/net_rpc.c:6560 ../../utils/net_rpc.c:6590 ../../utils/net_rpc.c:6620
+#: ../../utils/net_rpc.c:3210
+#: ../../utils/net_rpc.c:3543
+#: ../../utils/net_rpc.c:3668
+#: ../../utils/net_rpc.c:3701
+#: ../../utils/net_rpc.c:6476
+#: ../../utils/net_rpc.c:6530
+#: ../../utils/net_rpc.c:6560
+#: ../../utils/net_rpc.c:6590
+#: ../../utils/net_rpc.c:6620
#: ../../utils/net_rpc.c:6651
#, c-format
msgid "no server to migrate\n"
msgstr ""
-#: ../../utils/net_rpc.c:3270 ../../utils/net_rpc.c:3382 ../../utils/net_rpc.c:3465
+#: ../../utils/net_rpc.c:3270
+#: ../../utils/net_rpc.c:3382
+#: ../../utils/net_rpc.c:3465
#, c-format
msgid "Unsupported mode %d\n"
msgstr ""
@@ -4969,15 +5173,20 @@ msgstr ""
msgid " [%s] files and directories %s ACLs, %s DOS Attributes %s\n"
msgstr ""
-#: ../../utils/net_rpc.c:3472 ../../utils/net_rpc.c:3473
+#: ../../utils/net_rpc.c:3472
+#: ../../utils/net_rpc.c:3473
msgid "including"
msgstr ""
-#: ../../utils/net_rpc.c:3472 ../../utils/net_rpc.c:3473 ../../utils/net_rpc_printer.c:371 ../../utils/net_rpc_printer.c:372
+#: ../../utils/net_rpc.c:3472
+#: ../../utils/net_rpc.c:3473
+#: ../../utils/net_rpc_printer.c:371
+#: ../../utils/net_rpc_printer.c:372
msgid "without"
msgstr ""
-#: ../../utils/net_rpc.c:3474 ../../utils/net_rpc_printer.c:373
+#: ../../utils/net_rpc.c:3474
+#: ../../utils/net_rpc_printer.c:373
msgid "(preserving timestamps)"
msgstr ""
@@ -5022,7 +5231,8 @@ msgid ""
" Migrates shares including all share settings\n"
msgstr ""
-#: ../../utils/net_rpc.c:3738 ../../utils/net_rpc.c:3762
+#: ../../utils/net_rpc.c:3738
+#: ../../utils/net_rpc.c:3762
msgid "Migrate shares from remote to local server"
msgstr ""
@@ -5150,7 +5360,8 @@ msgstr ""
msgid "usage: %s <share> <path> [comment]\n"
msgstr ""
-#: ../../utils/net_rpc.c:4686 ../../utils/net_rpc.c:4704
+#: ../../utils/net_rpc.c:4686
+#: ../../utils/net_rpc.c:4704
#, c-format
msgid "usage: %s <share>\n"
msgstr ""
@@ -5237,7 +5448,8 @@ msgid ""
" List opened files\n"
msgstr ""
-#: ../../utils/net_rpc.c:4941 ../../utils/net_rpc.c:4980
+#: ../../utils/net_rpc.c:4941
+#: ../../utils/net_rpc.c:4980
msgid ""
"\n"
"Shutdown successfully aborted\n"
@@ -5250,11 +5462,13 @@ msgid ""
" Abort a scheduled shutdown\n"
msgstr ""
-#: ../../utils/net_rpc.c:5050 ../../utils/net_rpc.c:5103
+#: ../../utils/net_rpc.c:5050
+#: ../../utils/net_rpc.c:5103
msgid "This machine will be shutdown shortly"
msgstr ""
-#: ../../utils/net_rpc.c:5069 ../../utils/net_rpc.c:5124
+#: ../../utils/net_rpc.c:5069
+#: ../../utils/net_rpc.c:5124
msgid ""
"\n"
"Shutdown of remote machine succeeded\n"
@@ -5357,7 +5571,8 @@ msgstr ""
#. * in case of no trusted domains say something rather
#. * than just display blank line
#.
-#: ../../utils/net_rpc.c:5974 ../../utils/net_rpc.c:6121
+#: ../../utils/net_rpc.c:5974
+#: ../../utils/net_rpc.c:6121
msgid "none\n"
msgstr ""
@@ -5645,7 +5860,8 @@ msgid ""
" List published printers via MSRPC\n"
msgstr ""
-#: ../../utils/net_rpc.c:6900 ../../utils/net_rpc.c:7029
+#: ../../utils/net_rpc.c:6900
+#: ../../utils/net_rpc.c:7029
msgid "Publish printer in AD"
msgstr ""
@@ -5908,7 +6124,8 @@ msgstr ""
msgid ""
"net rpc changetrustpw\n"
" Change trust account password"
-msgstr "net rpc changetrustpw\n"
+msgstr ""
+"net rpc changetrustpw\n"
" trust account Passwort ändern"
#: ../../utils/net_rpc.c:7167
@@ -6043,7 +6260,8 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_rpc_audit.c:47 ../../utils/net_util.c:611
+#: ../../utils/net_rpc_audit.c:47
+#: ../../utils/net_util.c:611
msgid "Unknown"
msgstr ""
@@ -6056,11 +6274,13 @@ msgstr ""
msgid "\t%s%s%s\n"
msgstr ""
-#: ../../utils/net_rpc_audit.c:80 ../../utils/net_rpc_audit.c:147
+#: ../../utils/net_rpc_audit.c:80
+#: ../../utils/net_rpc_audit.c:147
msgid "insufficient arguments\n"
msgstr ""
-#: ../../utils/net_rpc_audit.c:86 ../../utils/net_rpc_audit.c:153
+#: ../../utils/net_rpc_audit.c:86
+#: ../../utils/net_rpc_audit.c:153
#, c-format
msgid "invalid auditing category: %s\n"
msgstr "Ungültige Audit-Kategorie: %s\n"
@@ -6221,7 +6441,8 @@ msgstr ""
msgid "User specified does not have administrator privileges\n"
msgstr ""
-#: ../../utils/net_rpc_join.c:403 ../../utils/net_rpc_join.c:431
+#: ../../utils/net_rpc_join.c:403
+#: ../../utils/net_rpc_join.c:431
#, c-format
msgid ""
"Please make sure that no computer account\n"
@@ -6355,7 +6576,8 @@ msgstr ""
msgid "copying [\\\\%s\\%s%s] => [\\\\%s\\%s%s] %s ACLs and %s DOS Attributes %s\n"
msgstr ""
-#: ../../utils/net_rpc_printer.c:371 ../../utils/net_rpc_printer.c:372
+#: ../../utils/net_rpc_printer.c:371
+#: ../../utils/net_rpc_printer.c:372
msgid "with"
msgstr ""
@@ -6409,7 +6631,8 @@ msgstr ""
msgid "cannot get printer-info: %s\n"
msgstr ""
-#: ../../utils/net_rpc_printer.c:823 ../../utils/net_rpc_printer.c:1318
+#: ../../utils/net_rpc_printer.c:823
+#: ../../utils/net_rpc_printer.c:1318
#, c-format
msgid "cannot set printer-info: %s\n"
msgstr ""
@@ -6535,7 +6758,11 @@ msgstr ""
msgid "unkown state: %d\n"
msgstr ""
-#: ../../utils/net_rpc_printer.c:1520 ../../utils/net_rpc_printer.c:1667 ../../utils/net_rpc_printer.c:1850 ../../utils/net_rpc_printer.c:2039 ../../utils/net_rpc_printer.c:2206
+#: ../../utils/net_rpc_printer.c:1520
+#: ../../utils/net_rpc_printer.c:1667
+#: ../../utils/net_rpc_printer.c:1850
+#: ../../utils/net_rpc_printer.c:2039
+#: ../../utils/net_rpc_printer.c:2206
#, c-format
msgid "no printers found on server.\n"
msgstr ""
@@ -6607,7 +6834,12 @@ msgstr ""
msgid "got no key-data\n"
msgstr ""
-#: ../../utils/net_rpc_registry.c:389 ../../utils/net_rpc_registry.c:461 ../../utils/net_rpc_registry.c:522 ../../utils/net_rpc_registry.c:791 ../../utils/net_rpc_registry.c:862 ../../utils/net_rpc_registry.c:1171
+#: ../../utils/net_rpc_registry.c:389
+#: ../../utils/net_rpc_registry.c:461
+#: ../../utils/net_rpc_registry.c:522
+#: ../../utils/net_rpc_registry.c:791
+#: ../../utils/net_rpc_registry.c:862
+#: ../../utils/net_rpc_registry.c:1171
#, c-format
msgid "registry_openkey failed: %s\n"
msgstr ""
@@ -6622,7 +6854,8 @@ msgstr ""
msgid "registry_deletevalue failed: %s\n"
msgstr ""
-#: ../../utils/net_rpc_registry.c:543 ../../utils/net_rpc_registry.c:560
+#: ../../utils/net_rpc_registry.c:543
+#: ../../utils/net_rpc_registry.c:560
#, c-format
msgid "registry_queryvalue failed: %s\n"
msgstr ""
@@ -6680,17 +6913,21 @@ msgstr ""
msgid "Usage: net rpc registry dump <file> \n"
msgstr ""
-#: ../../utils/net_rpc_registry.c:1048 ../../utils/net_rpc_registry.c:1093 ../../utils/net_rpc_registry.c:1100
+#: ../../utils/net_rpc_registry.c:1048
+#: ../../utils/net_rpc_registry.c:1093
+#: ../../utils/net_rpc_registry.c:1100
#, c-format
msgid "Opening %s...."
msgstr ""
-#: ../../utils/net_rpc_registry.c:1050 ../../utils/net_rpc_registry.c:1095
+#: ../../utils/net_rpc_registry.c:1050
+#: ../../utils/net_rpc_registry.c:1095
#, c-format
msgid "Failed to open %s for reading\n"
msgstr ""
-#: ../../utils/net_rpc_registry.c:1058 ../../utils/net_rpc_registry.c:1110
+#: ../../utils/net_rpc_registry.c:1058
+#: ../../utils/net_rpc_registry.c:1110
msgid "Could not get rootkey\n"
msgstr ""
@@ -6712,7 +6949,8 @@ msgstr ""
msgid "RootKey: [%s]\n"
msgstr ""
-#: ../../utils/net_rpc_registry.c:1121 ../../utils/net_rpc_registry.c:1127
+#: ../../utils/net_rpc_registry.c:1121
+#: ../../utils/net_rpc_registry.c:1127
#, c-format
msgid "Closing %s..."
msgstr ""
@@ -6902,7 +7140,8 @@ msgid ""
" View available/assigned privileges"
msgstr ""
-#: ../../utils/net_rpc_rights.c:650 ../../utils/net_rpc_rights.c:709
+#: ../../utils/net_rpc_rights.c:650
+#: ../../utils/net_rpc_rights.c:709
msgid "Assign privilege[s]"
msgstr ""
@@ -6912,7 +7151,8 @@ msgid ""
" Assign privilege[s]"
msgstr ""
-#: ../../utils/net_rpc_rights.c:658 ../../utils/net_rpc_rights.c:712
+#: ../../utils/net_rpc_rights.c:658
+#: ../../utils/net_rpc_rights.c:712
msgid "Revoke privilege[s]"
msgstr ""
@@ -7014,7 +7254,11 @@ msgstr ""
msgid "Unknown State [%d]"
msgstr ""
-#: ../../utils/net_rpc_service.c:82 ../../utils/net_rpc_service.c:162 ../../utils/net_rpc_service.c:355 ../../utils/net_rpc_service.c:625 ../../utils/net_rpc_service.c:705
+#: ../../utils/net_rpc_service.c:82
+#: ../../utils/net_rpc_service.c:162
+#: ../../utils/net_rpc_service.c:355
+#: ../../utils/net_rpc_service.c:625
+#: ../../utils/net_rpc_service.c:705
#, c-format
msgid "Failed to open service. [%s]\n"
msgstr ""
@@ -7024,7 +7268,8 @@ msgstr ""
msgid "Control service request failed. [%s]\n"
msgstr ""
-#: ../../utils/net_rpc_service.c:185 ../../utils/net_rpc_service.c:373
+#: ../../utils/net_rpc_service.c:185
+#: ../../utils/net_rpc_service.c:373
#, c-format
msgid "%s service is %s.\n"
msgstr ""
@@ -7033,7 +7278,8 @@ msgstr ""
msgid "Usage: net rpc service list\n"
msgstr ""
-#: ../../utils/net_rpc_service.c:230 ../../utils/net_rpc_service.c:340
+#: ../../utils/net_rpc_service.c:230
+#: ../../utils/net_rpc_service.c:340
#, c-format
msgid "Failed to open Service Control Manager. [%s]\n"
msgstr ""
@@ -7047,11 +7293,16 @@ msgstr ""
msgid "No services returned\n"
msgstr ""
-#: ../../utils/net_rpc_service.c:327 ../../utils/net_rpc_service.c:459 ../../utils/net_rpc_service.c:505 ../../utils/net_rpc_service.c:551 ../../utils/net_rpc_service.c:597
+#: ../../utils/net_rpc_service.c:327
+#: ../../utils/net_rpc_service.c:459
+#: ../../utils/net_rpc_service.c:505
+#: ../../utils/net_rpc_service.c:551
+#: ../../utils/net_rpc_service.c:597
msgid "Usage: net rpc service status <service>\n"
msgstr ""
-#: ../../utils/net_rpc_service.c:368 ../../utils/net_rpc_service.c:639
+#: ../../utils/net_rpc_service.c:368
+#: ../../utils/net_rpc_service.c:639
#, c-format
msgid "Query status request failed. [%s]\n"
msgstr ""
@@ -7116,7 +7367,12 @@ msgstr ""
msgid "\tDisplay Name = %s\n"
msgstr ""
-#: ../../utils/net_rpc_service.c:474 ../../utils/net_rpc_service.c:520 ../../utils/net_rpc_service.c:566 ../../utils/net_rpc_service.c:610 ../../utils/net_rpc_service.c:690 ../../utils/net_rpc_service.c:769
+#: ../../utils/net_rpc_service.c:474
+#: ../../utils/net_rpc_service.c:520
+#: ../../utils/net_rpc_service.c:566
+#: ../../utils/net_rpc_service.c:610
+#: ../../utils/net_rpc_service.c:690
+#: ../../utils/net_rpc_service.c:769
#, c-format
msgid "Failed to open Service Control Manager. [%s]\n"
msgstr ""
@@ -7334,12 +7590,18 @@ msgstr ""
msgid "Minimum password age: "
msgstr ""
-#: ../../utils/net_rpc_sh_acct.c:168 ../../utils/net_rpc_sh_acct.c:176 ../../utils/net_rpc_sh_acct.c:188 ../../utils/net_rpc_sh_acct.c:196
+#: ../../utils/net_rpc_sh_acct.c:168
+#: ../../utils/net_rpc_sh_acct.c:176
+#: ../../utils/net_rpc_sh_acct.c:188
+#: ../../utils/net_rpc_sh_acct.c:196
#, c-format
msgid "%d seconds\n"
msgstr ""
-#: ../../utils/net_rpc_sh_acct.c:170 ../../utils/net_rpc_sh_acct.c:178 ../../utils/net_rpc_sh_acct.c:190 ../../utils/net_rpc_sh_acct.c:198
+#: ../../utils/net_rpc_sh_acct.c:170
+#: ../../utils/net_rpc_sh_acct.c:178
+#: ../../utils/net_rpc_sh_acct.c:190
+#: ../../utils/net_rpc_sh_acct.c:198
msgid "not set\n"
msgstr ""
@@ -7370,7 +7632,13 @@ msgstr ""
msgid "User must logon to change password: %s\n"
msgstr "Benutzer muss sich anmelden um Passwort zu ändern: %s\n"
-#: ../../utils/net_rpc_sh_acct.c:228 ../../utils/net_rpc_sh_acct.c:258 ../../utils/net_rpc_sh_acct.c:288 ../../utils/net_rpc_sh_acct.c:318 ../../utils/net_rpc_sh_acct.c:348 ../../utils/net_rpc_sh_acct.c:378 ../../utils/net_rpc_sh_acct.c:408
+#: ../../utils/net_rpc_sh_acct.c:228
+#: ../../utils/net_rpc_sh_acct.c:258
+#: ../../utils/net_rpc_sh_acct.c:288
+#: ../../utils/net_rpc_sh_acct.c:318
+#: ../../utils/net_rpc_sh_acct.c:348
+#: ../../utils/net_rpc_sh_acct.c:378
+#: ../../utils/net_rpc_sh_acct.c:408
#, c-format
msgid "usage: %s <count>\n"
msgstr ""
@@ -7459,7 +7727,10 @@ msgstr ""
msgid "%s: unknown cmd\n"
msgstr ""
-#: ../../utils/net_rpc_shell.c:150 ../../utils/net_rpc_shell.c:231 ../../utils/net_sam.c:1573 ../../utils/net_sam.c:1835
+#: ../../utils/net_rpc_shell.c:150
+#: ../../utils/net_rpc_shell.c:231
+#: ../../utils/net_sam.c:1573
+#: ../../utils/net_sam.c:1835
msgid "talloc failed\n"
msgstr ""
@@ -7514,21 +7785,34 @@ msgstr "Kommandozeile ungültig: %s\n"
msgid "usage: net sam set %s <user> <value>\n"
msgstr ""
-#: ../../utils/net_sam.c:47 ../../utils/net_sam.c:152 ../../utils/net_sam.c:244 ../../utils/net_sam.c:307 ../../utils/net_sam.c:697 ../../utils/net_sam.c:735 ../../utils/net_sam.c:1527
+#: ../../utils/net_sam.c:47
+#: ../../utils/net_sam.c:152
+#: ../../utils/net_sam.c:244
+#: ../../utils/net_sam.c:307
+#: ../../utils/net_sam.c:697
+#: ../../utils/net_sam.c:735
+#: ../../utils/net_sam.c:1527
#, c-format
msgid "Could not find name %s\n"
msgstr ""
-#: ../../utils/net_sam.c:58 ../../utils/net_sam.c:68 ../../utils/net_sam.c:163 ../../utils/net_sam.c:255
+#: ../../utils/net_sam.c:58
+#: ../../utils/net_sam.c:68
+#: ../../utils/net_sam.c:163
+#: ../../utils/net_sam.c:255
msgid "Internal error\n"
msgstr ""
-#: ../../utils/net_sam.c:63 ../../utils/net_sam.c:168 ../../utils/net_sam.c:260
+#: ../../utils/net_sam.c:63
+#: ../../utils/net_sam.c:168
+#: ../../utils/net_sam.c:260
#, c-format
msgid "Loading user %s failed\n"
msgstr ""
-#: ../../utils/net_sam.c:74 ../../utils/net_sam.c:184 ../../utils/net_sam.c:272
+#: ../../utils/net_sam.c:74
+#: ../../utils/net_sam.c:184
+#: ../../utils/net_sam.c:272
#, c-format
msgid "Updating sam account %s failed with %s\n"
msgstr ""
@@ -7712,11 +7996,14 @@ msgid ""
"\n"
msgstr ""
-#: ../../utils/net_sam.c:493 ../../utils/net_sam.c:545 ../../utils/net_sam.c:583
+#: ../../utils/net_sam.c:493
+#: ../../utils/net_sam.c:545
+#: ../../utils/net_sam.c:583
msgid "Valid account policies are:\n"
msgstr ""
-#: ../../utils/net_sam.c:504 ../../utils/net_sam.c:556
+#: ../../utils/net_sam.c:504
+#: ../../utils/net_sam.c:556
#, c-format
msgid "Valid account policy, but unable to fetch value!\n"
msgstr ""
@@ -7803,7 +8090,8 @@ msgstr ""
msgid "usage: net sam rights grant <name> <rights> ...\n"
msgstr ""
-#: ../../utils/net_sam.c:703 ../../utils/net_sam.c:742
+#: ../../utils/net_sam.c:703
+#: ../../utils/net_sam.c:742
#, c-format
msgid "%s unknown\n"
msgstr ""
@@ -7864,7 +8152,10 @@ msgstr ""
msgid "usage: net sam mapunixgroup <name>\n"
msgstr ""
-#: ../../utils/net_sam.c:861 ../../utils/net_sam.c:1161 ../../utils/net_sam.c:1248 ../../utils/net_sam.c:1320
+#: ../../utils/net_sam.c:861
+#: ../../utils/net_sam.c:1161
+#: ../../utils/net_sam.c:1248
+#: ../../utils/net_sam.c:1320
#, c-format
msgid "Could not find group %s\n"
msgstr ""
@@ -7902,7 +8193,9 @@ msgstr ""
msgid "usage: net sam createdomaingroup <name>\n"
msgstr ""
-#: ../../utils/net_sam.c:960 ../../utils/net_sam.c:1038 ../../utils/net_sam.c:1133
+#: ../../utils/net_sam.c:960
+#: ../../utils/net_sam.c:1038
+#: ../../utils/net_sam.c:1133
#, c-format
msgid "Creating %s failed with %s\n"
msgstr ""
@@ -7912,11 +8205,13 @@ msgstr ""
msgid "Created domain group %s with RID %d\n"
msgstr ""
-#: ../../utils/net_sam.c:984 ../../utils/net_sam.c:1060
+#: ../../utils/net_sam.c:984
+#: ../../utils/net_sam.c:1060
msgid "usage: net sam deletelocalgroup <name>\n"
msgstr ""
-#: ../../utils/net_sam.c:990 ../../utils/net_sam.c:1066
+#: ../../utils/net_sam.c:990
+#: ../../utils/net_sam.c:1066
#, c-format
msgid "Could not find %s.\n"
msgstr ""
@@ -7991,7 +8286,8 @@ msgstr ""
msgid "usage: net sam addmem <group> <member>\n"
msgstr ""
-#: ../../utils/net_sam.c:1173 ../../utils/net_sam.c:1255
+#: ../../utils/net_sam.c:1173
+#: ../../utils/net_sam.c:1255
#, c-format
msgid "Could not find member %s\n"
msgstr ""
@@ -8061,7 +8357,8 @@ msgstr ""
msgid "usage: net sam listmem <group>\n"
msgstr ""
-#: ../../utils/net_sam.c:1329 ../../utils/net_sam.c:1339
+#: ../../utils/net_sam.c:1329
+#: ../../utils/net_sam.c:1339
#, c-format
msgid "Listing group members failed with %s\n"
msgstr ""
@@ -8153,7 +8450,14 @@ msgid ""
" Init an LDAP tree with default users/groups\n"
msgstr ""
-#: ../../utils/net_sam.c:1568 ../../utils/net_sam.c:1697 ../../utils/net_sam.c:1729 ../../utils/net_sam.c:1773 ../../utils/net_sam.c:1811 ../../utils/net_sam.c:1849 ../../utils/net_sam.c:1860 ../../utils/net_sam.c:1929
+#: ../../utils/net_sam.c:1568
+#: ../../utils/net_sam.c:1697
+#: ../../utils/net_sam.c:1729
+#: ../../utils/net_sam.c:1773
+#: ../../utils/net_sam.c:1811
+#: ../../utils/net_sam.c:1849
+#: ../../utils/net_sam.c:1860
+#: ../../utils/net_sam.c:1929
msgid "Out of Memory!\n"
msgstr ""
@@ -8189,9 +8493,14 @@ msgstr ""
msgid "Failed to add Domain Users group to ldap directory\n"
msgstr ""
-#: ../../utils/net_sam.c:1663 ../../utils/net_sam.c:1720 ../../utils/net_sam.c:1804 ../../utils/net_sam.c:1893 ../../utils/net_sam.c:1907 ../../utils/net_sam.c:1954
+#: ../../utils/net_sam.c:1663
+#: ../../utils/net_sam.c:1720
+#: ../../utils/net_sam.c:1804
+#: ../../utils/net_sam.c:1893
+#: ../../utils/net_sam.c:1907
+#: ../../utils/net_sam.c:1954
msgid "found!\n"
-msgstr ""
+msgstr "gefunden!\n"
#: ../../utils/net_sam.c:1668
msgid "Checking for Domain Admins group.\n"
@@ -8493,7 +8802,8 @@ msgid ""
"-------------------------------------------------------------------\n"
msgstr ""
-#: ../../utils/net_status.c:92 ../../utils/net_status.c:198
+#: ../../utils/net_status.c:92
+#: ../../utils/net_status.c:198
#, c-format
msgid "%s not initialised\n"
msgstr ""
@@ -8564,6 +8874,18 @@ msgid ""
"\n"
"\n"
msgstr ""
+"net time\n"
+"\tZeigt die Zeit eines Servers an\n"
+"\n"
+"net time system\n"
+"\tZeigt die Zeit eines Servers im /bin/date Format an\n"
+"\n"
+"net time set\n"
+"\tFührt /bin/date mit der Serverzeit aus\n"
+"\n"
+"net time zone\n"
+"\tZeigt die Zeitzone in Stunden zur GMT auf dem entfernten Computer\n"
+"\n"
#: ../../utils/net_time.c:123
#, c-format
@@ -8703,7 +9025,7 @@ msgstr ""
#: ../../utils/net_usershare.c:39
msgid "System error"
-msgstr ""
+msgstr "System Fehler"
#: ../../utils/net_usershare.c:55
#, c-format
@@ -9011,7 +9333,7 @@ msgstr ""
#: ../../utils/net_util.c:124
msgid "The username or password was not correct.\n"
-msgstr ""
+msgstr "Benutzername oder Passwort nicht korrekt.\n"
#: ../../utils/net_util.c:129
msgid "The account was locked out.\n"
@@ -9039,7 +9361,8 @@ msgstr ""
msgid "Encryption required and setup failed with error %s.\n"
msgstr ""
-#: ../../utils/net_util.c:343 ../../utils/net_util.c:365
+#: ../../utils/net_util.c:343
+#: ../../utils/net_util.c:365
msgid "ERROR: Unable to open secrets database\n"
msgstr ""
@@ -9051,7 +9374,7 @@ msgstr ""
#: ../../utils/net_util.c:524
#, c-format
msgid "Connection failed: %s\n"
-msgstr ""
+msgstr "Verbindung fehlgeschlagen: %s\n"
#: ../../utils/net_util.c:558
#, c-format
@@ -9069,7 +9392,7 @@ msgstr ""
#: ../../utils/net_util.c:608
msgid "Print"
-msgstr ""
+msgstr "Drucken"
#: ../../utils/net_util.c:609
msgid "Dev"
@@ -9078,3 +9401,4 @@ msgstr ""
#: ../../utils/net_util.c:610
msgid "IPC"
msgstr ""
+
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 06bcfb856b..1eec448083 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -157,6 +157,85 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
}
/*******************************************************************
+ Add in 3 inheritable components for a non-inheritable directory ACL.
+ CREATOR_OWNER/CREATOR_GROUP/WORLD.
+*******************************************************************/
+
+static void add_directory_inheritable_components(vfs_handle_struct *handle,
+ const char *name,
+ SMB_STRUCT_STAT *psbuf,
+ struct security_descriptor *psd)
+{
+ struct connection_struct *conn = handle->conn;
+ int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
+ struct smb_filename smb_fname;
+ enum security_ace_type acl_type;
+ uint32_t access_mask;
+ mode_t dir_mode;
+ mode_t file_mode;
+ mode_t mode;
+ struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
+ struct security_ace,
+ num_aces + 3);
+
+ if (new_ace_list == NULL) {
+ return;
+ }
+
+ /* Fake a quick smb_filename. */
+ ZERO_STRUCT(smb_fname);
+ smb_fname.st = *psbuf;
+ smb_fname.base_name = CONST_DISCARD(char *, name);
+
+ dir_mode = unix_mode(conn,
+ FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
+ file_mode = unix_mode(conn,
+ FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
+
+ mode = dir_mode | file_mode;
+
+ DEBUG(10, ("add_directory_inheritable_components: directory %s, "
+ "mode = 0%o\n",
+ name,
+ (unsigned int)mode ));
+
+ if (num_aces) {
+ memcpy(new_ace_list, psd->dacl->aces,
+ num_aces * sizeof(struct security_ace));
+ }
+ access_mask = map_canon_ace_perms(SNUM(conn), &acl_type,
+ mode & 0700, false);
+
+ init_sec_ace(&new_ace_list[num_aces],
+ &global_sid_Creator_Owner,
+ acl_type,
+ access_mask,
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY);
+ access_mask = map_canon_ace_perms(SNUM(conn), &acl_type,
+ (mode << 3) & 0700, false);
+ init_sec_ace(&new_ace_list[num_aces+1],
+ &global_sid_Creator_Group,
+ acl_type,
+ access_mask,
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY);
+ access_mask = map_canon_ace_perms(SNUM(conn), &acl_type,
+ (mode << 6) & 0700, false);
+ init_sec_ace(&new_ace_list[num_aces+2],
+ &global_sid_World,
+ acl_type,
+ access_mask,
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY);
+ psd->dacl->aces = new_ace_list;
+ psd->dacl->num_aces += 3;
+}
+
+/*******************************************************************
Pull a DATA_BLOB from an xattr given a pathname.
If the hash doesn't match, or doesn't exist - return the underlying
filesystem sd.
@@ -261,6 +340,33 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
/* We're returning the blob, throw
* away the filesystem SD. */
TALLOC_FREE(pdesc_next);
+ } else {
+ SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT *psbuf = &sbuf;
+ bool is_directory = false;
+ /*
+ * We're returning the underlying ACL from the
+ * filesystem. If it's a directory, and has no
+ * inheritable ACE entries we have to fake them.
+ */
+ if (fsp) {
+ is_directory = fsp->is_directory;
+ psbuf = &fsp->fsp_name->st;
+ } else {
+ if (vfs_stat_smb_fname(handle->conn,
+ name,
+ &sbuf) == 0) {
+ is_directory = S_ISDIR(sbuf.st_ex_mode);
+ }
+ }
+ if (is_directory &&
+ !sd_has_inheritable_components(psd,
+ true)) {
+ add_directory_inheritable_components(handle,
+ name,
+ psbuf,
+ psd);
+ }
}
if (!(security_info & OWNER_SECURITY_INFORMATION)) {
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 23f002ceeb..96531666d5 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -23,6 +23,7 @@
#include "../libcli/auth/schannel.h"
#include "../libcli/auth/spnego.h"
#include "smb_krb5.h"
+#include "ntlmssp.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_CLI
@@ -631,7 +632,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
RPC_HDR_AUTH auth_info;
uint32 save_offset = prs_offset(current_pdu);
uint32 auth_len = prhdr->auth_len;
- NTLMSSP_STATE *ntlmssp_state = cli->auth->a_u.ntlmssp_state;
+ struct ntlmssp_state *ntlmssp_state = cli->auth->a_u.ntlmssp_state;
unsigned char *data = NULL;
size_t data_len;
unsigned char *full_packet_data = NULL;
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 46f67f499b..f92a100d0a 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -31,6 +31,7 @@
#include "../librpc/gen_ndr/ndr_schannel.h"
#include "../libcli/auth/schannel.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
extern struct current_user current_user;
diff --git a/source3/smbd/error.c b/source3/smbd/error.c
index 279b7baff0..252eb77416 100644
--- a/source3/smbd/error.c
+++ b/source3/smbd/error.c
@@ -30,9 +30,29 @@ bool use_nt_status(void)
/****************************************************************************
Create an error packet. Normally called using the ERROR() macro.
- Setting eclass and ecode only and status to NT_STATUS_OK forces DOS errors.
- Setting status only and eclass and ecode to zero forces NT errors.
- If the override errors are set they take precedence over any passed in values.
+
+ Setting eclass and ecode to zero and status to a valid NT error will
+ reply with an NT error if the client supports CAP_STATUS32, otherwise
+ it maps to and returns a DOS error if the client doesn't support CAP_STATUS32.
+ This is the normal mode of calling this function via reply_nterror(req, status).
+
+ Setting eclass and ecode to non-zero and status to NT_STATUS_OK (0) will map
+ from a DOS error to an NT error and reply with an NT error if the client
+ supports CAP_STATUS32, otherwise it replies with the given DOS error.
+ This mode is currently not used in the server.
+
+ Setting both eclass, ecode and status to non-zero values allows a non-default
+ mapping from NT error codes to DOS error codes, and will return one or the
+ other depending on the client supporting CAP_STATUS32 or not. This is the
+ path taken by calling reply_botherror(req, eclass, ecode, status);
+
+ Setting status to NT_STATUS_DOS(eclass, ecode) forces DOS errors even if the
+ client supports CAP_STATUS32. This is the path taken to force a DOS error
+ reply by calling reply_force_doserror(req, eclass, ecode).
+
+ Setting status only and eclass to -1 forces NT errors even if the client
+ doesn't support CAP_STATUS32. This mode is currently never used in the
+ server.
****************************************************************************/
void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
@@ -95,21 +115,20 @@ void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
}
-void reply_force_nt_error(struct smb_request *req, NTSTATUS ntstatus,
- int line, const char *file)
-{
- TALLOC_FREE(req->outbuf);
- reply_outbuf(req, 0, 0);
- error_packet_set((char *)req->outbuf, -1, -1, ntstatus, line, file);
-}
+/****************************************************************************
+ Forces a DOS error on the wire.
+****************************************************************************/
-void reply_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+void reply_force_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
int line, const char *file)
{
TALLOC_FREE(req->outbuf);
reply_outbuf(req, 0, 0);
- error_packet_set((char *)req->outbuf, eclass, ecode, NT_STATUS_OK, line,
- file);
+ error_packet_set((char *)req->outbuf,
+ eclass, ecode,
+ NT_STATUS_DOS(eclass, ecode),
+ line,
+ file);
}
void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
@@ -134,8 +153,9 @@ void reply_openerror(struct smb_request *req, NTSTATUS status)
ERRDOS, ERRfilexists);
} else if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) {
/* EMFILE always seems to be returned as a DOS error.
- * See bug 6837. */
- reply_doserror(req, ERRDOS, ERRnofids);
+ * See bug 6837. NOTE this forces a DOS error on the wire
+ * even though it's calling reply_nterror(). */
+ reply_force_doserror(req, ERRDOS, ERRnofids);
} else {
reply_nterror(req, status);
}
diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c
index c08bc4019a..8369af418a 100644
--- a/source3/smbd/mangle_hash.c
+++ b/source3/smbd/mangle_hash.c
@@ -429,6 +429,13 @@ static void cache_mangled_name( const char mangled_name[13],
if( !s1[i] && !s2[i] ) {
/* Truncate at the '.' */
*s1 = '\0';
+ /*
+ * DANGER WILL ROBINSON - this
+ * is changing a const string via
+ * an aliased pointer ! Remember to
+ * put it back once we've used it.
+ * JRA
+ */
*s2 = '\0';
}
}
@@ -440,6 +447,8 @@ static void cache_mangled_name( const char mangled_name[13],
} else {
DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
}
+ /* Restore the change we made to the const string. */
+ *s2 = '.';
}
/* ************************************************************************** **
diff --git a/source3/smbd/message.c b/source3/smbd/message.c
index e6d5f451cd..82b3dc30a2 100644
--- a/source3/smbd/message.c
+++ b/source3/smbd/message.c
@@ -145,7 +145,7 @@ void reply_sends(struct smb_request *req)
START_PROFILE(SMBsends);
if (!(*lp_msg_command())) {
- reply_doserror(req, ERRSRV, ERRmsgoff);
+ reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
END_PROFILE(SMBsends);
return;
}
@@ -193,7 +193,7 @@ void reply_sendstrt(struct smb_request *req)
START_PROFILE(SMBsendstrt);
if (!(*lp_msg_command())) {
- reply_doserror(req, ERRSRV, ERRmsgoff);
+ reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
END_PROFILE(SMBsendstrt);
return;
}
@@ -240,7 +240,7 @@ void reply_sendtxt(struct smb_request *req)
START_PROFILE(SMBsendtxt);
if (! (*lp_msg_command())) {
- reply_doserror(req, ERRSRV, ERRmsgoff);
+ reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
END_PROFILE(SMBsendtxt);
return;
}
@@ -288,7 +288,7 @@ void reply_sendend(struct smb_request *req)
START_PROFILE(SMBsendend);
if (! (*lp_msg_command())) {
- reply_doserror(req, ERRSRV, ERRmsgoff);
+ reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
END_PROFILE(SMBsendend);
return;
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index be50090192..656375499f 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -512,7 +512,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
do_ntcreate_pipe_open(conn, req);
goto out;
}
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
@@ -752,7 +752,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
if(parameter_count < 54) {
DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)parameter_count));
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -782,7 +782,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
}
params = nttrans_realloc(ppparams, param_len);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -957,7 +957,7 @@ static void call_nt_transact_create(connection_struct *conn,
ppdata, data_count);
goto out;
}
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
@@ -1159,7 +1159,7 @@ static void call_nt_transact_create(connection_struct *conn,
}
params = nttrans_realloc(ppparams, param_len);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
goto out;
}
@@ -1595,7 +1595,7 @@ static void call_nt_transact_notify_change(connection_struct *conn,
bool recursive;
if(setup_count < 6) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -1606,7 +1606,7 @@ static void call_nt_transact_notify_change(connection_struct *conn,
DEBUG(3,("call_nt_transact_notify_change\n"));
if(!fsp) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -1700,7 +1700,7 @@ static void call_nt_transact_rename(connection_struct *conn,
TALLOC_CTX *ctx = talloc_tos();
if(parameter_count < 5) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -1769,13 +1769,13 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
DATA_BLOB blob;
if(parameter_count < 8) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
fsp = file_fsp(req, SVAL(params,0));
if(!fsp) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -1787,7 +1787,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
params = nttrans_realloc(ppparams, 4);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -1839,7 +1839,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
data = nttrans_realloc(ppdata, sd_size);
if(data == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -1880,12 +1880,12 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
NTSTATUS status;
if(parameter_count < 8) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
if((fsp = file_fsp(req, SVAL(params,0))) == NULL) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -1899,7 +1899,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
fsp_str_dbg(fsp), (unsigned int)security_info_sent));
if (data_count == 0) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -2243,7 +2243,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
DEBUG(1,("get_user_quota: access_denied service [%s] user "
"[%s]\n", lp_servicename(SNUM(conn)),
conn->server_info->unix_name));
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
@@ -2253,7 +2253,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
if (parameter_count < 4) {
DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count));
- reply_doserror(req, ERRDOS, ERRinvalidparam);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -2288,7 +2288,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -2308,7 +2308,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
}
if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) {
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
@@ -2316,7 +2316,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -2325,7 +2325,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/
if(pdata == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -2388,20 +2388,20 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
if (data_count < 8) {
DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8));
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
sid_len = IVAL(pdata,4);
/* Ensure this is less than 1mb. */
if (sid_len > (1024*1024)) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
if (data_count < 8+sid_len) {
DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len)));
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
@@ -2432,13 +2432,13 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
if(params == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
pdata = nttrans_realloc(ppdata, data_len);
if(pdata == NULL) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
@@ -2472,7 +2472,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
default:
DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level));
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
break;
}
@@ -2510,7 +2510,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
DEBUG(1,("set_user_quota: access_denied service [%s] user "
"[%s]\n", lp_servicename(SNUM(conn)),
conn->server_info->unix_name));
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
@@ -2520,7 +2520,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
if (parameter_count < 2) {
DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count));
- reply_doserror(req, ERRDOS, ERRinvalidparam);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
@@ -2534,7 +2534,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
if (data_count < 40) {
DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40));
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
@@ -2548,7 +2548,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
if (data_count < 40+sid_len) {
DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %lu bytes data\n",data_count,(unsigned long)40+sid_len));
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
@@ -2565,7 +2565,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
((qt.usedspace != 0xFFFFFFFF)||
(IVAL(pdata,20)!=0xFFFFFFFF))) {
/* more than 32 bits? */
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
#endif /* LARGE_SMB_OFF_T */
@@ -2579,7 +2579,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
((qt.softlim != 0xFFFFFFFF)||
(IVAL(pdata,28)!=0xFFFFFFFF))) {
/* more than 32 bits? */
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
#endif /* LARGE_SMB_OFF_T */
@@ -2593,7 +2593,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
((qt.hardlim != 0xFFFFFFFF)||
(IVAL(pdata,36)!=0xFFFFFFFF))) {
/* more than 32 bits? */
- reply_doserror(req, ERRDOS, ERRunknownlevel);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
#endif /* LARGE_SMB_OFF_T */
@@ -2604,7 +2604,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
/* 44 unknown bytes left... */
if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
@@ -2738,7 +2738,7 @@ static void handle_nttrans(connection_struct *conn,
/* Error in request */
DEBUG(0,("handle_nttrans: Unknown request %d in "
"nttrans call\n", state->call));
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
}
return;
@@ -2774,7 +2774,7 @@ void reply_nttrans(struct smb_request *req)
function_code = SVAL(req->vwv+18, 0);
if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBnttrans);
return;
}
@@ -2788,7 +2788,7 @@ void reply_nttrans(struct smb_request *req)
}
if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBnttrans);
return;
}
@@ -2834,7 +2834,7 @@ void reply_nttrans(struct smb_request *req)
/* Don't allow more than 128mb for each value. */
if ((state->total_data > (1024*1024*128)) ||
(state->total_param > (1024*1024*128))) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBnttrans);
return;
}
@@ -2855,7 +2855,7 @@ void reply_nttrans(struct smb_request *req)
DEBUG(0,("reply_nttrans: data malloc fail for %u "
"bytes !\n", (unsigned int)state->total_data));
TALLOC_FREE(state);
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBnttrans);
return;
}
@@ -2877,7 +2877,7 @@ void reply_nttrans(struct smb_request *req)
"bytes !\n", (unsigned int)state->total_param));
SAFE_FREE(state->data);
TALLOC_FREE(state);
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBnttrans);
return;
}
@@ -2910,7 +2910,7 @@ void reply_nttrans(struct smb_request *req)
SAFE_FREE(state->data);
SAFE_FREE(state->param);
TALLOC_FREE(state);
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBnttrans);
return;
}
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index 091db09987..bf64c59afd 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -105,7 +105,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
/* at a mailslot or something we really, really don't understand, */
/* not just something we really don't understand. */
if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
@@ -119,7 +119,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
* Hack for NT printers... JRA.
*/
if(should_fail_next_srvsvc_open(fname)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
#endif
@@ -171,7 +171,7 @@ void reply_pipe_write(struct smb_request *req)
struct tevent_req *subreq;
if (!fsp_is_np(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -223,7 +223,7 @@ static void pipe_write_done(struct tevent_req *subreq)
/* Looks bogus to me now. Needs to be removed ? JRA. */
if ((nwritten == 0 && state->numtowrite != 0)) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto send;
}
@@ -266,7 +266,7 @@ void reply_pipe_write_and_X(struct smb_request *req)
struct tevent_req *subreq;
if (!fsp_is_np(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -340,7 +340,7 @@ static void pipe_write_andx_done(struct tevent_req *subreq)
/* Looks bogus to me now. Is this error message correct ? JRA. */
if (nwritten != state->numtowrite) {
- reply_doserror(req, ERRDOS,ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto done;
}
@@ -384,7 +384,7 @@ void reply_pipe_read_and_X(struct smb_request *req)
#endif
if (!fsp_is_np(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 65d0929024..828053811b 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -1068,7 +1068,7 @@ bool nt4_compatible_acls(void)
not get. Deny entries are implicit on get with ace->perms = 0.
****************************************************************************/
-static uint32_t map_canon_ace_perms(int snum,
+uint32_t map_canon_ace_perms(int snum,
enum security_ace_type *pacl_type,
mode_t perms,
bool directory_ace)
@@ -1570,7 +1570,7 @@ static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
****************************************************************************/
static bool create_canon_ace_lists(files_struct *fsp,
- SMB_STRUCT_STAT *pst,
+ const SMB_STRUCT_STAT *pst,
DOM_SID *pfile_owner_sid,
DOM_SID *pfile_grp_sid,
canon_ace **ppfile_ace,
@@ -2305,7 +2305,7 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
****************************************************************************/
static bool unpack_canon_ace(files_struct *fsp,
- SMB_STRUCT_STAT *pst,
+ const SMB_STRUCT_STAT *pst,
DOM_SID *pfile_owner_sid,
DOM_SID *pfile_grp_sid,
canon_ace **ppfile_ace,
@@ -2313,6 +2313,7 @@ static bool unpack_canon_ace(files_struct *fsp,
uint32 security_info_sent,
const SEC_DESC *psd)
{
+ SMB_STRUCT_STAT st;
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
@@ -2376,14 +2377,17 @@ static bool unpack_canon_ace(files_struct *fsp,
print_canon_ace_list( "file ace - before valid", file_ace);
+ st = *pst;
+
/*
* A default 3 element mode entry for a file should be r-- --- ---.
* A default 3 element mode entry for a directory should be rwx --- ---.
*/
- pst->st_ex_mode = create_default_mode(fsp, False);
+ st.st_ex_mode = create_default_mode(fsp, False);
- if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
@@ -2397,9 +2401,10 @@ static bool unpack_canon_ace(files_struct *fsp,
* it's a directory.
*/
- pst->st_ex_mode = create_default_mode(fsp, True);
+ st.st_ex_mode = create_default_mode(fsp, True);
- if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
@@ -4086,6 +4091,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
free_canon_ace_list(file_ace_list);
free_canon_ace_list(dir_ace_list);
+ /* Ensure the stat struct in the fsp is correct. */
+ status = vfs_stat_fsp(fsp);
+
return NT_STATUS_OK;
}
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 15d89a5450..572f37dbbe 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -1335,7 +1335,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
if (type == SMBntcreateX) {
reply_nterror(req, NT_STATUS_INVALID_HANDLE);
} else {
- reply_doserror(req, ERRSRV, ERRinvnid);
+ reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
}
return NULL;
}
@@ -1343,7 +1343,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
if (!change_to_user(conn,session_tag)) {
DEBUG(0, ("Error: Could not change to user. Removing "
"deferred open, mid=%d.\n", req->mid));
- reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
+ reply_force_doserror(req, ERRSRV, ERRbaduid);
return conn;
}
@@ -1357,7 +1357,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
/* IPC services are limited */
if (IS_IPC(conn) && !(flags & CAN_IPC)) {
- reply_doserror(req, ERRSRV,ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return conn;
}
} else {
@@ -1382,7 +1382,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
if (!set_current_service(conn,SVAL(req->inbuf,smb_flg),
(flags & (AS_USER|DO_CHDIR)
?True:False))) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return conn;
}
conn->num_smb_operations++;
@@ -1393,7 +1393,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
&& (!change_to_guest() ||
!check_access(smbd_server_fd(), lp_hostsallow(-1),
lp_hostsdeny(-1)))) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return conn;
}
@@ -1608,6 +1608,180 @@ static void fixup_chain_error_packet(struct smb_request *req)
SCVAL(req->outbuf, smb_vwv0, 0xff);
}
+/**
+ * @brief Find the smb_cmd offset of the last command pushed
+ * @param[in] buf The buffer we're building up
+ * @retval Where can we put our next andx cmd?
+ *
+ * While chaining requests, the "next" request we're looking at needs to put
+ * its SMB_Command before the data the previous request already built up added
+ * to the chain. Find the offset to the place where we have to put our cmd.
+ */
+
+static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs)
+{
+ uint8_t cmd;
+ size_t ofs;
+
+ cmd = CVAL(buf, smb_com);
+
+ SMB_ASSERT(is_andx_req(cmd));
+
+ ofs = smb_vwv0;
+
+ while (CVAL(buf, ofs) != 0xff) {
+
+ if (!is_andx_req(CVAL(buf, ofs))) {
+ return false;
+ }
+
+ /*
+ * ofs is from start of smb header, so add the 4 length
+ * bytes. The next cmd is right after the wct field.
+ */
+ ofs = SVAL(buf, ofs+2) + 4 + 1;
+
+ SMB_ASSERT(ofs+4 < talloc_get_size(buf));
+ }
+
+ *pofs = ofs;
+ return true;
+}
+
+/**
+ * @brief Do the smb chaining at a buffer level
+ * @param[in] poutbuf Pointer to the talloc'ed buffer to be modified
+ * @param[in] smb_command The command that we want to issue
+ * @param[in] wct How many words?
+ * @param[in] vwv The words, already in network order
+ * @param[in] bytes_alignment How shall we align "bytes"?
+ * @param[in] num_bytes How many bytes?
+ * @param[in] bytes The data the request ships
+ *
+ * smb_splice_chain() adds the vwv and bytes to the request already present in
+ * *poutbuf.
+ */
+
+static bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command,
+ uint8_t wct, const uint16_t *vwv,
+ size_t bytes_alignment,
+ uint32_t num_bytes, const uint8_t *bytes)
+{
+ uint8_t *outbuf;
+ size_t old_size, new_size;
+ size_t ofs;
+ size_t chain_padding = 0;
+ size_t bytes_padding = 0;
+ bool first_request;
+
+ old_size = talloc_get_size(*poutbuf);
+
+ /*
+ * old_size == smb_wct means we're pushing the first request in for
+ * libsmb/
+ */
+
+ first_request = (old_size == smb_wct);
+
+ if (!first_request && ((old_size % 4) != 0)) {
+ /*
+ * Align the wct field of subsequent requests to a 4-byte
+ * boundary
+ */
+ chain_padding = 4 - (old_size % 4);
+ }
+
+ /*
+ * After the old request comes the new wct field (1 byte), the vwv's
+ * and the num_bytes field. After at we might need to align the bytes
+ * given to us to "bytes_alignment", increasing the num_bytes value.
+ */
+
+ new_size = old_size + chain_padding + 1 + wct * sizeof(uint16_t) + 2;
+
+ if ((bytes_alignment != 0) && ((new_size % bytes_alignment) != 0)) {
+ bytes_padding = bytes_alignment - (new_size % bytes_alignment);
+ }
+
+ new_size += bytes_padding + num_bytes;
+
+ if ((smb_command != SMBwriteX) && (new_size > 0xffff)) {
+ DEBUG(1, ("splice_chain: %u bytes won't fit\n",
+ (unsigned)new_size));
+ return false;
+ }
+
+ outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size);
+ if (outbuf == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ *poutbuf = outbuf;
+
+ if (first_request) {
+ SCVAL(outbuf, smb_com, smb_command);
+ } else {
+ size_t andx_cmd_ofs;
+
+ if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) {
+ DEBUG(1, ("invalid command chain\n"));
+ *poutbuf = TALLOC_REALLOC_ARRAY(
+ NULL, *poutbuf, uint8_t, old_size);
+ return false;
+ }
+
+ if (chain_padding != 0) {
+ memset(outbuf + old_size, 0, chain_padding);
+ old_size += chain_padding;
+ }
+
+ SCVAL(outbuf, andx_cmd_ofs, smb_command);
+ SSVAL(outbuf, andx_cmd_ofs + 2, old_size - 4);
+ }
+
+ ofs = old_size;
+
+ /*
+ * Push the chained request:
+ *
+ * wct field
+ */
+
+ SCVAL(outbuf, ofs, wct);
+ ofs += 1;
+
+ /*
+ * vwv array
+ */
+
+ memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct);
+ ofs += sizeof(uint16_t) * wct;
+
+ /*
+ * bcc (byte count)
+ */
+
+ SSVAL(outbuf, ofs, num_bytes + bytes_padding);
+ ofs += sizeof(uint16_t);
+
+ /*
+ * padding
+ */
+
+ if (bytes_padding != 0) {
+ memset(outbuf + ofs, 0, bytes_padding);
+ ofs += bytes_padding;
+ }
+
+ /*
+ * The bytes field
+ */
+
+ memcpy(outbuf + ofs, bytes, num_bytes);
+
+ return true;
+}
+
/****************************************************************************
Construct a chained reply and add it to the already made reply
****************************************************************************/
@@ -1809,7 +1983,7 @@ void chain_reply(struct smb_request *req)
* We end up here if there's any error in the chain syntax. Report a
* DOS error, just like Windows does.
*/
- reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
+ reply_force_doserror(req, ERRSRV, ERRerror);
fixup_chain_error_packet(req);
done:
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 185f6014d1..b2d98bfbc0 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -704,7 +704,7 @@ void reply_tcon_and_X(struct smb_request *req)
}
if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
- reply_doserror(req, ERRDOS, ERRbuftoosmall);
+ reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
END_PROFILE(SMBtconX);
return;
}
@@ -744,7 +744,7 @@ void reply_tcon_and_X(struct smb_request *req)
q = strchr_m(path+2,'\\');
if (!q) {
data_blob_clear_free(&password);
- reply_doserror(req, ERRDOS, ERRnosuchshare);
+ reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
END_PROFILE(SMBtconX);
return;
}
@@ -864,7 +864,7 @@ void reply_unknown_new(struct smb_request *req, uint8 type)
{
DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
smb_fn_name(type), type, type));
- reply_doserror(req, ERRSRV, ERRunknownsmb);
+ reply_force_doserror(req, ERRSRV, ERRunknownsmb);
return;
}
@@ -901,7 +901,7 @@ void reply_ioctl(struct smb_request *req)
replysize = 32;
break;
default:
- reply_doserror(req, ERRSRV, ERRnosupport);
+ reply_force_doserror(req, ERRSRV, ERRnosupport);
END_PROFILE(SMBioctl);
return;
}
@@ -920,7 +920,7 @@ void reply_ioctl(struct smb_request *req)
files_struct *fsp = file_fsp(
req, SVAL(req->vwv+0, 0));
if (!fsp) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
END_PROFILE(SMBioctl);
return;
}
@@ -1652,7 +1652,7 @@ void reply_fclose(struct smb_request *req)
p += 2;
if (status_len == 0) {
- reply_doserror(req, ERRSRV, ERRsrverror);
+ reply_force_doserror(req, ERRSRV, ERRsrverror);
END_PROFILE(SMBfclose);
return;
}
@@ -1738,7 +1738,7 @@ void reply_open(struct smb_request *req)
OPENX_FILE_EXISTS_OPEN, &access_mask,
&share_mode, &create_disposition,
&create_options)) {
- reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+ reply_force_doserror(req, ERRDOS, ERRbadaccess);
goto out;
}
@@ -1789,7 +1789,8 @@ void reply_open(struct smb_request *req)
DEBUG(3,("attempt to open a directory %s\n",
fsp_str_dbg(fsp)));
close_file(req, fsp, ERROR_CLOSE);
- reply_doserror(req, ERRDOS,ERRnoaccess);
+ reply_botherror(req, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
goto out;
}
@@ -1875,7 +1876,7 @@ void reply_open_and_X(struct smb_request *req)
if (lp_nt_pipe_support()) {
reply_open_pipe_and_X(conn, req);
} else {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
}
goto out;
}
@@ -1910,7 +1911,7 @@ void reply_open_and_X(struct smb_request *req)
&access_mask, &share_mode,
&create_disposition,
&create_options)) {
- reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+ reply_force_doserror(req, ERRDOS, ERRbadaccess);
goto out;
}
@@ -1963,7 +1964,7 @@ void reply_open_and_X(struct smb_request *req)
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
if (fattr & aDIR) {
close_file(req, fsp, ERROR_CLOSE);
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
@@ -3198,7 +3199,7 @@ void reply_lockread(struct smb_request *req)
}
if (!CHECK_READ(fsp,req)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBlockread);
return;
}
@@ -3308,7 +3309,7 @@ void reply_read(struct smb_request *req)
}
if (!CHECK_READ(fsp,req)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBread);
return;
}
@@ -3338,7 +3339,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS,ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBread);
return;
}
@@ -3420,7 +3421,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
return;
}
@@ -3618,7 +3619,7 @@ void reply_read_and_X(struct smb_request *req)
}
if (!CHECK_READ(fsp,req)) {
- reply_doserror(req, ERRDOS,ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBreadX);
return;
}
@@ -3669,7 +3670,7 @@ void reply_read_and_X(struct smb_request *req)
"used and we don't support 64 bit offsets.\n",
(unsigned int)IVAL(req->vwv+10, 0) ));
END_PROFILE(SMBreadX);
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
@@ -3752,7 +3753,7 @@ void reply_writebraw(struct smb_request *req)
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
error_to_writebrawerr(req);
END_PROFILE(SMBwritebraw);
return;
@@ -3786,7 +3787,7 @@ void reply_writebraw(struct smb_request *req)
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
error_to_writebrawerr(req);
END_PROFILE(SMBwritebraw);
return;
@@ -3802,7 +3803,7 @@ void reply_writebraw(struct smb_request *req)
(int)nwritten, (int)write_through));
if (nwritten < (ssize_t)numtowrite) {
- reply_doserror(req, ERRHRD, ERRdiskfull);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
error_to_writebrawerr(req);
goto strict_unlock;
}
@@ -3812,7 +3813,7 @@ void reply_writebraw(struct smb_request *req)
/* Allocate a buffer of 64k + length. */
buf = TALLOC_ARRAY(NULL, char, 65540);
if (!buf) {
- reply_doserror(req, ERRDOS, ERRnomem);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
error_to_writebrawerr(req);
goto strict_unlock;
}
@@ -3968,7 +3969,7 @@ void reply_writeunlock(struct smb_request *req)
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS,ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBwriteunlock);
return;
}
@@ -3983,7 +3984,7 @@ void reply_writeunlock(struct smb_request *req)
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBwriteunlock);
return;
}
@@ -4013,7 +4014,7 @@ void reply_writeunlock(struct smb_request *req)
}
if((nwritten < numtowrite) && (numtowrite != 0)) {
- reply_doserror(req, ERRHRD, ERRdiskfull);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
goto strict_unlock;
}
@@ -4089,7 +4090,7 @@ void reply_write(struct smb_request *req)
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBwrite);
return;
}
@@ -4103,7 +4104,7 @@ void reply_write(struct smb_request *req)
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBwrite);
return;
}
@@ -4147,7 +4148,7 @@ void reply_write(struct smb_request *req)
}
if((nwritten == 0) && (numtowrite != 0)) {
- reply_doserror(req, ERRHRD, ERRdiskfull);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
goto strict_unlock;
}
@@ -4299,14 +4300,14 @@ void reply_write_and_X(struct smb_request *req)
return;
}
if (numtowrite != req->unread_bytes) {
- reply_doserror(req, ERRDOS, ERRbadmem);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
END_PROFILE(SMBwriteX);
return;
}
} else {
if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
smb_doff + numtowrite > smblen) {
- reply_doserror(req, ERRDOS, ERRbadmem);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
END_PROFILE(SMBwriteX);
return;
}
@@ -4315,7 +4316,7 @@ void reply_write_and_X(struct smb_request *req)
/* If it's an IPC, pass off the pipe handler. */
if (IS_IPC(conn)) {
if (req->unread_bytes) {
- reply_doserror(req, ERRDOS, ERRbadmem);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
END_PROFILE(SMBwriteX);
return;
}
@@ -4334,7 +4335,7 @@ void reply_write_and_X(struct smb_request *req)
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBwriteX);
return;
}
@@ -4358,7 +4359,7 @@ void reply_write_and_X(struct smb_request *req)
DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
"used and we don't support 64 bit offsets.\n",
(unsigned int)IVAL(req->vwv+12, 0) ));
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBwriteX);
return;
}
@@ -4371,7 +4372,7 @@ void reply_write_and_X(struct smb_request *req)
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBwriteX);
return;
}
@@ -4400,7 +4401,7 @@ void reply_write_and_X(struct smb_request *req)
}
if((nwritten == 0) && (numtowrite != 0)) {
- reply_doserror(req, ERRHRD, ERRdiskfull);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
goto strict_unlock;
}
@@ -4611,7 +4612,7 @@ void reply_close(struct smb_request *req)
*/
if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
END_PROFILE(SMBclose);
return;
}
@@ -4690,7 +4691,7 @@ void reply_writeclose(struct smb_request *req)
return;
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS,ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBwriteclose);
return;
}
@@ -4706,7 +4707,7 @@ void reply_writeclose(struct smb_request *req)
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_doserror(req, ERRDOS,ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBwriteclose);
return;
}
@@ -4732,7 +4733,7 @@ void reply_writeclose(struct smb_request *req)
conn->num_files_open));
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
- reply_doserror(req, ERRHRD, ERRdiskfull);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
goto strict_unlock;
}
@@ -4882,7 +4883,7 @@ void reply_tdis(struct smb_request *req)
if (!conn) {
DEBUG(4,("Invalid connection in tdis\n"));
- reply_doserror(req, ERRSRV, ERRinvnid);
+ reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
END_PROFILE(SMBtdis);
return;
}
@@ -4982,7 +4983,7 @@ void reply_printopen(struct smb_request *req)
}
if (!CAN_PRINT(conn)) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBsplopen);
return;
}
@@ -5040,7 +5041,7 @@ void reply_printclose(struct smb_request *req)
}
if (!CAN_PRINT(conn)) {
- reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
+ reply_force_doserror(req, ERRSRV, ERRerror);
END_PROFILE(SMBsplclose);
return;
}
@@ -5088,7 +5089,7 @@ void reply_printqueue(struct smb_request *req)
one printer - I think we should now only accept it if they
get it right (tridge) */
if (!CAN_PRINT(conn)) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBsplretq);
return;
}
@@ -5182,13 +5183,13 @@ void reply_printwrite(struct smb_request *req)
}
if (!CAN_PRINT(conn)) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBsplwr);
return;
}
if (!CHECK_WRITE(fsp)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBsplwr);
return;
}
@@ -6548,7 +6549,7 @@ void reply_copy(struct smb_request *req)
if (tid2 != conn->cnum) {
/* can't currently handle inter share copies XXXX */
DEBUG(3,("Rejecting inter-share copy\n"));
- reply_doserror(req, ERRSRV, ERRinvdevice);
+ reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
goto out;
}
@@ -6587,19 +6588,19 @@ void reply_copy(struct smb_request *req)
target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
if ((flags&1) && target_is_directory) {
- reply_doserror(req, ERRDOS, ERRbadfile);
+ reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
goto out;
}
if ((flags&2) && !target_is_directory) {
- reply_doserror(req, ERRDOS, ERRbadpath);
+ reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
goto out;
}
if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
/* wants a tree copy! XXXX */
DEBUG(3,("Rejecting tree copy\n"));
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
}
@@ -6810,7 +6811,7 @@ void reply_copy(struct smb_request *req)
}
if (count == 0) {
- reply_doserror(req, ERRDOS, error);
+ reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
goto out;
}
@@ -7239,7 +7240,7 @@ void reply_lockingX(struct smb_request *req)
/* we don't support these - and CANCEL_LOCK makes w2k
and XP reboot so I don't really want to be
compatible! (tridge) */
- reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+ reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
END_PROFILE(SMBlockingX);
return;
}
@@ -7282,7 +7283,7 @@ void reply_lockingX(struct smb_request *req)
return;
} else {
END_PROFILE(SMBlockingX);
- reply_doserror(req, ERRDOS, ERRlock);
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
return;
}
}
@@ -7350,8 +7351,8 @@ void reply_lockingX(struct smb_request *req)
* There is no error code marked "stupid client bug".... :-).
*/
if(err) {
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBlockingX);
- reply_doserror(req, ERRDOS, ERRnoaccess);
return;
}
}
@@ -7385,8 +7386,8 @@ void reply_lockingX(struct smb_request *req)
* There is no error code marked "stupid client bug".... :-).
*/
if(err) {
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBlockingX);
- reply_doserror(req, ERRDOS, ERRnoaccess);
return;
}
}
@@ -7427,7 +7428,7 @@ void reply_lockingX(struct smb_request *req)
void reply_readbmpx(struct smb_request *req)
{
START_PROFILE(SMBreadBmpx);
- reply_doserror(req, ERRSRV, ERRuseSTD);
+ reply_force_doserror(req, ERRSRV, ERRuseSTD);
END_PROFILE(SMBreadBmpx);
return;
}
@@ -7441,7 +7442,7 @@ void reply_readbmpx(struct smb_request *req)
void reply_readbs(struct smb_request *req)
{
START_PROFILE(SMBreadBs);
- reply_doserror(req, ERRSRV, ERRuseSTD);
+ reply_force_doserror(req, ERRSRV, ERRuseSTD);
END_PROFILE(SMBreadBs);
return;
}
@@ -7468,7 +7469,7 @@ void reply_setattrE(struct smb_request *req)
fsp = file_fsp(req, SVAL(req->vwv+0, 0));
if(!fsp || (fsp->conn != conn)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
goto out;
}
@@ -7499,7 +7500,7 @@ void reply_setattrE(struct smb_request *req)
status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
- reply_doserror(req, ERRDOS, ERRnoaccess);
+ reply_nterror(req, status);
goto out;
}
@@ -7527,7 +7528,7 @@ void reply_setattrE(struct smb_request *req)
void reply_writebmpx(struct smb_request *req)
{
START_PROFILE(SMBwriteBmpx);
- reply_doserror(req, ERRSRV, ERRuseSTD);
+ reply_force_doserror(req, ERRSRV, ERRuseSTD);
END_PROFILE(SMBwriteBmpx);
return;
}
@@ -7541,7 +7542,7 @@ void reply_writebmpx(struct smb_request *req)
void reply_writebs(struct smb_request *req)
{
START_PROFILE(SMBwriteBs);
- reply_doserror(req, ERRSRV, ERRuseSTD);
+ reply_force_doserror(req, ERRSRV, ERRuseSTD);
END_PROFILE(SMBwriteBs);
return;
}
@@ -7568,7 +7569,7 @@ void reply_getattrE(struct smb_request *req)
fsp = file_fsp(req, SVAL(req->vwv+0, 0));
if(!fsp || (fsp->conn != conn)) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
END_PROFILE(SMBgetattrE);
return;
}
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
index 2d738cbd12..700d7ea02e 100644
--- a/source3/smbd/seal.c
+++ b/source3/smbd/seal.c
@@ -20,6 +20,7 @@
#include "includes.h"
#include "smbd/globals.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
/******************************************************************************
Server side encryption.
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index addd386fb4..612cf2231a 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -25,6 +25,7 @@
#include "includes.h"
#include "smbd/globals.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
/* For split krb5 SPNEGO blobs. */
struct pending_auth_data {
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index dc24124b54..0df4bd6c56 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -22,6 +22,7 @@
#include "smbd/globals.h"
#include "../libcli/smb/smb_common.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
uint64_t in_session_id,
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 40c1af2aeb..df61167354 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1012,7 +1012,7 @@ static void call_trans2open(connection_struct *conn,
pname = &params[28];
if (IS_IPC(conn)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
goto out;
}
@@ -1055,7 +1055,7 @@ static void call_trans2open(connection_struct *conn,
&access_mask, &share_mode,
&create_disposition,
&create_options)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
@@ -1121,7 +1121,7 @@ static void call_trans2open(connection_struct *conn,
inode = smb_fname->st.st_ex_ino;
if (fattr & aDIR) {
close_file(req, fsp, ERROR_CLOSE);
- reply_doserror(req, ERRDOS,ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
@@ -2334,7 +2334,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS, ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
goto out;
}
@@ -2462,7 +2462,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
if(numentries == 0) {
dptr_close(sconn, &dptr_num);
if (get_Protocol() < PROTOCOL_NT1) {
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_force_doserror(req, ERRDOS, ERRnofiles);
goto out;
} else {
reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
@@ -2649,7 +2649,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS, ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
return;
}
@@ -2682,7 +2682,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
/* Check that the dptr is valid */
if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_nterror(req, STATUS_NO_MORE_FILES);
return;
}
@@ -2691,7 +2691,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
/* Get the wildcard mask from the dptr */
if((p = dptr_wcard(sconn, dptr_num))== NULL) {
DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_nterror(req, STATUS_NO_MORE_FILES);
return;
}
@@ -5231,8 +5231,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS,
- ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
return;
}
@@ -7664,7 +7663,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
max_data_bytes);
return;
} else {
- reply_doserror(req, ERRDOS, ERRbadpath);
+ reply_nterror(req,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND);
return;
}
} else {
@@ -7804,7 +7804,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
TALLOC_CTX *ctx = talloc_tos();
if (!CAN_WRITE(conn)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
@@ -8023,7 +8023,7 @@ static void call_trans2getdfsreferral(connection_struct *conn,
max_referral_level = SVAL(params,0);
if(!lp_host_msdfs()) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
return;
}
@@ -8065,7 +8065,7 @@ static void call_trans2ioctl(connection_struct *conn,
/* check for an invalid fid before proceeding */
if (!fsp) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
@@ -8094,7 +8094,7 @@ static void call_trans2ioctl(connection_struct *conn,
}
DEBUG(2,("Unknown TRANS2_IOCTL\n"));
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
}
/****************************************************************************
@@ -8320,7 +8320,7 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
default:
/* Error in request */
DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
- reply_doserror(req, ERRSRV,ERRerror);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
}
}
@@ -8372,7 +8372,7 @@ void reply_trans2(struct smb_request *req)
case TRANSACT2_SETFSINFO:
break;
default:
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBtrans2);
return;
}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 5a0a300092..c7a69ae403 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -364,8 +364,11 @@ bool torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
bool torture_close_connection(struct cli_state *c)
{
bool ret = True;
- if (!cli_tdis(c)) {
- printf("tdis failed (%s)\n", cli_errstr(c));
+ NTSTATUS status;
+
+ status = cli_tdis(c);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("tdis failed (%s)\n", nt_errstr(status));
ret = False;
}
@@ -1192,8 +1195,9 @@ static bool run_tcon_test(int dummy)
cli->cnum = cnum2;
- if (!cli_tdis(cli)) {
- printf("secondary tdis failed (%s)\n", cli_errstr(cli));
+ status = cli_tdis(cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("secondary tdis failed (%s)\n", nt_errstr(status));
return False;
}
@@ -5321,9 +5325,10 @@ static bool run_sesssetup_bench(int dummy)
d_printf("\r%d ", (int)c->vuid);
- if (!cli_ulogoff(c)) {
+ status = cli_ulogoff(c);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf("(%s) cli_ulogoff failed: %s\n",
- __location__, cli_errstr(c));
+ __location__, nt_errstr(status));
return false;
}
c->vuid = 0;
@@ -5796,7 +5801,8 @@ static bool run_notify_bench(int dummy)
struct tevent_context *ev;
NTSTATUS status;
uint16_t dnum;
- struct tevent_req *req1, *req2;
+ struct tevent_req *req1;
+ struct tevent_req *req2 = NULL;
int i, num_unc_names;
int num_finished = 0;
@@ -5964,7 +5970,7 @@ static bool run_windows_write(int dummy)
int i;
bool ret = false;
const char *fname = "\\writetest.txt";
- struct timeval start;
+ struct timeval start_time;
double seconds;
double kbytes;
@@ -5980,7 +5986,7 @@ static bool run_windows_write(int dummy)
cli_sockopt(cli1, sockops);
- start = timeval_current();
+ start_time = timeval_current();
for (i=0; i<torture_numops; i++) {
char c = 0;
@@ -6002,7 +6008,7 @@ static bool run_windows_write(int dummy)
}
}
- seconds = timeval_elapsed(&start);
+ seconds = timeval_elapsed(&start_time);
kbytes = (double)torture_blocksize * torture_numops;
kbytes /= 1024;
@@ -6042,6 +6048,7 @@ static bool run_uid_regression_test(int dummy)
int16_t old_vuid;
int16_t old_cnum;
bool correct = True;
+ NTSTATUS status;
printf("starting uid regression test\n");
@@ -6054,9 +6061,10 @@ static bool run_uid_regression_test(int dummy)
/* Ok - now save then logoff our current user. */
old_vuid = cli->vuid;
- if (!cli_ulogoff(cli)) {
+ status = cli_ulogoff(cli);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf("(%s) cli_ulogoff failed: %s\n",
- __location__, cli_errstr(cli));
+ __location__, nt_errstr(status));
correct = false;
goto out;
}
@@ -6078,17 +6086,20 @@ static bool run_uid_regression_test(int dummy)
cli->vuid = 0;
/* This should succeed. */
- if (cli_tdis(cli)) {
+ status = cli_tdis(cli);
+
+ if (NT_STATUS_IS_OK(status)) {
printf("First tdis with invalid vuid should succeed.\n");
} else {
- printf("First tdis failed (%s)\n", cli_errstr(cli));
+ printf("First tdis failed (%s)\n", nt_errstr(status));
}
cli->vuid = old_vuid;
cli->cnum = old_cnum;
/* This should fail. */
- if (cli_tdis(cli)) {
+ status = cli_tdis(cli);
+ if (NT_STATUS_IS_OK(status)) {
printf("Second tdis with invalid vuid should fail - succeeded instead !.\n");
} else {
/* Should be bad tid. */
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index f133eec0fc..8e644bb6b2 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -1007,6 +1007,8 @@ static NTSTATUS net_ads_join_ok(struct net_context *c)
{
ADS_STRUCT *ads = NULL;
ADS_STATUS status;
+ fstring dc_name;
+ struct sockaddr_storage dcip;
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
@@ -1015,6 +1017,8 @@ static NTSTATUS net_ads_join_ok(struct net_context *c)
net_use_krb_machine_account(c);
+ get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
+
status = ads_startup(c, true, &ads);
if (!ADS_ERR_OK(status)) {
return ads_ntstatus(status);
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 5b3b1e34d7..7dc8c1dd2c 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -3074,13 +3074,19 @@ static int rpc_share_list(struct net_context *c, int argc, const char **argv)
static bool check_share_availability(struct cli_state *cli, const char *netname)
{
- if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, netname, "A:", "", 0))) {
+ NTSTATUS status;
+
+ status = cli_tcon_andx(cli, netname, "A:", "", 0);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf(_("skipping [%s]: not a file share.\n"), netname);
return false;
}
- if (!cli_tdis(cli))
+ status = cli_tdis(cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf(_("cli_tdis returned %s\n"), nt_errstr(status));
return false;
+ }
return true;
}
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index 87df3c6160..57e4251543 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -27,6 +27,7 @@
#include "utils/ntlm_auth.h"
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
#include "smb_krb5.h"
#include <iniparser.h>
@@ -635,7 +636,7 @@ static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *u
return nt_status;
}
-static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state)
+static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
{
NTSTATUS status;
if ( (opt_username == NULL) || (opt_domain == NULL) ) {
@@ -685,7 +686,7 @@ static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_st
return NT_STATUS_OK;
}
-static NTSTATUS ntlm_auth_start_ntlmssp_server(NTLMSSP_STATE **ntlmssp_state)
+static NTSTATUS ntlm_auth_start_ntlmssp_server(struct ntlmssp_state **ntlmssp_state)
{
NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
@@ -1172,7 +1173,7 @@ static void offer_gss_spnego_mechs(void) {
static void manage_gss_spnego_request(struct ntlm_auth_state *state,
char *buf, int length)
{
- static NTLMSSP_STATE *ntlmssp_state = NULL;
+ static struct ntlmssp_state *ntlmssp_state = NULL;
struct spnego_data request, response;
DATA_BLOB token;
NTSTATUS status;
@@ -1415,7 +1416,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state,
return;
}
-static NTLMSSP_STATE *client_ntlmssp_state = NULL;
+static struct ntlmssp_state *client_ntlmssp_state = NULL;
static bool manage_client_ntlmssp_init(struct spnego_data spnego)
{
diff --git a/source3/winbindd/wb_getgrsid.c b/source3/winbindd/wb_getgrsid.c
index 03d71e45b9..bb93be2174 100644
--- a/source3/winbindd/wb_getgrsid.c
+++ b/source3/winbindd/wb_getgrsid.c
@@ -52,6 +52,17 @@ struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->max_nesting = max_nesting;
+ if (lp_winbind_trusted_domains_only()) {
+ struct winbindd_domain *our_domain = find_our_domain();
+
+ if (sid_compare_domain(group_sid, &our_domain->sid) == 0) {
+ DEBUG(7, ("winbindd_getgrsid: My domain -- rejecting "
+ "getgrsid() for %s\n", sid_string_tos(group_sid)));
+ tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
+ return tevent_req_post(req, ev);
+ }
+ }
+
subreq = wb_lookupsid_send(state, ev, &state->sid);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/winbindd/wb_gettoken.c b/source3/winbindd/wb_gettoken.c
index 26189e5a97..ca407b2117 100644
--- a/source3/winbindd/wb_gettoken.c
+++ b/source3/winbindd/wb_gettoken.c
@@ -60,6 +60,13 @@ struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
+ if (lp_winbind_trusted_domains_only() && domain->primary) {
+ DEBUG(7, ("wb_gettoken: My domain -- rejecting getgroups() "
+ "for %s.\n", sid_string_tos(sid)));
+ tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
+ return tevent_req_post(req, ev);
+ }
+
subreq = wb_lookupusergroups_send(state, ev, domain, &state->usersid);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/winbindd/wb_sid2gid.c b/source3/winbindd/wb_sid2gid.c
index a578746ea2..e15d563cd7 100644
--- a/source3/winbindd/wb_sid2gid.c
+++ b/source3/winbindd/wb_sid2gid.c
@@ -54,7 +54,7 @@ struct tevent_req *wb_sid2gid_send(TALLOC_CTX *mem_ctx,
DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n",
(int)state->gid, expired ? " (expired)": ""));
- if (!expired || IS_DOMAIN_OFFLINE(find_our_domain())) {
+ if (!expired || is_domain_offline(find_our_domain())) {
if (state->gid == -1) {
tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
} else {
diff --git a/source3/winbindd/wb_sid2uid.c b/source3/winbindd/wb_sid2uid.c
index abfe257bfa..9c22b8d10b 100644
--- a/source3/winbindd/wb_sid2uid.c
+++ b/source3/winbindd/wb_sid2uid.c
@@ -53,7 +53,7 @@ struct tevent_req *wb_sid2uid_send(TALLOC_CTX *mem_ctx,
DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n",
(int)state->uid, expired ? " (expired)": ""));
- if (!expired || IS_DOMAIN_OFFLINE(find_our_domain())) {
+ if (!expired || is_domain_offline(find_our_domain())) {
if (state->uid == -1) {
tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
} else {
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index e09374c5cb..f6f4a8fee7 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -532,6 +532,8 @@ static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
winbindd_list_groups_send, winbindd_list_groups_recv },
{ WINBINDD_CHECK_MACHACC, "CHECK_MACHACC",
winbindd_check_machine_acct_send, winbindd_check_machine_acct_recv },
+ { WINBINDD_PING_DC, "PING_DC",
+ winbindd_ping_dc_send, winbindd_ping_dc_recv },
{ 0, NULL, NULL, NULL }
};
@@ -796,10 +798,15 @@ static void winbind_client_request_read(struct tevent_req *req)
ret = wb_req_read_recv(req, state, &state->request, &err);
TALLOC_FREE(req);
if (ret == -1) {
+ if (err == EPIPE) {
+ DEBUG(6, ("closing socket %d, client exited\n",
+ state->sock));
+ } else {
+ DEBUG(2, ("Could not read client request from fd %d: "
+ "%s\n", state->sock, strerror(err)));
+ }
close(state->sock);
state->sock = -1;
- DEBUG(2, ("Could not read client request: %s\n",
- strerror(err)));
remove_client(state);
return;
}
@@ -833,10 +840,6 @@ static void remove_client(struct winbindd_cli_state *state)
state->sock = -1;
}
- /* Free any getent state */
-
- free_getent_state(state->getgrent_state);
-
TALLOC_FREE(state->mem_ctx);
/* Remove from list and free */
@@ -855,7 +858,7 @@ static bool remove_idle_client(void)
for (state = winbindd_client_list(); state; state = state->next) {
if (state->response == NULL &&
- !state->pwent_state && !state->getgrent_state) {
+ !state->pwent_state && !state->grent_state) {
nidle++;
if (!last_access || state->last_access < last_access) {
last_access = state->last_access;
diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
index 2e7d09f442..ea791234fb 100644
--- a/source3/winbindd/winbindd.h
+++ b/source3/winbindd/winbindd.h
@@ -65,22 +65,11 @@ struct winbindd_cli_state {
* initialized? */
bool getgrent_initialized; /* Has getgrent_state been
* initialized? */
- struct getent_state *getgrent_state; /* State for getgrent() */
struct getpwent_state *pwent_state; /* State for getpwent() */
struct getgrent_state *grent_state; /* State for getgrent() */
};
-/* State between get{pw,gr}ent() calls */
-
-struct getent_state {
- struct getent_state *prev, *next;
- void *sam_entries;
- uint32 sam_entry_index, num_sam_entries;
- bool got_sam_entries;
- fstring domain_name;
-};
-
struct getpwent_state {
struct winbindd_domain *domain;
int next_user;
@@ -121,8 +110,6 @@ struct winbindd_cm_conn {
struct rpc_pipe_client *netlogon_pipe;
};
-struct winbindd_async_request;
-
/* Async child */
struct winbindd_domain;
@@ -326,10 +313,7 @@ struct winbindd_methods {
/* enumerate trusted domains */
NTSTATUS (*trusted_domains)(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids);
+ struct netr_DomainTrustList *trusts);
};
/* Filled out by IDMAP backends */
@@ -400,9 +384,4 @@ struct WINBINDD_CCACHE_ENTRY {
#define WINBINDD_PAM_AUTH_KRB5_RENEW_TIME 2592000 /* one month */
#define DOM_SEQUENCE_NONE ((uint32)-1)
-#define IS_DOMAIN_OFFLINE(x) ( lp_winbind_offline_logon() && \
- ( get_global_winbindd_state_offline() \
- || !(x)->online ) )
-#define IS_DOMAIN_ONLINE(x) (!IS_DOMAIN_OFFLINE(x))
-
#endif /* _WINBINDD_H */
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index 92c0272088..d15fb86d86 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -1257,33 +1257,23 @@ static NTSTATUS password_policy(struct winbindd_domain *domain,
/* get a list of trusted domains */
static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ struct netr_DomainTrustList *trusts)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- struct netr_DomainTrustList trusts;
int i;
uint32 flags;
struct rpc_pipe_client *cli;
- uint32 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT);
int ret_count;
DEBUG(3,("ads: trusted_domains\n"));
- *num_domains = 0;
- *alt_names = NULL;
- *names = NULL;
- *dom_sids = NULL;
+ ZERO_STRUCTP(trusts);
/* If this is our primary domain or a root in our forest,
query for all trusts. If not, then just look for domain
trusts in the target forest */
- if ( domain->primary ||
- ((domain->domain_flags&fr_flags) == fr_flags) )
- {
+ if (domain->primary || domain_is_forest_root(domain)) {
flags = NETR_TRUST_FLAG_OUTBOUND |
NETR_TRUST_FLAG_INBOUND |
NETR_TRUST_FLAG_IN_FOREST;
@@ -1303,142 +1293,121 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
cli->desthost,
flags,
- &trusts,
+ trusts,
NULL);
- if ( NT_STATUS_IS_OK(result) && trusts.count) {
-
- /* Allocate memory for trusted domain names and sids */
-
- if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
- DEBUG(0, ("trusted_domains: out of memory\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
- DEBUG(0, ("trusted_domains: out of memory\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, trusts.count)) ) {
- DEBUG(0, ("trusted_domains: out of memory\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- /* Copy across names and sids */
-
-
- ret_count = 0;
- for (i = 0; i < trusts.count; i++) {
- struct winbindd_domain d;
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+ if (trusts->count == 0) {
+ return NT_STATUS_OK;
+ }
- ZERO_STRUCT(d);
+ /* Copy across names and sids */
- /* drop external trusts if this is not our primary
- domain. This means that the returned number of
- domains may be less that the ones actually trusted
- by the DC. */
+ ret_count = 0;
+ for (i = 0; i < trusts->count; i++) {
+ struct netr_DomainTrust *trust = &trusts->array[i];
+ struct winbindd_domain d;
- if ( (trusts.array[i].trust_attributes == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
- !domain->primary )
- {
- DEBUG(10,("trusted_domains: Skipping external trusted domain "
- "%s because it is outside of our primary domain\n",
- trusts.array[i].netbios_name));
- continue;
- }
+ ZERO_STRUCT(d);
- /* We must check that the SID of each trusted domain
- * was returned to work around a bug in Windows:
- * http://support.microsoft.com/kb/922832 */
+ /*
+ * drop external trusts if this is not our primary
+ * domain. This means that the returned number of
+ * domains may be less that the ones actually trusted
+ * by the DC.
+ */
- (*names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].netbios_name);
- (*alt_names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].dns_name);
- if (trusts.array[i].sid) {
- sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid);
- } else {
- sid_copy(&(*dom_sids)[ret_count], &global_sid_NULL);
- }
+ if ((trust->trust_attributes
+ == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
+ !domain->primary )
+ {
+ DEBUG(10,("trusted_domains: Skipping external trusted "
+ "domain %s because it is outside of our "
+ "primary domain\n",
+ trust->netbios_name));
+ continue;
+ }
- /* add to the trusted domain cache */
+ /* add to the trusted domain cache */
- fstrcpy( d.name, trusts.array[i].netbios_name);
- fstrcpy( d.alt_name, trusts.array[i].dns_name);
- if (trusts.array[i].sid) {
- sid_copy( &d.sid, trusts.array[i].sid);
- } else {
- sid_copy(&d.sid, &global_sid_NULL);
- }
+ fstrcpy(d.name, trust->netbios_name);
+ fstrcpy(d.alt_name, trust->dns_name);
+ if (trust->sid) {
+ sid_copy(&d.sid, trust->sid);
+ } else {
+ sid_copy(&d.sid, &global_sid_NULL);
+ }
- if ( domain->primary ) {
+ if ( domain->primary ) {
+ DEBUG(10,("trusted_domains(ads): Searching "
+ "trusted domain list of %s and storing "
+ "trust flags for domain %s\n",
+ domain->name, d.alt_name));
+
+ d.domain_flags = trust->trust_flags;
+ d.domain_type = trust->trust_type;
+ d.domain_trust_attribs = trust->trust_attributes;
+
+ wcache_tdc_add_domain( &d );
+ ret_count++;
+ } else if (domain_is_forest_root(domain)) {
+ /* Check if we already have this record. If
+ * we are following our forest root that is not
+ * our primary domain, we want to keep trust
+ * flags from the perspective of our primary
+ * domain not our forest root. */
+ struct winbindd_tdc_domain *exist = NULL;
+
+ exist = wcache_tdc_fetch_domain(
+ talloc_tos(), trust->netbios_name);
+ if (!exist) {
DEBUG(10,("trusted_domains(ads): Searching "
- "trusted domain list of %s and storing "
- "trust flags for domain %s\n",
- domain->name, d.alt_name));
-
- d.domain_flags = trusts.array[i].trust_flags;
- d.domain_type = trusts.array[i].trust_type;
- d.domain_trust_attribs = trusts.array[i].trust_attributes;
+ "trusted domain list of %s and "
+ "storing trust flags for domain "
+ "%s\n", domain->name, d.alt_name));
+ d.domain_flags = trust->trust_flags;
+ d.domain_type = trust->trust_type;
+ d.domain_trust_attribs =
+ trust->trust_attributes;
wcache_tdc_add_domain( &d );
ret_count++;
- } else if ( (domain->domain_flags&fr_flags) == fr_flags ) {
- /* Check if we already have this record. If
- * we are following our forest root that is not
- * our primary domain, we want to keep trust
- * flags from the perspective of our primary
- * domain not our forest root. */
- struct winbindd_tdc_domain *exist = NULL;
-
- exist =
- wcache_tdc_fetch_domain(NULL, trusts.array[i].netbios_name);
- if (!exist) {
- DEBUG(10,("trusted_domains(ads): Searching "
- "trusted domain list of %s and storing "
- "trust flags for domain %s\n",
- domain->name, d.alt_name));
- d.domain_flags = trusts.array[i].trust_flags;
- d.domain_type = trusts.array[i].trust_type;
- d.domain_trust_attribs = trusts.array[i].trust_attributes;
-
- wcache_tdc_add_domain( &d );
- ret_count++;
- }
- TALLOC_FREE(exist);
+ }
+ TALLOC_FREE(exist);
+ } else {
+ /* This gets a little tricky. If we are
+ following a transitive forest trust, then
+ innerit the flags, type, and attribs from
+ the domain we queried to make sure we don't
+ record the view of the trust from the wrong
+ side. Always view it from the side of our
+ primary domain. --jerry */
+ struct winbindd_tdc_domain *parent = NULL;
+
+ DEBUG(10,("trusted_domains(ads): Searching "
+ "trusted domain list of %s and inheriting "
+ "trust flags for domain %s\n",
+ domain->name, d.alt_name));
+
+ parent = wcache_tdc_fetch_domain(talloc_tos(),
+ domain->name);
+ if (parent) {
+ d.domain_flags = parent->trust_flags;
+ d.domain_type = parent->trust_type;
+ d.domain_trust_attribs = parent->trust_attribs;
} else {
- /* This gets a little tricky. If we are
- following a transitive forest trust, then
- innerit the flags, type, and attribs from
- the domain we queried to make sure we don't
- record the view of the trust from the wrong
- side. Always view it from the side of our
- primary domain. --jerry */
- struct winbindd_tdc_domain *parent = NULL;
-
- DEBUG(10,("trusted_domains(ads): Searching "
- "trusted domain list of %s and inheriting "
- "trust flags for domain %s\n",
- domain->name, d.alt_name));
-
- parent = wcache_tdc_fetch_domain(NULL, domain->name);
- if (parent) {
- d.domain_flags = parent->trust_flags;
- d.domain_type = parent->trust_type;
- d.domain_trust_attribs = parent->trust_attribs;
- } else {
- d.domain_flags = domain->domain_flags;
- d.domain_type = domain->domain_type;
- d.domain_trust_attribs = domain->domain_trust_attribs;
- }
- TALLOC_FREE(parent);
-
- wcache_tdc_add_domain( &d );
- ret_count++;
+ d.domain_flags = domain->domain_flags;
+ d.domain_type = domain->domain_type;
+ d.domain_trust_attribs =
+ domain->domain_trust_attribs;
}
- }
+ TALLOC_FREE(parent);
- *num_domains = ret_count;
+ wcache_tdc_add_domain( &d );
+ ret_count++;
+ }
}
-
return result;
}
diff --git a/source3/winbindd/winbindd_async.c b/source3/winbindd/winbindd_async.c
index 6c5d92e71b..5a350b99bc 100644
--- a/source3/winbindd/winbindd_async.c
+++ b/source3/winbindd/winbindd_async.c
@@ -6,17 +6,6 @@
Copyright (C) Volker Lendecke 2005
Copyright (C) Gerald Carter 2006
- The helpers always consist of three functions:
-
- * A request setup function that takes the necessary parameters together
- with a continuation function that is to be called upon completion
-
- * A private continuation function that is internal only. This is to be
- called by the lower-level functions in do_async(). Its only task is to
- properly call the continuation function named above.
-
- * A worker function that is called inside the appropriate child process.
-
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
@@ -37,423 +26,6 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-struct do_async_state {
- TALLOC_CTX *mem_ctx;
- struct winbindd_request request;
- struct winbindd_response response;
- void (*cont)(TALLOC_CTX *mem_ctx,
- bool success,
- struct winbindd_response *response,
- void *c, void *private_data);
- void *c, *private_data;
-};
-
-static void do_async_recv(void *private_data, bool success)
-{
- struct do_async_state *state =
- talloc_get_type_abort(private_data, struct do_async_state);
-
- state->cont(state->mem_ctx, success, &state->response,
- state->c, state->private_data);
-}
-
-void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
- const struct winbindd_request *request,
- void (*cont)(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data),
- void *c, void *private_data)
-{
- struct do_async_state *state;
-
- state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
- if (state == NULL) {
- DEBUG(0, ("talloc failed\n"));
- cont(mem_ctx, False, NULL, c, private_data);
- return;
- }
-
- state->mem_ctx = mem_ctx;
- state->request = *request;
- state->request.length = sizeof(state->request);
- state->cont = cont;
- state->c = c;
- state->private_data = private_data;
-
- async_request(mem_ctx, child, &state->request,
- &state->response, do_async_recv, state);
-}
-
-static void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
- const struct winbindd_request *request,
- void (*cont)(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data),
- void *c, void *private_data)
-{
- struct do_async_state *state;
-
- state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
- if (state == NULL) {
- DEBUG(0, ("talloc failed\n"));
- cont(mem_ctx, False, NULL, c, private_data);
- return;
- }
-
- state->mem_ctx = mem_ctx;
- state->request = *request;
- state->request.length = sizeof(state->request);
- state->cont = cont;
- state->c = c;
- state->private_data = private_data;
-
- async_domain_request(mem_ctx, domain, &state->request,
- &state->response, do_async_recv, state);
-}
-
-struct lookupsid_state {
- DOM_SID sid;
- void *caller_private_data;
-};
-
-
-static void lookupsid_recv2(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const char *dom_name,
- const char *name, enum lsa_SidType type) =
- (void (*)(void *, bool, const char *, const char *,
- enum lsa_SidType))c;
- struct lookupsid_state *s = talloc_get_type_abort(private_data,
- struct lookupsid_state);
-
- if (!success) {
- DEBUG(5, ("Could not trigger lookupsid\n"));
- cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("lookupsid (forest root) returned an error\n"));
- cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- cont(s->caller_private_data, True, response->data.name.dom_name,
- response->data.name.name,
- (enum lsa_SidType)response->data.name.type);
-}
-
-static void lookupsid_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const char *dom_name,
- const char *name, enum lsa_SidType type) =
- (void (*)(void *, bool, const char *, const char *,
- enum lsa_SidType))c;
- struct lookupsid_state *s = talloc_get_type_abort(private_data,
- struct lookupsid_state);
-
- if (!success) {
- DEBUG(5, ("Could not trigger lookupsid\n"));
- cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- /* Try again using the forest root */
- struct winbindd_domain *root_domain = find_root_domain();
- struct winbindd_request request;
-
- if ( !root_domain ) {
- DEBUG(5,("lookupsid_recv: unable to determine forest root\n"));
- cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_LOOKUPSID;
- sid_to_fstring(request.data.sid, &s->sid);
-
- do_async_domain(mem_ctx, root_domain, &request, lookupsid_recv2,
- (void *)cont, s);
-
- return;
- }
-
- cont(s->caller_private_data, True, response->data.name.dom_name,
- response->data.name.name,
- (enum lsa_SidType)response->data.name.type);
-}
-
-void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success,
- const char *dom_name,
- const char *name,
- enum lsa_SidType type),
- void *private_data)
-{
- struct winbindd_domain *domain;
- struct winbindd_request request;
- struct lookupsid_state *s;
-
- domain = find_lookup_domain_from_sid(sid);
- if (domain == NULL) {
- DEBUG(5, ("Could not find domain for sid %s\n",
- sid_string_dbg(sid)));
- cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_LOOKUPSID;
- sid_to_fstring(request.data.sid, sid);
-
- if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupsid_state)) == NULL ) {
- DEBUG(0, ("winbindd_lookupsid_async: talloc failed\n"));
- cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- sid_copy( &s->sid, sid );
- s->caller_private_data = private_data;
-
- do_async_domain(mem_ctx, domain, &request, lookupsid_recv,
- (void *)cont, s);
-}
-
-enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- enum lsa_SidType type;
- DOM_SID sid;
- char *name;
- char *dom_name;
-
- /* Ensure null termination */
- state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
-
- DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
- state->request->data.sid));
-
- /* Lookup sid from PDC using lsa_lookup_sids() */
-
- if (!string_to_sid(&sid, state->request->data.sid)) {
- DEBUG(5, ("%s not a SID\n", state->request->data.sid));
- return WINBINDD_ERROR;
- }
-
- /* Lookup the sid */
-
- if (!winbindd_lookup_name_by_sid(state->mem_ctx, domain, &sid,
- &dom_name, &name, &type))
- {
- TALLOC_FREE(dom_name);
- TALLOC_FREE(name);
- return WINBINDD_ERROR;
- }
-
- fstrcpy(state->response->data.name.dom_name, dom_name);
- fstrcpy(state->response->data.name.name, name);
- state->response->data.name.type = type;
-
- TALLOC_FREE(dom_name);
- TALLOC_FREE(name);
- return WINBINDD_OK;
-}
-
-/********************************************************************
- This is the second callback after contacting the forest root
-********************************************************************/
-
-struct lookupname_state {
- char *dom_name;
- char *name;
- void *caller_private_data;
-};
-
-
-static void lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const DOM_SID *sid,
- enum lsa_SidType type) =
- (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
- DOM_SID sid;
- struct lookupname_state *s = talloc_get_type_abort( private_data,
- struct lookupname_state );
-
- if (!success) {
- DEBUG(5, ("Could not trigger lookup_name\n"));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("lookup_name returned an error\n"));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- if (!string_to_sid(&sid, response->data.sid.sid)) {
- DEBUG(0, ("Could not convert string %s to sid\n",
- response->data.sid.sid));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- cont(s->caller_private_data, True, &sid,
- (enum lsa_SidType)response->data.sid.type);
-}
-
-/********************************************************************
- This is the first callback after contacting our own domain
-********************************************************************/
-
-static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const DOM_SID *sid,
- enum lsa_SidType type) =
- (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
- DOM_SID sid;
- struct lookupname_state *s = talloc_get_type_abort( private_data,
- struct lookupname_state );
-
- if (!success) {
- DEBUG(5, ("lookupname_recv: lookup_name() failed!\n"));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- /* Try again using the forest root */
- struct winbindd_domain *root_domain = find_root_domain();
- struct winbindd_request request;
-
- if ( !root_domain ) {
- DEBUG(5,("lookupname_recv: unable to determine forest root\n"));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_LOOKUPNAME;
-
- fstrcpy( request.data.name.dom_name, s->dom_name );
- fstrcpy( request.data.name.name, s->name );
-
- do_async_domain(mem_ctx, root_domain, &request, lookupname_recv2,
- (void *)cont, s);
-
- return;
- }
-
- if (!string_to_sid(&sid, response->data.sid.sid)) {
- DEBUG(0, ("Could not convert string %s to sid\n",
- response->data.sid.sid));
- cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- cont(s->caller_private_data, True, &sid,
- (enum lsa_SidType)response->data.sid.type);
-}
-
-/********************************************************************
- The lookup name call first contacts a DC in its own domain
- and fallbacks to contact a DC if the forest in our domain doesn't
- know the name.
-********************************************************************/
-
-void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
- const char *dom_name, const char *name,
- void (*cont)(void *private_data, bool success,
- const DOM_SID *sid,
- enum lsa_SidType type),
- enum winbindd_cmd orig_cmd,
- void *private_data)
-{
- struct winbindd_request request;
- struct winbindd_domain *domain;
- struct lookupname_state *s;
-
- domain = find_lookup_domain_from_name(dom_name);
- if (domain == NULL) {
- DEBUG(5, ("Could not find domain for name '%s'\n", dom_name));
- cont(private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_LOOKUPNAME;
- request.original_cmd = orig_cmd;
- fstrcpy(request.data.name.dom_name, dom_name);
- fstrcpy(request.data.name.name, name);
-
- if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupname_state)) == NULL ) {
- DEBUG(0, ("winbindd_lookupname_async: talloc failed\n"));
- cont(private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- s->dom_name = talloc_strdup( s, dom_name );
- s->name = talloc_strdup( s, name );
- if (!s->dom_name || !s->name) {
- cont(private_data, False, NULL, SID_NAME_UNKNOWN);
- return;
- }
-
- s->caller_private_data = private_data;
-
- do_async_domain(mem_ctx, domain, &request, lookupname_recv,
- (void *)cont, s);
-}
-
-enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- enum lsa_SidType type;
- char *name_domain, *name_user;
- DOM_SID sid;
- char *p;
-
- /* Ensure null termination */
- state->request->data.name.dom_name[sizeof(state->request->data.name.dom_name)-1]='\0';
-
- /* Ensure null termination */
- state->request->data.name.name[sizeof(state->request->data.name.name)-1]='\0';
-
- /* cope with the name being a fully qualified name */
- p = strstr(state->request->data.name.name, lp_winbind_separator());
- if (p) {
- *p = 0;
- name_domain = state->request->data.name.name;
- name_user = p+1;
- } else {
- name_domain = state->request->data.name.dom_name;
- name_user = state->request->data.name.name;
- }
-
- DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
- name_domain, lp_winbind_separator(), name_user));
-
- /* Lookup name from DC using lsa_lookup_names() */
- if (!winbindd_lookup_sid_by_name(state->mem_ctx, state->request->original_cmd, domain, name_domain,
- name_user, &sid, &type)) {
- return WINBINDD_ERROR;
- }
-
- sid_to_fstring(state->response->data.sid.sid, &sid);
- state->response->data.sid.type = type;
-
- return WINBINDD_OK;
-}
-
bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
size_t num_sids, char **result, ssize_t *len)
{
@@ -514,127 +86,6 @@ bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
return True;
}
-static void getsidaliases_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ,
- DOM_SID *aliases, size_t num_aliases) =
- (void (*)(void *, bool, DOM_SID *, size_t))c;
- char *aliases_str;
- DOM_SID *sids = NULL;
- size_t num_sids = 0;
-
- if (!success) {
- DEBUG(5, ("Could not trigger getsidaliases\n"));
- cont(private_data, success, NULL, 0);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("getsidaliases returned an error\n"));
- cont(private_data, False, NULL, 0);
- return;
- }
-
- aliases_str = (char *)response->extra_data.data;
-
- if (aliases_str == NULL) {
- DEBUG(10, ("getsidaliases return 0 SIDs\n"));
- cont(private_data, True, NULL, 0);
- return;
- }
-
- if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
- DEBUG(0, ("Could not parse sids\n"));
- cont(private_data, False, NULL, 0);
- return;
- }
-
- cont(private_data, True, sids, num_sids);
-}
-
-void winbindd_getsidaliases_async(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- const DOM_SID *sids, size_t num_sids,
- void (*cont)(void *private_data,
- bool success,
- const DOM_SID *aliases,
- size_t num_aliases),
- void *private_data)
-{
- struct winbindd_request request;
- char *sidstr = NULL;
- ssize_t len;
-
- if (num_sids == 0) {
- cont(private_data, True, NULL, 0);
- return;
- }
-
- if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr, &len)) {
- cont(private_data, False, NULL, 0);
- return;
- }
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_GETSIDALIASES;
- request.extra_len = len;
- request.extra_data.data = sidstr;
-
- do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
- (void *)cont, private_data);
-}
-
-static void query_user_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const char *acct_name,
- const char *full_name, const char *homedir,
- const char *shell, uint32 gid, uint32 group_rid) =
- (void (*)(void *, bool, const char *, const char *,
- const char *, const char *, uint32, uint32))c;
-
- if (!success) {
- DEBUG(5, ("Could not trigger query_user\n"));
- cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("query_user returned an error\n"));
- cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
- return;
- }
-
- cont(private_data, True, response->data.user_info.acct_name,
- response->data.user_info.full_name,
- response->data.user_info.homedir,
- response->data.user_info.shell,
- response->data.user_info.primary_gid,
- response->data.user_info.group_rid);
-}
-
-void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
- const DOM_SID *sid,
- void (*cont)(void *private_data, bool success,
- const char *acct_name,
- const char *full_name,
- const char *homedir,
- const char *shell,
- gid_t gid,
- uint32 group_rid),
- void *private_data)
-{
- struct winbindd_request request;
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_USERINFO;
- sid_to_fstring(request.data.sid, sid);
- do_async_domain(mem_ctx, domain, &request, query_user_recv,
- (void *)cont, private_data);
-}
-
enum winbindd_result winbindd_dual_ping(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index c4bc936a5d..ddbd9d9d5b 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -514,7 +514,7 @@ static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
time_t t = time(NULL);
unsigned cache_time = lp_winbind_cache_time();
- if ( IS_DOMAIN_OFFLINE(domain) ) {
+ if (is_domain_offline(domain)) {
return;
}
@@ -2446,62 +2446,9 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
* Guenther */
static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ struct netr_DomainTrustList *trusts)
{
- struct winbind_cache *cache = get_cache(domain);
- struct cache_entry *centry = NULL;
NTSTATUS status;
- int i;
-
- if (!cache->tdb)
- goto do_query;
-
- centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
-
- if (!centry) {
- goto do_query;
- }
-
- *num_domains = centry_uint32(centry);
-
- if (*num_domains) {
- (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
- (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
- (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
-
- if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
- smb_panic_fn("trusted_domains out of memory");
- }
- } else {
- (*names) = NULL;
- (*alt_names) = NULL;
- (*dom_sids) = NULL;
- }
-
- for (i=0; i<(*num_domains); i++) {
- (*names)[i] = centry_string(centry, mem_ctx);
- (*alt_names)[i] = centry_string(centry, mem_ctx);
- if (!centry_sid(centry, &(*dom_sids)[i])) {
- sid_copy(&(*dom_sids)[i], &global_sid_NULL);
- }
- }
-
- status = centry->status;
-
- DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
- domain->name, *num_domains, nt_errstr(status) ));
-
- centry_free(centry);
- return status;
-
-do_query:
- (*num_domains) = 0;
- (*dom_sids) = NULL;
- (*names) = NULL;
- (*alt_names) = NULL;
/* Return status value returned by seq number check */
@@ -2511,8 +2458,7 @@ do_query:
DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
domain->name ));
- status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
- names, alt_names, dom_sids);
+ status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
/* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
* so that the generic centry handling still applies correctly -
@@ -2521,33 +2467,6 @@ do_query:
if (!NT_STATUS_IS_ERR(status)) {
status = NT_STATUS_OK;
}
-
-
-#if 0 /* Disabled as we want the trust dom list to be managed by
- the main parent and always to make the query. --jerry */
-
- /* and save it */
- refresh_sequence_number(domain, false);
-
- centry = centry_start(domain, status);
- if (!centry)
- goto skip_save;
-
- centry_put_uint32(centry, *num_domains);
-
- for (i=0; i<(*num_domains); i++) {
- centry_put_string(centry, (*names)[i]);
- centry_put_string(centry, (*alt_names)[i]);
- centry_put_sid(centry, &(*dom_sids)[i]);
- }
-
- centry_end(centry, "TRUSTDOMS/%s", domain->name);
-
- centry_free(centry);
-
-skip_save:
-#endif
-
return status;
}
@@ -3557,34 +3476,6 @@ static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
return 0;
}
-static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
- struct tdb_validation_status *state)
-{
- struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
- int32 num_domains, i;
-
- if (!centry) {
- return 1;
- }
-
- num_domains = centry_uint32(centry);
-
- for (i=0; i< num_domains; i++) {
- DOM_SID sid;
- (void)centry_string(centry, mem_ctx);
- (void)centry_string(centry, mem_ctx);
- (void)centry_sid(centry, &sid);
- }
-
- centry_free(centry);
-
- if (!(state->success)) {
- return 1;
- }
- DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
- return 0;
-}
-
static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
TDB_DATA dbuf,
struct tdb_validation_status *state)
@@ -3666,7 +3557,6 @@ struct key_val_struct {
{"DR/", validate_dr},
{"DE/", validate_de},
{"NSS/PWINFO/", validate_pwinfo},
- {"TRUSTDOMS/", validate_trustdoms},
{"TRUSTDOMCACHE/", validate_trustdomcache},
{"NSS/NA/", validate_nss_na},
{"NSS/AN/", validate_nss_an},
@@ -4361,6 +4251,7 @@ static bool wcache_opnum_cacheable(uint32_t opnum)
case NDR_WBINT_ALLOCATEGID:
case NDR_WBINT_CHECKMACHINEACCOUNT:
case NDR_WBINT_CHANGEMACHINEACCOUNT:
+ case NDR_WBINT_PINGDC:
return false;
}
return true;
@@ -4393,7 +4284,7 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
goto fail;
}
- if (IS_DOMAIN_ONLINE(domain)) {
+ if (!is_domain_offline(domain)) {
uint32_t entry_seqnum, dom_seqnum, last_check;
if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c
index 86017e2215..921110a0be 100644
--- a/source3/winbindd/winbindd_ccache_access.c
+++ b/source3/winbindd/winbindd_ccache_access.c
@@ -6,23 +6,24 @@
Copyright (C) Robert O'Callahan 2006
Copyright (C) Jeremy Allison 2006 (minor fixes to fit into Samba and
protect against integer wrap).
-
+
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 "winbindd.h"
+#include "ntlmssp.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -49,7 +50,7 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
DATA_BLOB *auth_msg)
{
NTSTATUS status;
- NTLMSSP_STATE *ntlmssp_state = NULL;
+ struct ntlmssp_state *ntlmssp_state = NULL;
DATA_BLOB dummy_msg, reply;
status = ntlmssp_client_start(&ntlmssp_state);
@@ -77,7 +78,7 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
}
status = ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
-
+
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Could not set hashes: %s\n",
nt_errstr(status)));
@@ -250,21 +251,15 @@ enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *doma
goto process_result;
}
- initial = data_blob(state->request->extra_data.data, initial_blob_len);
- challenge = data_blob(state->request->extra_data.data + initial_blob_len,
- state->request->data.ccache_ntlm_auth.challenge_blob_len);
-
- if (!initial.data || !challenge.data) {
- result = NT_STATUS_NO_MEMORY;
- } else {
- result = do_ntlm_auth_with_hashes(name_user, name_domain,
- entry->lm_hash, entry->nt_hash,
- initial, challenge, &auth);
- }
-
- data_blob_free(&initial);
- data_blob_free(&challenge);
+ initial = data_blob_const(state->request->extra_data.data,
+ initial_blob_len);
+ challenge = data_blob_const(
+ state->request->extra_data.data + initial_blob_len,
+ state->request->data.ccache_ntlm_auth.challenge_blob_len);
+ result = do_ntlm_auth_with_hashes(name_user, name_domain,
+ entry->lm_hash, entry->nt_hash,
+ initial, challenge, &auth);
if (!NT_STATUS_IS_OK(result)) {
goto process_result;
}
diff --git a/source3/winbindd/winbindd_check_machine_acct.c b/source3/winbindd/winbindd_check_machine_acct.c
index 610e9edfaa..33b6d9fba4 100644
--- a/source3/winbindd/winbindd_check_machine_acct.c
+++ b/source3/winbindd/winbindd_check_machine_acct.c
@@ -42,7 +42,7 @@ struct tevent_req *winbindd_check_machine_acct_send(TALLOC_CTX *mem_ctx,
return NULL;
}
- if (request->domain_name[0] == '0') {
+ if (request->domain_name[0] == '\0') {
/* preserve old behavior, when no domain name is given */
domain = find_our_domain();
} else {
diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c
index ad3d6d7916..45da57e132 100644
--- a/source3/winbindd/winbindd_domain.c
+++ b/source3/winbindd/winbindd_domain.c
@@ -31,14 +31,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
.struct_cmd = WINBINDD_PING,
.struct_fn = winbindd_dual_ping,
},{
- .name = "LOOKUPSID",
- .struct_cmd = WINBINDD_LOOKUPSID,
- .struct_fn = winbindd_dual_lookupsid,
- },{
- .name = "LOOKUPNAME",
- .struct_cmd = WINBINDD_LOOKUPNAME,
- .struct_fn = winbindd_dual_lookupname,
- },{
.name = "LIST_TRUSTDOM",
.struct_cmd = WINBINDD_LIST_TRUSTDOM,
.struct_fn = winbindd_dual_list_trusted_domains,
@@ -47,10 +39,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
.struct_cmd = WINBINDD_INIT_CONNECTION,
.struct_fn = winbindd_dual_init_connection,
},{
- .name = "GETDCNAME",
- .struct_cmd = WINBINDD_GETDCNAME,
- .struct_fn = winbindd_dual_getdcname,
- },{
.name = "SHOW_SEQUENCE",
.struct_cmd = WINBINDD_SHOW_SEQUENCE,
.struct_fn = winbindd_dual_show_sequence,
@@ -75,22 +63,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
.struct_cmd = WINBINDD_PAM_CHAUTHTOK,
.struct_fn = winbindd_dual_pam_chauthtok,
},{
- .name = "DUAL_USERINFO",
- .struct_cmd = WINBINDD_DUAL_USERINFO,
- .struct_fn = winbindd_dual_userinfo,
- },{
- .name = "GETUSERDOMGROUPS",
- .struct_cmd = WINBINDD_GETUSERDOMGROUPS,
- .struct_fn = winbindd_dual_getuserdomgroups,
- },{
- .name = "GETSIDALIASES",
- .struct_cmd = WINBINDD_DUAL_GETSIDALIASES,
- .struct_fn = winbindd_dual_getsidaliases,
- },{
- .name = "GETSIDALIASES",
- .struct_cmd = WINBINDD_GETSIDALIASES,
- .struct_fn = winbindd_dual_getsidaliases,
- },{
.name = "CCACHE_NTLM_AUTH",
.struct_cmd = WINBINDD_CCACHE_NTLMAUTH,
.struct_fn = winbindd_dual_ccache_ntlm_auth,
@@ -108,6 +80,4 @@ void setup_domain_child(struct winbindd_domain *domain,
{
setup_child(domain, child, domain_dispatch_table,
"log.wb", domain->name);
-
- child->domain = domain;
}
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 376d7c7309..74b2b99b7f 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -367,85 +367,6 @@ int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
return 0;
}
-/*
- * Machinery for async requests sent to children. You set up a
- * winbindd_request, select a child to query, and issue a async_request
- * call. When the request is completed, the callback function you specified is
- * called back with the private pointer you gave to async_request.
- */
-
-struct winbindd_async_request {
- struct winbindd_async_request *next, *prev;
- TALLOC_CTX *mem_ctx;
- struct winbindd_child *child;
- struct winbindd_response *response;
- void (*continuation)(void *private_data, bool success);
- struct timed_event *reply_timeout_event;
- pid_t child_pid; /* pid of the child we're waiting on. Used to detect
- a restart of the child (child->pid != child_pid). */
- void *private_data;
-};
-
-static void async_request_done(struct tevent_req *req);
-
-void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
- struct winbindd_request *request,
- struct winbindd_response *response,
- void (*continuation)(void *private_data, bool success),
- void *private_data)
-{
- struct winbindd_async_request *state;
- struct tevent_req *req;
-
- DEBUG(10, ("Sending request to child pid %d (domain=%s)\n",
- (int)child->pid,
- (child->domain != NULL) ? child->domain->name : "''"));
-
- state = talloc(mem_ctx, struct winbindd_async_request);
- if (state == NULL) {
- DEBUG(0, ("talloc failed\n"));
- continuation(private_data, False);
- return;
- }
-
- state->mem_ctx = mem_ctx;
- state->child = child;
- state->reply_timeout_event = NULL;
- state->response = response;
- state->continuation = continuation;
- state->private_data = private_data;
-
- request->pid = child->pid;
-
- req = wb_child_request_send(state, winbind_event_context(),
- child, request);
- if (req == NULL) {
- DEBUG(0, ("wb_child_request_send failed\n"));
- continuation(private_data, false);
- return;
- }
- tevent_req_set_callback(req, async_request_done, state);
-}
-
-static void async_request_done(struct tevent_req *req)
-{
- struct winbindd_async_request *state = tevent_req_callback_data(
- req, struct winbindd_async_request);
- struct winbindd_response *response;
- int ret, err;
-
- ret = wb_child_request_recv(req, state, &response, &err);
- TALLOC_FREE(req);
- if (ret == -1) {
- DEBUG(2, ("wb_child_request_recv failed: %s\n",
- strerror(err)));
- state->continuation(state->private_data, false);
- return;
- }
- *state->response = *response;
- state->continuation(state->private_data, true);
-}
-
struct domain_request_state {
struct winbindd_domain *domain;
struct winbindd_request *request;
@@ -527,13 +448,6 @@ static void recvfrom_child(void *private_data_data, bool success)
request_ok(state);
}
-void sendto_child(struct winbindd_cli_state *state,
- struct winbindd_child *child)
-{
- async_request(state->mem_ctx, child, state->request,
- state->response, recvfrom_child, state);
-}
-
void sendto_domain(struct winbindd_cli_state *state,
struct winbindd_domain *domain)
{
@@ -588,7 +502,7 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
"logname == NULL");
}
- child->domain = NULL;
+ child->domain = domain;
child->table = table;
child->queue = tevent_queue_create(NULL, "winbind_child");
SMB_ASSERT(child->queue != NULL);
@@ -696,7 +610,7 @@ void winbind_msg_offline(struct messaging_context *msg_ctx,
}
for (child = children; child != NULL; child = child->next) {
- /* Don't send message to internal childs. We've already
+ /* Don't send message to internal children. We've already
done so above. */
if (!child->domain || winbindd_internal_child(child)) {
continue;
@@ -830,7 +744,7 @@ void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
TALLOC_CTX *mem_ctx;
const char *message;
struct server_id *sender;
-
+
DEBUG(5,("winbind_msg_onlinestatus received.\n"));
if (!data->data) {
@@ -843,7 +757,7 @@ void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
if (mem_ctx == NULL) {
return;
}
-
+
message = collect_onlinestatus(mem_ctx);
if (message == NULL) {
talloc_destroy(mem_ctx);
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index cecbb61051..b247d5a233 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -510,6 +510,54 @@ again:
return status;
}
+NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r)
+{
+ NTSTATUS status;
+ struct winbindd_domain *domain;
+ struct rpc_pipe_client *netlogon_pipe;
+ union netr_CONTROL_QUERY_INFORMATION info;
+ WERROR werr;
+ fstring logon_server;
+
+ domain = wb_child_domain();
+ if (domain == NULL) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ status = cm_connect_netlogon(domain, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ return status;
+ }
+
+ fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
+
+ /*
+ * This provokes a WERR_NOT_SUPPORTED error message. This is
+ * documented in the wspp docs. I could not get a successful
+ * call to work, but the main point here is testing that the
+ * netlogon pipe works.
+ */
+ status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
+ logon_server, NETLOGON_CONTROL_QUERY,
+ 2, &info, &werr);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
+ invalidate_cm_connection(&domain->conn);
+ return status;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
+ DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
+ "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
+ return NT_STATUS_OK;
+}
NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r)
{
diff --git a/source3/winbindd/winbindd_getgrnam.c b/source3/winbindd/winbindd_getgrnam.c
index d888393399..3ca1aa6111 100644
--- a/source3/winbindd/winbindd_getgrnam.c
+++ b/source3/winbindd/winbindd_getgrnam.c
@@ -40,7 +40,6 @@ struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req, *subreq;
struct winbindd_getgrnam_state *state;
- struct winbindd_domain *domain;
char *tmp;
NTSTATUS nt_status;
@@ -77,27 +76,7 @@ struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx,
fstrcpy(state->name_domain, get_global_sam_name());
}
- /* Get info for the domain */
-
- domain = find_domain_from_name_noinit(state->name_domain);
- if (domain == NULL) {
- DEBUG(3, ("could not get domain sid for domain %s\n",
- state->name_domain));
- tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
- return tevent_req_post(req, ev);
- }
-
- /* should we deal with users for our domain? */
-
- if ( lp_winbind_trusted_domains_only() && domain->primary) {
- DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
- "getgrnam() for %s\\%s.\n", state->name_domain,
- state->name_group));
- tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
- return tevent_req_post(req, ev);
- }
-
- subreq = wb_lookupname_send(state, ev, domain->name, state->name_group,
+ subreq = wb_lookupname_send(state, ev, state->name_domain, state->name_group,
0);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c
index 3bdf762c45..736eba698a 100644
--- a/source3/winbindd/winbindd_getgroups.c
+++ b/source3/winbindd/winbindd_getgroups.c
@@ -45,7 +45,6 @@ struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
struct tevent_req *req, *subreq;
struct winbindd_getgroups_state *state;
char *domuser, *mapped_user;
- struct winbindd_domain *domain;
NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
@@ -76,29 +75,6 @@ struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- domain = find_domain_from_name_noinit(state->domname);
- if (domain == NULL) {
- /* Retry with DNS name */
- char *p = strchr(domuser, '@');
- if (p != NULL) {
- domain = find_domain_from_name_noinit(p+1);
- }
- }
- if (domain == NULL) {
- DEBUG(7, ("could not find domain entry for domain %s\n",
- state->domname));
- tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
- return tevent_req_post(req, ev);
- }
-
- if (lp_winbind_trusted_domains_only() && domain->primary) {
- DEBUG(7,("winbindd_getgroups: My domain -- "
- "rejecting getgroups() for %s\\%s.\n",
- state->domname, state->username));
- tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
- return tevent_req_post(req, ev);
- }
-
subreq = wb_lookupname_send(state, ev, state->domname, state->username,
LOOKUP_NAME_NO_NSS);
if (tevent_req_nomem(subreq, req)) {
diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c
index eab5c26df4..a985fa254f 100644
--- a/source3/winbindd/winbindd_group.c
+++ b/source3/winbindd/winbindd_group.c
@@ -66,290 +66,6 @@ bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
return True;
}
-/* Get the list of domain groups and domain aliases for a domain. We fill in
- the sam_entries and num_sam_entries fields with domain group information.
- Return True if some groups were returned, False otherwise. */
-
-bool get_sam_group_entries(struct getent_state *ent)
-{
- NTSTATUS status;
- uint32 num_entries;
- struct acct_info *name_list = NULL;
- TALLOC_CTX *mem_ctx;
- bool result = False;
- struct acct_info *sam_grp_entries = NULL;
- struct winbindd_domain *domain;
-
- if (ent->got_sam_entries)
- return False;
-
- if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
- ent->domain_name))) {
- DEBUG(1, ("get_sam_group_entries: "
- "could not create talloc context!\n"));
- return False;
- }
-
- /* Free any existing group info */
-
- SAFE_FREE(ent->sam_entries);
- ent->num_sam_entries = 0;
- ent->got_sam_entries = True;
-
- /* Enumerate domain groups */
-
- num_entries = 0;
-
- if (!(domain = find_domain_from_name(ent->domain_name))) {
- DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
- ent->domain_name));
- goto done;
- }
-
- /* always get the domain global groups */
-
- status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
- &sam_grp_entries);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("get_sam_group_entries: "
- "could not enumerate domain groups! Error: %s\n",
- nt_errstr(status)));
- result = False;
- goto done;
- }
-
- /* Copy entries into return buffer */
-
- if (num_entries) {
- name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
- if (!name_list) {
- DEBUG(0,("get_sam_group_entries: Failed to malloc "
- "memory for %d domain groups!\n",
- num_entries));
- result = False;
- goto done;
- }
- memcpy(name_list, sam_grp_entries,
- num_entries * sizeof(struct acct_info));
- }
-
- ent->num_sam_entries = num_entries;
-
- /* get the domain local groups if we are a member of a native win2k
- * domain and are not using LDAP to get the groups */
-
- if ( ( lp_security() != SEC_ADS && domain->native_mode
- && domain->primary) || domain->internal )
- {
- DEBUG(4,("get_sam_group_entries: %s domain; "
- "enumerating local groups as well\n",
- domain->native_mode ? "Native Mode 2k":
- "BUILTIN or local"));
-
- status = domain->methods->enum_local_groups(domain, mem_ctx,
- &num_entries,
- &sam_grp_entries);
-
- if ( !NT_STATUS_IS_OK(status) ) {
- DEBUG(3,("get_sam_group_entries: "
- "Failed to enumerate "
- "domain local groups with error %s!\n",
- nt_errstr(status)));
- num_entries = 0;
- }
- else
- DEBUG(4,("get_sam_group_entries: "
- "Returned %d local groups\n",
- num_entries));
-
- /* Copy entries into return buffer */
-
- if ( num_entries ) {
- name_list = SMB_REALLOC_ARRAY(name_list,
- struct acct_info,
- ent->num_sam_entries+
- num_entries);
- if (!name_list) {
- DEBUG(0,("get_sam_group_entries: "
- "Failed to realloc more memory "
- "for %d local groups!\n",
- num_entries));
- result = False;
- goto done;
- }
-
- memcpy(&name_list[ent->num_sam_entries],
- sam_grp_entries,
- num_entries * sizeof(struct acct_info));
- }
-
- ent->num_sam_entries += num_entries;
- }
-
-
- /* Fill in remaining fields */
-
- ent->sam_entries = name_list;
- ent->sam_entry_index = 0;
-
- result = (ent->num_sam_entries > 0);
-
- done:
- talloc_destroy(mem_ctx);
-
- return result;
-}
-
-/* Get user supplementary groups. This is much quicker than trying to
- invert the groups database. We merge the groups from the gids and
- other_sids info3 fields as trusted domain, universal group
- memberships, and nested groups (win2k native mode only) are not
- returned by the getgroups RPC call but are present in the info3. */
-
-struct getgroups_state {
- struct winbindd_cli_state *state;
- struct winbindd_domain *domain;
- char *domname;
- char *username;
- DOM_SID user_sid;
-
- const DOM_SID *token_sids;
- size_t i, num_token_sids;
-
- gid_t *token_gids;
- size_t num_token_gids;
-};
-
-enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID user_sid;
- NTSTATUS status;
-
- char *sidstring;
- ssize_t len;
- DOM_SID *groups;
- uint32 num_groups;
-
- /* Ensure null termination */
- state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
-
- if (!string_to_sid(&user_sid, state->request->data.sid)) {
- DEBUG(1, ("Could not get convert sid %s from string\n",
- state->request->data.sid));
- return WINBINDD_ERROR;
- }
-
- status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
- &user_sid, &num_groups,
- &groups);
- if (!NT_STATUS_IS_OK(status))
- return WINBINDD_ERROR;
-
- if (num_groups == 0) {
- state->response->data.num_entries = 0;
- state->response->extra_data.data = NULL;
- return WINBINDD_OK;
- }
-
- if (!print_sidlist(state->mem_ctx,
- groups, num_groups,
- &sidstring, &len)) {
- DEBUG(0, ("talloc failed\n"));
- return WINBINDD_ERROR;
- }
-
- state->response->extra_data.data = sidstring;
- state->response->length += len+1;
- state->response->data.num_entries = num_groups;
-
- return WINBINDD_OK;
-}
-
-enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID *sids = NULL;
- size_t num_sids = 0;
- char *sidstr = NULL;
- ssize_t len;
- size_t i;
- uint32 num_aliases;
- uint32 *alias_rids;
- NTSTATUS result;
-
- DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
-
- sidstr = state->request->extra_data.data;
- if (sidstr == NULL) {
- sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
- if (!sidstr) {
- DEBUG(0, ("Out of memory\n"));
- return WINBINDD_ERROR;
- }
- }
-
- DEBUG(10, ("Sidlist: %s\n", sidstr));
-
- if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
- DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
- return WINBINDD_ERROR;
- }
-
- num_aliases = 0;
- alias_rids = NULL;
-
- result = domain->methods->lookup_useraliases(domain,
- state->mem_ctx,
- num_sids, sids,
- &num_aliases,
- &alias_rids);
-
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(3, ("Could not lookup_useraliases: %s\n",
- nt_errstr(result)));
- return WINBINDD_ERROR;
- }
-
- num_sids = 0;
- sids = NULL;
- sidstr = NULL;
-
- DEBUG(10, ("Got %d aliases\n", num_aliases));
-
- for (i=0; i<num_aliases; i++) {
- DOM_SID sid;
- DEBUGADD(10, (" rid %d\n", alias_rids[i]));
- sid_copy(&sid, &domain->sid);
- sid_append_rid(&sid, alias_rids[i]);
- result = add_sid_to_array(state->mem_ctx, &sid, &sids,
- &num_sids);
- if (!NT_STATUS_IS_OK(result)) {
- return WINBINDD_ERROR;
- }
- }
-
-
- if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
- DEBUG(0, ("Could not print_sidlist\n"));
- state->response->extra_data.data = NULL;
- return WINBINDD_ERROR;
- }
-
- state->response->extra_data.data = NULL;
-
- if (sidstr) {
- state->response->extra_data.data = sidstr;
- DEBUG(10, ("aliases_list: %s\n",
- (char *)state->response->extra_data.data));
- state->response->length += len+1;
- state->response->data.num_entries = num_sids;
- }
-
- return WINBINDD_OK;
-}
-
struct getgr_countmem {
int num;
size_t len;
diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c
index 1d275014ce..028026087d 100644
--- a/source3/winbindd/winbindd_idmap.c
+++ b/source3/winbindd/winbindd_idmap.c
@@ -7,17 +7,6 @@
Copyright (C) Gerald Carter 2006
Copyright (C) Simo Sorce 2007
- The helpers always consist of three functions:
-
- * A request setup function that takes the necessary parameters together
- with a continuation function that is to be called upon completion
-
- * A private continuation function that is internal only. This is to be
- called by the lower-level functions in do_async(). Its only task is to
- properly call the continuation function named above.
-
- * A worker function that is called inside the appropriate child process.
-
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
@@ -45,322 +34,12 @@ struct winbindd_child *idmap_child(void)
return &static_idmap_child;
}
-static void winbindd_sid2uid_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, uid_t uid) =
- (void (*)(void *, bool, uid_t))c;
-
- if (!success) {
- DEBUG(5, ("Could not trigger sid2uid\n"));
- cont(private_data, False, 0);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("sid2uid returned an error\n"));
- cont(private_data, False, 0);
- return;
- }
-
- cont(private_data, True, response->data.uid);
-}
-
-void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success, uid_t uid),
- void *private_data)
-{
- struct winbindd_request request;
- struct winbindd_domain *domain;
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_SID2UID;
-
- domain = find_domain_from_sid(sid);
-
- if (domain != NULL) {
- DEBUG(10, ("winbindd_sid2uid_async found domain %s, "
- "have_idmap_config = %d\n", domain->name,
- (int)domain->have_idmap_config));
-
- }
- else {
- DEBUG(10, ("winbindd_sid2uid_async did not find a domain for "
- "%s\n", sid_string_dbg(sid)));
- }
-
- if ((domain != NULL) && (domain->have_idmap_config)) {
- fstrcpy(request.domain_name, domain->name);
- }
-
- sid_to_fstring(request.data.dual_sid2id.sid, sid);
- do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv,
- (void *)cont, private_data);
-}
-
-enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID sid;
- NTSTATUS result;
-
- DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
- state->request->data.dual_sid2id.sid));
-
- if (!string_to_sid(&sid, state->request->data.dual_sid2id.sid)) {
- DEBUG(1, ("Could not get convert sid %s from string\n",
- state->request->data.dual_sid2id.sid));
- return WINBINDD_ERROR;
- }
-
- result = idmap_sid_to_uid(state->request->domain_name, &sid,
- &state->response->data.uid);
-
- DEBUG(10, ("winbindd_dual_sid2uid: 0x%08x - %s - %u\n",
- NT_STATUS_V(result), sid_string_dbg(&sid),
- (unsigned int)state->response->data.uid));
-
- return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
-}
-
-static void winbindd_sid2gid_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, gid_t gid) =
- (void (*)(void *, bool, gid_t))c;
-
- if (!success) {
- DEBUG(5, ("Could not trigger sid2gid\n"));
- cont(private_data, False, 0);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("sid2gid returned an error\n"));
- cont(private_data, False, 0);
- return;
- }
-
- cont(private_data, True, response->data.gid);
-}
-
-void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success, gid_t gid),
- void *private_data)
-{
- struct winbindd_request request;
- struct winbindd_domain *domain;
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_SID2GID;
-
- domain = find_domain_from_sid(sid);
- if ((domain != NULL) && (domain->have_idmap_config)) {
- fstrcpy(request.domain_name, domain->name);
- }
-
- sid_to_fstring(request.data.dual_sid2id.sid, sid);
-
- DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n",
- request.data.dual_sid2id.sid));
-
- do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
- (void *)cont, private_data);
-}
-
-enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID sid;
- NTSTATUS result;
-
- DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
- state->request->data.dual_sid2id.sid));
-
- if (!string_to_sid(&sid, state->request->data.dual_sid2id.sid)) {
- DEBUG(1, ("Could not get convert sid %s from string\n",
- state->request->data.dual_sid2id.sid));
- return WINBINDD_ERROR;
- }
-
- /* Find gid for this sid and return it, possibly ask the slow remote idmap */
-
- result = idmap_sid_to_gid(state->request->domain_name, &sid,
- &state->response->data.gid);
-
- DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n",
- NT_STATUS_V(result), sid_string_dbg(&sid),
- (unsigned int)state->response->data.gid));
-
- return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
-}
-
-/* The following uid2sid/gid2sid functions has been contributed by
- * Keith Reynolds <Keith.Reynolds@centrify.com> */
-
-static void winbindd_uid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const char *sid) =
- (void (*)(void *, bool, const char *))c;
-
- if (!success) {
- DEBUG(5, ("Could not trigger uid2sid\n"));
- cont(private_data, False, NULL);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("uid2sid returned an error\n"));
- cont(private_data, False, NULL);
- return;
- }
-
- cont(private_data, True, response->data.sid.sid);
-}
-
-void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
- void (*cont)(void *private_data, bool success, const char *sid),
- void *private_data)
-{
- struct winbindd_domain *domain;
- struct winbindd_request request;
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_UID2SID;
- request.data.uid = uid;
-
- for (domain = domain_list(); domain != NULL; domain = domain->next) {
- if (domain->have_idmap_config
- && (uid >= domain->id_range_low)
- && (uid <= domain->id_range_high)) {
- fstrcpy(request.domain_name, domain->name);
- }
- }
-
- do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv,
- (void *)cont, private_data);
-}
-
-enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID sid;
- NTSTATUS result;
-
- DEBUG(3,("[%5lu]: uid to sid %lu\n",
- (unsigned long)state->pid,
- (unsigned long) state->request->data.uid));
-
- /* Find sid for this uid and return it, possibly ask the slow remote idmap */
- result = idmap_uid_to_sid(state->request->domain_name, &sid,
- state->request->data.uid);
-
- if (NT_STATUS_IS_OK(result)) {
- sid_to_fstring(state->response->data.sid.sid, &sid);
- state->response->data.sid.type = SID_NAME_USER;
- return WINBINDD_OK;
- }
-
- return WINBINDD_ERROR;
-}
-
-static void winbindd_gid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data)
-{
- void (*cont)(void *priv, bool succ, const char *sid) =
- (void (*)(void *, bool, const char *))c;
-
- if (!success) {
- DEBUG(5, ("Could not trigger gid2sid\n"));
- cont(private_data, False, NULL);
- return;
- }
-
- if (response->result != WINBINDD_OK) {
- DEBUG(5, ("gid2sid returned an error\n"));
- cont(private_data, False, NULL);
- return;
- }
-
- cont(private_data, True, response->data.sid.sid);
-}
-
-void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
- void (*cont)(void *private_data, bool success, const char *sid),
- void *private_data)
-{
- struct winbindd_domain *domain;
- struct winbindd_request request;
-
- ZERO_STRUCT(request);
- request.cmd = WINBINDD_DUAL_GID2SID;
- request.data.gid = gid;
-
- for (domain = domain_list(); domain != NULL; domain = domain->next) {
- if (domain->have_idmap_config
- && (gid >= domain->id_range_low)
- && (gid <= domain->id_range_high)) {
- fstrcpy(request.domain_name, domain->name);
- }
- }
-
- do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv,
- (void *)cont, private_data);
-}
-
-enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID sid;
- NTSTATUS result;
-
- DEBUG(3,("[%5lu]: gid %lu to sid\n",
- (unsigned long)state->pid,
- (unsigned long) state->request->data.gid));
-
- /* Find sid for this gid and return it, possibly ask the slow remote idmap */
- result = idmap_gid_to_sid(state->request->domain_name, &sid,
- state->request->data.gid);
-
- if (NT_STATUS_IS_OK(result)) {
- sid_to_fstring(state->response->data.sid.sid, &sid);
- DEBUG(10, ("[%5lu]: retrieved sid: %s\n",
- (unsigned long)state->pid,
- state->response->data.sid.sid));
- state->response->data.sid.type = SID_NAME_DOM_GRP;
- return WINBINDD_OK;
- }
-
- return WINBINDD_ERROR;
-}
-
static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = {
{
.name = "PING",
.struct_cmd = WINBINDD_PING,
.struct_fn = winbindd_dual_ping,
},{
- .name = "DUAL_SID2UID",
- .struct_cmd = WINBINDD_DUAL_SID2UID,
- .struct_fn = winbindd_dual_sid2uid,
- },{
- .name = "DUAL_SID2GID",
- .struct_cmd = WINBINDD_DUAL_SID2GID,
- .struct_fn = winbindd_dual_sid2gid,
- },{
- .name = "DUAL_UID2SID",
- .struct_cmd = WINBINDD_DUAL_UID2SID,
- .struct_fn = winbindd_dual_uid2sid,
- },{
- .name = "DUAL_GID2SID",
- .struct_cmd = WINBINDD_DUAL_GID2SID,
- .struct_fn = winbindd_dual_gid2sid,
- },{
.name = "NDRCMD",
.struct_cmd = WINBINDD_DUAL_NDRCMD,
.struct_fn = winbindd_dual_ndrcmd,
diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index 3ebd9ffdbd..ac8f1a7dfd 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -5,17 +5,17 @@
Copyright (C) Tim Potter 2000
Copyright (C) Andrew Bartlett 2002
-
+
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/>.
*/
@@ -93,7 +93,7 @@ void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
int extra_data_len = 0;
char *extra_data = NULL;
int i = 0;
-
+
DEBUG(3, ("[%5lu]: list trusted domains\n",
(unsigned long)state->pid));
@@ -102,6 +102,12 @@ void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
goto done;
}
+ extra_data = talloc_strdup(state->mem_ctx, "");
+ if (extra_data == NULL) {
+ request_error(state);
+ goto done;
+ }
+
for ( i = 0; i < num_domains; i++ ) {
struct winbindd_domain *domain;
bool is_online = true;
@@ -111,41 +117,27 @@ void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
if (domain) {
is_online = domain->online;
}
-
- if ( !extra_data ) {
- extra_data = talloc_asprintf(state->mem_ctx,
- "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
- d->domain_name,
- d->dns_name ? d->dns_name : d->domain_name,
- sid_string_talloc(state->mem_ctx, &d->sid),
- get_trust_type_string(d),
- trust_is_transitive(d) ? "Yes" : "No",
- trust_is_inbound(d) ? "Yes" : "No",
- trust_is_outbound(d) ? "Yes" : "No",
- is_online ? "Online" : "Offline" );
- } else {
- extra_data = talloc_asprintf(state->mem_ctx,
- "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
- extra_data,
- d->domain_name,
- d->dns_name ? d->dns_name : d->domain_name,
- sid_string_talloc(state->mem_ctx, &d->sid),
- get_trust_type_string(d),
- trust_is_transitive(d) ? "Yes" : "No",
- trust_is_inbound(d) ? "Yes" : "No",
- trust_is_outbound(d) ? "Yes" : "No",
- is_online ? "Online" : "Offline" );
- }
- }
-
- extra_data_len = 0;
- if (extra_data != NULL) {
- extra_data_len = strlen(extra_data);
+ extra_data = talloc_asprintf_append_buffer(
+ extra_data,
+ "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s\n",
+ d->domain_name,
+ d->dns_name ? d->dns_name : d->domain_name,
+ sid_string_talloc(state->mem_ctx, &d->sid),
+ get_trust_type_string(d),
+ trust_is_transitive(d) ? "Yes" : "No",
+ trust_is_inbound(d) ? "Yes" : "No",
+ trust_is_outbound(d) ? "Yes" : "No",
+ is_online ? "Online" : "Offline" );
}
+ extra_data_len = strlen(extra_data);
if (extra_data_len > 0) {
+
+ /* Strip the last \n */
+ extra_data[extra_data_len-1] = '\0';
+
state->response->extra_data.data = extra_data;
- state->response->length += extra_data_len+1;
+ state->response->length += extra_data_len;
}
request_ok(state);
@@ -156,20 +148,18 @@ done:
enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
- uint32 i, num_domains;
- char **names, **alt_names;
- DOM_SID *sids;
+ int i;
int extra_data_len = 0;
char *extra_data;
NTSTATUS result;
bool have_own_domain = False;
+ struct netr_DomainTrustList trusts;
DEBUG(3, ("[%5lu]: list trusted domains\n",
(unsigned long)state->pid));
result = domain->methods->trusted_domains(domain, state->mem_ctx,
- &num_domains, &names,
- &alt_names, &sids);
+ &trusts);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
@@ -179,45 +169,37 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
extra_data = talloc_strdup(state->mem_ctx, "");
- if (num_domains > 0)
- extra_data = talloc_asprintf(
- state->mem_ctx, "%s\\%s\\%s",
- names[0], alt_names[0] ? alt_names[0] : names[0],
- sid_string_talloc(state->mem_ctx, &sids[0]));
-
- for (i=1; i<num_domains; i++)
- extra_data = talloc_asprintf(
- state->mem_ctx, "%s\n%s\\%s\\%s",
- extra_data, names[i],
- alt_names[i] ? alt_names[i] : names[i],
- sid_string_talloc(state->mem_ctx, &sids[i]));
+ for (i=0; i<trusts.count; i++) {
+ extra_data = talloc_asprintf_append_buffer(
+ extra_data, "%s\\%s\\%s\n",
+ trusts.array[i].netbios_name,
+ trusts.array[i].dns_name,
+ sid_string_talloc(state->mem_ctx,
+ trusts.array[i].sid));
+ }
/* add our primary domain */
-
- for (i=0; i<num_domains; i++) {
- if (strequal(names[i], domain->name)) {
+
+ for (i=0; i<trusts.count; i++) {
+ if (strequal(trusts.array[i].netbios_name, domain->name)) {
have_own_domain = True;
break;
}
}
if (state->request->data.list_all_domains && !have_own_domain) {
- extra_data = talloc_asprintf(
- state->mem_ctx, "%s\n%s\\%s\\%s",
- extra_data, domain->name,
+ extra_data = talloc_asprintf_append_buffer(
+ extra_data, "%s\\%s\\%s\n", domain->name,
domain->alt_name ? domain->alt_name : domain->name,
sid_string_talloc(state->mem_ctx, &domain->sid));
}
- /* This is a bit excessive, but the extra data sooner or later will be
- talloc'ed */
+ extra_data_len = strlen(extra_data);
+ if (extra_data_len > 0) {
- extra_data_len = 0;
- if (extra_data != NULL) {
- extra_data_len = strlen(extra_data);
- }
+ /* Strip the last \n */
+ extra_data[extra_data_len-1] = '\0';
- if (extra_data_len > 0) {
state->response->extra_data.data = extra_data;
state->response->length += extra_data_len+1;
}
@@ -225,78 +207,6 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
return WINBINDD_OK;
}
-enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- const char *dcname_slash = NULL;
- const char *p;
- struct rpc_pipe_client *netlogon_pipe;
- NTSTATUS result;
- WERROR werr;
- unsigned int orig_timeout;
- struct winbindd_domain *req_domain;
-
- state->request->domain_name
- [sizeof(state->request->domain_name)-1] = '\0';
-
- DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
- state->request->domain_name));
-
- result = cm_connect_netlogon(domain, &netlogon_pipe);
-
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
- return WINBINDD_ERROR;
- }
-
- /* This call can take a long time - allow the server to time out.
- 35 seconds should do it. */
-
- orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
-
- req_domain = find_domain_from_name_noinit(state->request->domain_name);
- if (req_domain == domain) {
- result = rpccli_netr_GetDcName(netlogon_pipe,
- state->mem_ctx,
- domain->dcname,
- state->request->domain_name,
- &dcname_slash,
- &werr);
- } else {
- result = rpccli_netr_GetAnyDCName(netlogon_pipe,
- state->mem_ctx,
- domain->dcname,
- state->request->domain_name,
- &dcname_slash,
- &werr);
- }
- /* And restore our original timeout. */
- rpccli_set_timeout(netlogon_pipe, orig_timeout);
-
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(5,("Error requesting DCname for domain %s: %s\n",
- state->request->domain_name, nt_errstr(result)));
- return WINBINDD_ERROR;
- }
-
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
- state->request->domain_name, win_errstr(werr)));
- return WINBINDD_ERROR;
- }
-
- p = dcname_slash;
- if (*p == '\\') {
- p+=1;
- }
- if (*p == '\\') {
- p+=1;
- }
-
- fstrcpy(state->response->data.dc_name, p);
- return WINBINDD_OK;
-}
-
/* This is the child-only version of --sequence. It only allows for a single
* domain (ie "our" one) to be displayed. */
@@ -440,7 +350,7 @@ void winbindd_interface_version(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5lu]: request interface version\n",
(unsigned long)state->pid));
-
+
state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
request_ok(state);
}
@@ -450,7 +360,7 @@ void winbindd_interface_version(struct winbindd_cli_state *state)
void winbindd_domain_name(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
-
+
fstrcpy(state->response->data.domain_name, lp_workgroup());
request_ok(state);
}
@@ -461,7 +371,7 @@ void winbindd_netbios_name(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5lu]: request netbios name\n",
(unsigned long)state->pid));
-
+
fstrcpy(state->response->data.netbios_name, global_myname());
request_ok(state);
}
@@ -473,7 +383,7 @@ void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
char *priv_dir;
DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
(unsigned long)state->pid));
-
+
priv_dir = get_winbind_priv_pipe_dir();
state->response->extra_data.data = talloc_move(state->mem_ctx,
&priv_dir);
diff --git a/source3/winbindd/winbindd_passdb.c b/source3/winbindd/winbindd_passdb.c
index c23f87dcd5..34b5990a3f 100644
--- a/source3/winbindd/winbindd_passdb.c
+++ b/source3/winbindd/winbindd_passdb.c
@@ -398,16 +398,10 @@ static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
/* get a list of trusted domains - builtin domain */
static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ TALLOC_CTX *mem_ctx,
+ struct netr_DomainTrustList *trusts)
{
- *num_domains = 0;
- *names = NULL;
- *alt_names = NULL;
- *dom_sids = NULL;
+ ZERO_STRUCTP(trusts);
return NT_STATUS_OK;
}
@@ -649,58 +643,44 @@ static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
/* get a list of trusted domains */
static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ TALLOC_CTX *mem_ctx,
+ struct netr_DomainTrustList *trusts)
{
NTSTATUS nt_status;
struct trustdom_info **domains;
int i;
- TALLOC_CTX *tmp_ctx;
-
- *num_domains = 0;
- *names = NULL;
- *alt_names = NULL;
- *dom_sids = NULL;
-
- if (!(tmp_ctx = talloc_init("trusted_domains"))) {
- return NT_STATUS_NO_MEMORY;
- }
- nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
+ nt_status = pdb_enum_trusteddoms(talloc_tos(), &trusts->count,
+ &domains);
if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(tmp_ctx);
return nt_status;
}
- if (*num_domains) {
- *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
- *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
- *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
+ if (trusts->count == 0) {
+ trusts->array = NULL;
+ return NT_STATUS_OK;
+ }
- if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
- TALLOC_FREE(tmp_ctx);
- return NT_STATUS_NO_MEMORY;
- }
- } else {
- *names = NULL;
- *alt_names = NULL;
- *dom_sids = NULL;
+ trusts->array = talloc_zero_array(
+ mem_ctx, struct netr_DomainTrust, trusts->count);
+ if (trusts->array == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- for (i=0; i<*num_domains; i++) {
- (*alt_names)[i] = NULL;
- if (!((*names)[i] = talloc_strdup((*names),
- domains[i]->name))) {
- TALLOC_FREE(tmp_ctx);
+ for (i=0; i<trusts->count; i++) {
+ struct dom_sid *sid;
+
+ trusts->array[i].netbios_name = talloc_move(
+ trusts->array, &domains[i]->name);
+ trusts->array[i].dns_name = NULL;
+
+ sid = talloc(trusts->array, struct dom_sid);
+ if (sid == NULL) {
return NT_STATUS_NO_MEMORY;
}
- sid_copy(&(*dom_sids)[i], &domains[i]->sid);
+ sid_copy(sid, &domains[i]->sid);
+ trusts->array[i].sid = sid;
}
-
- TALLOC_FREE(tmp_ctx);
return NT_STATUS_OK;
}
diff --git a/source3/winbindd/winbindd_ping_dc.c b/source3/winbindd/winbindd_ping_dc.c
new file mode 100644
index 0000000000..e06e5896c2
--- /dev/null
+++ b/source3/winbindd/winbindd_ping_dc.c
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/CIFS implementation.
+ async implementation of WINBINDD_PING_DC
+ Copyright (C) Volker Lendecke 2009
+
+ 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 "winbindd.h"
+#include "librpc/gen_ndr/cli_wbint.h"
+
+struct winbindd_ping_dc_state {
+ uint8_t dummy;
+};
+
+static void winbindd_ping_dc_done(struct tevent_req *subreq);
+
+struct tevent_req *winbindd_ping_dc_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct winbindd_cli_state *cli,
+ struct winbindd_request *request)
+{
+ struct tevent_req *req, *subreq;
+ struct winbindd_ping_dc_state *state;
+ struct winbindd_domain *domain;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct winbindd_ping_dc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (request->domain_name[0] == '\0') {
+ /* preserve old behavior, when no domain name is given */
+ domain = find_our_domain();
+ } else {
+ domain = find_domain_from_name(request->domain_name);
+ }
+ if (domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
+ return tevent_req_post(req, ev);
+ }
+ if (domain->internal) {
+ /*
+ * Internal domains are passdb based, we can always
+ * contact them.
+ */
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = rpccli_wbint_PingDc_send(state, ev, domain->child.rpccli);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, winbindd_ping_dc_done, req);
+ return req;
+}
+
+static void winbindd_ping_dc_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winbindd_ping_dc_state *state = tevent_req_data(
+ req, struct winbindd_ping_dc_state);
+ NTSTATUS status, result;
+
+ status = rpccli_wbint_PingDc_recv(subreq, state, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (!NT_STATUS_IS_OK(result)) {
+ tevent_req_nterror(req, result);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS winbindd_ping_dc_recv(struct tevent_req *req,
+ struct winbindd_response *presp)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 6e232c9db8..93d5748c49 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -82,62 +82,10 @@ NTSTATUS winbindd_lookup_names(TALLOC_CTX *mem_ctx,
/* The following definitions come from winbindd/winbindd_async.c */
-void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
- const struct winbindd_request *request,
- void (*cont)(TALLOC_CTX *mem_ctx, bool success,
- struct winbindd_response *response,
- void *c, void *private_data),
- void *c, void *private_data);
-void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success,
- const char *dom_name,
- const char *name,
- enum lsa_SidType type),
- void *private_data);
-enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
- const char *dom_name, const char *name,
- void (*cont)(void *private_data, bool success,
- const DOM_SID *sid,
- enum lsa_SidType type),
- enum winbindd_cmd orig_cmd,
- void *private_data);
-enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_listent_async(TALLOC_CTX *mem_ctx,
- struct winbindd_domain *domain,
- void (*cont)(void *private_data, bool success,
- fstring dom_name, char* extra_data),
- void *private_data, enum ent_type type);
-enum winbindd_result winbindd_dual_list_users(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
size_t num_sids, char **result, ssize_t *len);
bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
DOM_SID **sids, size_t *num_sids);
-void winbindd_getsidaliases_async(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- const DOM_SID *sids, size_t num_sids,
- void (*cont)(void *private_data,
- bool success,
- const DOM_SID *aliases,
- size_t num_aliases),
- void *private_data);
-enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
- const DOM_SID *sid,
- void (*cont)(void *private_data, bool success,
- const char *acct_name,
- const char *full_name,
- const char *homedir,
- const char *shell,
- gid_t gid,
- uint32 group_rid),
- void *private_data);
/* The following definitions come from winbindd/winbindd_cache.c */
@@ -328,19 +276,12 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
struct winbindd_response **presponse, int *err);
-void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
- struct winbindd_request *request,
- struct winbindd_response *response,
- void (*continuation)(void *private_data, bool success),
- void *private_data);
void async_domain_request(TALLOC_CTX *mem_ctx,
struct winbindd_domain *domain,
struct winbindd_request *request,
struct winbindd_response *response,
void (*continuation)(void *private_data_data, bool success),
void *private_data_data);
-void sendto_child(struct winbindd_cli_state *state,
- struct winbindd_child *child);
void sendto_domain(struct winbindd_cli_state *state,
struct winbindd_domain *domain);
void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
@@ -394,9 +335,6 @@ void winbindd_getgroups(struct winbindd_cli_state *state);
void winbindd_getusersids(struct winbindd_cli_state *state);
void winbindd_getuserdomgroups(struct winbindd_cli_state *state);
void winbindd_getsidaliases(struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-bool get_sam_group_entries(struct getent_state *ent);
bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
const char *dom_name, const char *gr_name, gid_t unix_gid);
NTSTATUS winbindd_print_groupmembers(struct talloc_dict *members,
@@ -408,64 +346,17 @@ NTSTATUS winbindd_print_groupmembers(struct talloc_dict *members,
void init_idmap_child(void);
struct winbindd_child *idmap_child(void);
-void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
- void (*cont)(void *private_data, bool success),
- void *private_data);
-enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_remove_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
- void (*cont)(void *private_data, bool success),
- void *private_data);
-enum winbindd_result winbindd_dual_remove_mapping(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
- void (*cont)(void *private_data, bool success),
- void *private_data);
-enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_sids2xids_async(TALLOC_CTX *mem_ctx, void *sids, int size,
- void (*cont)(void *private_data, bool success, void *data, int len),
- void *private_data);
-enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success, uid_t uid),
- void *private_data);
-enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- void (*cont)(void *private_data, bool success, gid_t gid),
- void *private_data);
-enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
- void (*cont)(void *private_data, bool success, const char *sid),
- void *private_data);
-enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
- void (*cont)(void *private_data, bool success, const char *sid),
- void *private_data);
-enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
/* The following definitions come from winbindd/winbindd_locator.c */
void init_locator_child(void);
struct winbindd_child *locator_child(void);
-void winbindd_dsgetdcname(struct winbindd_cli_state *state);
/* The following definitions come from winbindd/winbindd_misc.c */
-void winbindd_check_machine_acct(struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type);
void winbindd_list_trusted_domains(struct winbindd_cli_state *state);
enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
void winbindd_show_sequence(struct winbindd_cli_state *state);
enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
struct winbindd_cli_state *state);
@@ -518,47 +409,10 @@ enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state);
enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state);
-/* The following definitions come from winbindd/winbindd_passdb.c */
-
-
-/* The following definitions come from winbindd/winbindd_reconnect.c */
-
-
-/* The following definitions come from winbindd/winbindd_sid.c */
-
-void winbindd_lookupsid(struct winbindd_cli_state *state);
-void winbindd_lookupname(struct winbindd_cli_state *state);
-void winbindd_lookuprids(struct winbindd_cli_state *state);
-void winbindd_sid_to_uid(struct winbindd_cli_state *state);
-void winbindd_sid_to_gid(struct winbindd_cli_state *state);
-void winbindd_set_mapping(struct winbindd_cli_state *state);
-void winbindd_remove_mapping(struct winbindd_cli_state *state);
-void winbindd_set_hwm(struct winbindd_cli_state *state);
-void winbindd_uid_to_sid(struct winbindd_cli_state *state);
-void winbindd_gid_to_sid(struct winbindd_cli_state *state);
-void winbindd_allocate_uid(struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_allocate_gid(struct winbindd_cli_state *state);
-enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-
-/* The following definitions come from winbindd/winbindd_user.c */
-
-enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
- struct winbindd_cli_state *state);
-void winbindd_getpwnam(struct winbindd_cli_state *state);
-void winbindd_getpwuid(struct winbindd_cli_state *state);
-void winbindd_getpwsid(struct winbindd_cli_state *state);
-void winbindd_setpwent(struct winbindd_cli_state *state);
-void winbindd_endpwent(struct winbindd_cli_state *state);
-void winbindd_getpwent(struct winbindd_cli_state *state);
-void winbindd_list_users(struct winbindd_cli_state *state);
-
/* The following definitions come from winbindd/winbindd_util.c */
struct winbindd_domain *domain_list(void);
-void free_domain_list(void);
+bool domain_is_forest_root(const struct winbindd_domain *domain);
void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
struct timeval now, void *private_data);
enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
@@ -574,19 +428,6 @@ struct winbindd_domain *find_root_domain(void);
struct winbindd_domain *find_builtin_domain(void);
struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid);
struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name);
-bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
- enum winbindd_cmd orig_cmd,
- struct winbindd_domain *domain,
- const char *domain_name,
- const char *name, DOM_SID *sid,
- enum lsa_SidType *type);
-bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
- struct winbindd_domain *domain,
- DOM_SID *sid,
- char **dom_name,
- char **name,
- enum lsa_SidType *type);
-void free_getent_state(struct getent_state *state);
bool parse_domain_user(const char *domuser, fstring domain, fstring user);
bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
char **domain, char **user);
@@ -633,6 +474,7 @@ void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain);
void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain);
void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain);
void set_auth_errors(struct winbindd_response *resp, NTSTATUS result);
+bool is_domain_offline(const struct winbindd_domain *domain);
/* The following definitions come from winbindd/winbindd_wins.c */
@@ -987,6 +829,13 @@ struct tevent_req *winbindd_check_machine_acct_send(TALLOC_CTX *mem_ctx,
NTSTATUS winbindd_check_machine_acct_recv(struct tevent_req *req,
struct winbindd_response *presp);
+struct tevent_req *winbindd_ping_dc_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct winbindd_cli_state *cli,
+ struct winbindd_request *request);
+NTSTATUS winbindd_ping_dc_recv(struct tevent_req *req,
+ struct winbindd_response *presp);
+
struct tevent_req *winbindd_change_machine_acct_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct winbindd_cli_state *cli,
diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c
index 3efd4a9428..bf6e577f29 100644
--- a/source3/winbindd/winbindd_reconnect.c
+++ b/source3/winbindd/winbindd_reconnect.c
@@ -279,21 +279,15 @@ static NTSTATUS password_policy(struct winbindd_domain *domain,
/* get a list of trusted domains */
static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ struct netr_DomainTrustList *trusts)
{
NTSTATUS result;
- result = msrpc_methods.trusted_domains(domain, mem_ctx,
- num_domains, names,
- alt_names, dom_sids);
+ result = msrpc_methods.trusted_domains(domain, mem_ctx, trusts);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.trusted_domains(domain, mem_ctx,
- num_domains, names,
- alt_names, dom_sids);
+ trusts);
return result;
}
diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c
index 1018a2952b..e7003766d8 100644
--- a/source3/winbindd/winbindd_rpc.c
+++ b/source3/winbindd/winbindd_rpc.c
@@ -787,16 +787,16 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
if (!NT_STATUS_IS_OK(result))
return result;
- *num_names = rids->count;
- rid_mem = rids->rids;
-
- if (!*num_names) {
+ if (!rids || !rids->count) {
names = NULL;
name_types = NULL;
sid_mem = NULL;
return NT_STATUS_OK;
}
+ *num_names = rids->count;
+ rid_mem = rids->rids;
+
/* Step #2: Convert list of rids into list of usernames. Do this
in bunches of ~1000 to avoid crashing NT4. It looks like there
is a buffer overflow or something like that lurking around
@@ -1032,10 +1032,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
/* get a list of trusted domains */
static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 *num_domains,
- char ***names,
- char ***alt_names,
- DOM_SID **dom_sids)
+ struct netr_DomainTrustList *trusts)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uint32 enum_ctx = 0;
@@ -1044,10 +1041,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
DEBUG(3,("rpc: trusted_domains\n"));
- *num_domains = 0;
- *names = NULL;
- *alt_names = NULL;
- *dom_sids = NULL;
+ ZERO_STRUCTP(trusts);
result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
if (!NT_STATUS_IS_OK(result))
@@ -1070,22 +1064,33 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
!NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
break;
- start_idx = *num_domains;
- *num_domains += dom_list.count;
- *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
- char *, *num_domains);
- *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
- DOM_SID, *num_domains);
- *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
- char *, *num_domains);
- if ((*names == NULL) || (*dom_sids == NULL) ||
- (*alt_names == NULL))
+ start_idx = trusts->count;
+ trusts->count += dom_list.count;
+
+ trusts->array = talloc_realloc(
+ mem_ctx, trusts->array, struct netr_DomainTrust,
+ trusts->count);
+ if (trusts->array == NULL) {
return NT_STATUS_NO_MEMORY;
+ }
for (i=0; i<dom_list.count; i++) {
- (*names)[start_idx+i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
- (*dom_sids)[start_idx+i] = *dom_list.domains[i].sid;
- (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
+ struct netr_DomainTrust *trust = &trusts->array[i];
+ struct dom_sid *sid;
+
+ ZERO_STRUCTP(trust);
+
+ trust->netbios_name = talloc_move(
+ trusts->array,
+ &dom_list.domains[i].name.string);
+ trust->dns_name = NULL;
+
+ sid = talloc(trusts->array, struct dom_sid);
+ if (sid == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ sid_copy(sid, dom_list.domains[i].sid);
+ trust->sid = sid;
}
}
return result;
@@ -1258,7 +1263,7 @@ NTSTATUS winbindd_lookup_names(TALLOC_CTX *mem_ctx,
NTSTATUS status;
struct rpc_pipe_client *cli = NULL;
struct policy_handle lsa_policy;
- unsigned int orig_timeout;
+ unsigned int orig_timeout = 0;
lookup_names_fn_t lookup_names_fn = rpccli_lsa_lookup_names;
if (domain->can_do_ncacn_ip_tcp) {
diff --git a/source3/winbindd/winbindd_user.c b/source3/winbindd/winbindd_user.c
deleted file mode 100644
index 6afa941b7f..0000000000
--- a/source3/winbindd/winbindd_user.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Winbind daemon - user related functions
-
- Copyright (C) Tim Potter 2000
- Copyright (C) Jeremy Allison 2001.
- Copyright (C) Gerald (Jerry) Carter 2003.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 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 "winbindd.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_WINBIND
-
-/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
-
-enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
- struct winbindd_cli_state *state)
-{
- DOM_SID sid;
- struct wbint_userinfo user_info;
- NTSTATUS status;
-
- /* Ensure null termination */
- state->request->data.sid[sizeof(state->request->data.sid)-1]='\0';
-
- DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
- state->request->data.sid));
-
- if (!string_to_sid(&sid, state->request->data.sid)) {
- DEBUG(5, ("%s not a SID\n", state->request->data.sid));
- return WINBINDD_ERROR;
- }
-
- status = domain->methods->query_user(domain, state->mem_ctx,
- &sid, &user_info);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("error getting user info for sid %s\n",
- sid_string_dbg(&sid)));
- return WINBINDD_ERROR;
- }
-
- fstrcpy(state->response->data.user_info.acct_name,
- user_info.acct_name);
- fstrcpy(state->response->data.user_info.full_name,
- user_info.full_name);
- fstrcpy(state->response->data.user_info.homedir, user_info.homedir);
- fstrcpy(state->response->data.user_info.shell, user_info.shell);
- state->response->data.user_info.primary_gid = user_info.primary_gid;
- if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
- &state->response->data.user_info.group_rid)) {
- DEBUG(1, ("Could not extract group rid out of %s\n",
- sid_string_dbg(&sid)));
- return WINBINDD_ERROR;
- }
-
- return WINBINDD_OK;
-}
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index ff8c101b37..3e03f4091c 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -58,7 +58,7 @@ struct winbindd_domain *domain_list(void)
/* Free all entries in the trusted domain list */
-void free_domain_list(void)
+static void free_domain_list(void)
{
struct winbindd_domain *domain = _domain_list;
@@ -143,13 +143,14 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
}
}
- /* See if we found a match. Check if we need to update the
- SID. */
-
- if ( domain && sid) {
- if ( sid_equal( &domain->sid, &global_sid_NULL ) )
+ if (domain != NULL) {
+ /*
+ * We found a match. Possibly update the SID
+ */
+ if ((sid != NULL)
+ && sid_equal(&domain->sid, &global_sid_NULL)) {
sid_copy( &domain->sid, sid );
-
+ }
return domain;
}
@@ -223,6 +224,14 @@ done:
return domain;
}
+bool domain_is_forest_root(const struct winbindd_domain *domain)
+{
+ const uint32_t fr_flags =
+ (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
+
+ return ((domain->domain_flags & fr_flags) == fr_flags);
+}
+
/********************************************************************
rescan our domains looking for new trusted domains
********************************************************************/
@@ -243,8 +252,6 @@ static void add_trusted_domains( struct winbindd_domain *domain )
TALLOC_CTX *mem_ctx;
struct winbindd_request *request;
struct winbindd_response *response;
- uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
-
struct trustdom_state *state;
mem_ctx = talloc_init("add_trusted_domains");
@@ -269,7 +276,7 @@ static void add_trusted_domains( struct winbindd_domain *domain )
/* Flags used to know how to continue the forest trust search */
state->primary = domain->primary;
- state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
+ state->forest_root = domain_is_forest_root(domain);
request->length = sizeof(*request);
request->cmd = WINBINDD_LIST_TRUSTDOM;
@@ -792,23 +799,18 @@ struct winbindd_domain *find_root_domain(void)
{
struct winbindd_domain *ours = find_our_domain();
- if ( !ours )
- return NULL;
-
- if ( strlen(ours->forest_name) == 0 )
+ if (ours->forest_name[0] == '\0') {
return NULL;
+ }
return find_domain_from_name( ours->forest_name );
}
struct winbindd_domain *find_builtin_domain(void)
{
- DOM_SID sid;
struct winbindd_domain *domain;
- string_to_sid(&sid, "S-1-5-32");
- domain = find_domain_from_sid(&sid);
-
+ domain = find_domain_from_sid(&global_sid_Builtin);
if (domain == NULL) {
smb_panic("Could not find BUILTIN domain");
}
@@ -868,95 +870,6 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
return find_our_domain();
}
-/* Lookup a sid in a domain from a name */
-
-bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
- enum winbindd_cmd orig_cmd,
- struct winbindd_domain *domain,
- const char *domain_name,
- const char *name, DOM_SID *sid,
- enum lsa_SidType *type)
-{
- NTSTATUS result;
-
- /*
- * For all but LOOKUPNAME we have to avoid nss calls to avoid
- * recursion
- */
- result = domain->methods->name_to_sid(
- domain, mem_ctx, domain_name, name,
- orig_cmd == WINBINDD_LOOKUPNAME ? 0 : LOOKUP_NAME_NO_NSS,
- sid, type);
-
- /* Return sid and type if lookup successful */
- if (!NT_STATUS_IS_OK(result)) {
- *type = SID_NAME_UNKNOWN;
- }
-
- return NT_STATUS_IS_OK(result);
-}
-
-/**
- * @brief Lookup a name in a domain from a sid.
- *
- * @param sid Security ID you want to look up.
- * @param name On success, set to the name corresponding to @p sid.
- * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
- * @param type On success, contains the type of name: alias, group or
- * user.
- * @retval True if the name exists, in which case @p name and @p type
- * are set, otherwise False.
- **/
-bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
- struct winbindd_domain *domain,
- DOM_SID *sid,
- char **dom_name,
- char **name,
- enum lsa_SidType *type)
-{
- NTSTATUS result;
-
- *dom_name = NULL;
- *name = NULL;
-
- /* Lookup name */
-
- result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
-
- /* Return name and type if successful */
-
- if (NT_STATUS_IS_OK(result)) {
- return True;
- }
-
- *type = SID_NAME_UNKNOWN;
-
- return False;
-}
-
-/* Free state information held for {set,get,end}{pw,gr}ent() functions */
-
-void free_getent_state(struct getent_state *state)
-{
- struct getent_state *temp;
-
- /* Iterate over state list */
-
- temp = state;
-
- while(temp != NULL) {
- struct getent_state *next = temp->next;
-
- /* Free sam entries then list entry */
-
- SAFE_FREE(state->sam_entries);
- DLIST_REMOVE(state, state);
-
- SAFE_FREE(temp);
- temp = next;
- }
-}
-
/* Is this a domain which we may assume no DOMAIN\ prefix? */
static bool assume_domain(const char *domain)
@@ -1550,3 +1463,14 @@ void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
get_friendly_nt_error_msg(result));
resp->data.auth.pam_error = nt_status_to_pam(result);
}
+
+bool is_domain_offline(const struct winbindd_domain *domain)
+{
+ if (!lp_winbind_offline_logon()) {
+ return false;
+ }
+ if (get_global_winbindd_state_offline()) {
+ return true;
+ }
+ return !domain->online;
+}
diff --git a/source4/Makefile b/source4/Makefile
index 6a99ea3160..0da1ee2626 100644
--- a/source4/Makefile
+++ b/source4/Makefile
@@ -243,7 +243,7 @@ installman:: manpages installdirs
@$(SHELL) $(srcdir)/script/installman.sh $(DESTDIR)$(mandir) $(MANPAGES)
installmisc:: installdirs
- @$(SHELL) $(srcdir)/script/installmisc.sh $(srcdir) $(DESTDIR)$(setupdir) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) $(pythondir)
+ @$(SHELL) $(srcdir)/script/installmisc.sh "$(DESTDIR)" $(srcdir) $(DESTDIR)$(setupdir) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) $(pythondir) $(PYTHON)
installpc:: installdirs
@$(SHELL) $(srcdir)/script/installpc.sh $(builddir) $(DESTDIR)$(pkgconfigdir) $(PC_FILES)
diff --git a/source4/auth/auth.h b/source4/auth/auth.h
index c31ed2f5fd..fa2329df32 100644
--- a/source4/auth/auth.h
+++ b/source4/auth/auth.h
@@ -135,7 +135,7 @@ struct auth_operations {
* security=server, and makes a number of compromises to allow
* that. It is not compatible with being a PDC. */
- NTSTATUS (*get_challenge)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge);
+ NTSTATUS (*get_challenge)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]);
/* Given the user supplied info, check if this backend want to handle the password checking */
@@ -190,7 +190,7 @@ struct auth_context {
const struct auth_usersupplied_info *user_info,
struct auth_serversupplied_info **server_info);
- NTSTATUS (*get_challenge)(struct auth_context *auth_ctx, const uint8_t **_chal);
+ NTSTATUS (*get_challenge)(struct auth_context *auth_ctx, uint8_t chal[8]);
bool (*challenge_may_be_modified)(struct auth_context *auth_ctx);
@@ -226,7 +226,7 @@ struct ldb_context;
struct ldb_dn;
struct gensec_security;
-NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal);
+NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8]);
NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
struct ldb_context *sam_ctx,
uint32_t logon_parameters,
@@ -275,16 +275,23 @@ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx,
const char *nt4_username,
const char *password,
struct auth_session_info **session_info);
-NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
+
+struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_context *auth_ctx,
+ const struct auth_usersupplied_info *user_info);
+NTSTATUS auth_check_password_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct auth_serversupplied_info **server_info);
-void auth_check_password_send(struct auth_context *auth_ctx,
- const struct auth_usersupplied_info *user_info,
- void (*callback)(struct auth_check_password_request *req, void *private_data),
- void *private_data);
+bool auth_challenge_may_be_modified(struct auth_context *auth_ctx);
NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by);
+NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx,
+ struct auth_context *auth_ctx,
+ const char *principal,
+ struct auth_serversupplied_info **server_info);
+
NTSTATUS samba_server_gensec_start(TALLOC_CTX *mem_ctx,
struct tevent_context *event_ctx,
struct messaging_context *msg_ctx,
diff --git a/source4/auth/credentials/config.mk b/source4/auth/credentials/config.mk
index 6b051ef46c..32f415a8bf 100644
--- a/source4/auth/credentials/config.mk
+++ b/source4/auth/credentials/config.mk
@@ -4,7 +4,7 @@
PUBLIC_DEPENDENCIES = \
LIBCLI_AUTH SECRETS LIBCRYPTO KERBEROS UTIL_LDB HEIMDAL_GSSAPI
PRIVATE_DEPENDENCIES = \
- SECRETS
+ SECRETS SAMDB
CREDENTIALS_OBJ_FILES = $(addprefix $(authsrcdir)/credentials/, credentials.o credentials_files.o credentials_ntlm.o credentials_krb5.o ../kerberos/kerberos_util.o)
diff --git a/source4/auth/gensec/config.mk b/source4/auth/gensec/config.mk
index f7cbd5b197..947a91e852 100644
--- a/source4/auth/gensec/config.mk
+++ b/source4/auth/gensec/config.mk
@@ -2,7 +2,7 @@
# Start SUBSYSTEM gensec
[LIBRARY::gensec]
PUBLIC_DEPENDENCIES = \
- CREDENTIALS LIBSAMBA-UTIL LIBCRYPTO ASN1_UTIL samba_socket LIBPACKET LIBTSOCKET
+ CREDENTIALS LIBSAMBA-UTIL LIBCRYPTO ASN1_UTIL samba_socket LIBPACKET LIBTSOCKET UTIL_TEVENT
# End SUBSYSTEM gensec
#################################
diff --git a/source4/auth/gensec/gensec.c b/source4/auth/gensec/gensec.c
index ecd0778ee6..3de0e1c935 100644
--- a/source4/auth/gensec/gensec.c
+++ b/source4/auth/gensec/gensec.c
@@ -25,6 +25,7 @@
#include "lib/events/events.h"
#include "lib/socket/socket.h"
#include "lib/tsocket/tsocket.h"
+#include "../lib/util/tevent_ntstatus.h"
#include "librpc/rpc/dcerpc.h"
#include "auth/credentials/credentials.h"
#include "auth/gensec/gensec.h"
@@ -982,71 +983,105 @@ _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_
return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
}
-static void gensec_update_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
- struct timeval t, void *ptr)
-{
- struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
- req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
- req->callback.fn(req, req->callback.private_data);
-}
+struct gensec_update_state {
+ struct tevent_immediate *im;
+ struct gensec_security *gensec_security;
+ DATA_BLOB in;
+ DATA_BLOB out;
+};
+static void gensec_update_async_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
/**
* Next state function for the GENSEC state machine async version
- *
+ *
+ * @param mem_ctx The memory context for the request
+ * @param ev The event context for the request
* @param gensec_security GENSEC State
* @param in The request, as a DATA_BLOB
- * @param callback The function that will be called when the operation is
- * finished, it should return gensec_update_recv() to get output
- * @param private_data A private pointer that will be passed to the callback function
+ *
+ * @return The request handle or NULL on no memory failure
*/
-_PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
- void (*callback)(struct gensec_update_request *req, void *private_data),
- void *private_data)
+_PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_security,
+ const DATA_BLOB in)
+{
+ struct tevent_req *req;
+ struct gensec_update_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct gensec_update_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->gensec_security = gensec_security;
+ state->in = in;
+ state->out = data_blob(NULL, 0);
+ state->im = tevent_create_immediate(state);
+ if (tevent_req_nomem(state->im, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_schedule_immediate(state->im, ev,
+ gensec_update_async_trigger,
+ req);
+
+ return req;
+}
+
+static void gensec_update_async_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
{
- struct gensec_update_request *req = NULL;
- struct tevent_timer *te = NULL;
-
- req = talloc(gensec_security, struct gensec_update_request);
- if (!req) goto failed;
- req->gensec_security = gensec_security;
- req->in = in;
- req->out = data_blob(NULL, 0);
- req->callback.fn = callback;
- req->callback.private_data = private_data;
-
- te = event_add_timed(gensec_security->event_ctx, req,
- timeval_zero(),
- gensec_update_async_timed_handler, req);
- if (!te) goto failed;
-
- return;
-
-failed:
- talloc_free(req);
- callback(NULL, private_data);
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data, struct tevent_req);
+ struct gensec_update_state *state =
+ tevent_req_data(req, struct gensec_update_state);
+ NTSTATUS status;
+
+ status = gensec_update(state->gensec_security, state,
+ state->in, &state->out);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
}
/**
* Next state function for the GENSEC state machine
*
- * @param req GENSEC update request state
+ * @param req request state
* @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
* @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
* @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
* or NT_STATUS_OK if the user is authenticated.
*/
-_PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
+_PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB *out)
{
+ struct gensec_update_state *state =
+ tevent_req_data(req, struct gensec_update_state);
NTSTATUS status;
- NT_STATUS_HAVE_NO_MEMORY(req);
+ if (tevent_req_is_nterror(req, &status)) {
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_received(req);
+ return status;
+ }
+ } else {
+ status = NT_STATUS_OK;
+ }
- *out = req->out;
+ *out = state->out;
talloc_steal(out_mem_ctx, out->data);
- status = req->status;
- talloc_free(req);
+ tevent_req_received(req);
return status;
}
diff --git a/source4/auth/gensec/gensec.h b/source4/auth/gensec/gensec.h
index 2ea2402064..232f1a4500 100644
--- a/source4/auth/gensec/gensec.h
+++ b/source4/auth/gensec/gensec.h
@@ -69,18 +69,7 @@ struct auth_session_info;
struct cli_credentials;
struct gensec_settings;
struct tevent_context;
-
-struct gensec_update_request {
- struct gensec_security *gensec_security;
- void *private_data;
- DATA_BLOB in;
- DATA_BLOB out;
- NTSTATUS status;
- struct {
- void (*fn)(struct gensec_update_request *req, void *private_data);
- void *private_data;
- } callback;
-};
+struct tevent_req;
struct gensec_settings {
struct loadparm_context *lp_ctx;
@@ -231,10 +220,11 @@ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
const char **sasl_names);
NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out);
-void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
- void (*callback)(struct gensec_update_request *req, void *private_data),
- void *private_data);
-NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out);
+struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_security,
+ const DATA_BLOB in);
+NTSTATUS gensec_update_recv(struct tevent_req *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out);
void gensec_want_feature(struct gensec_security *gensec_security,
uint32_t feature);
bool gensec_have_feature(struct gensec_security *gensec_security,
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 5520c9d01f..d5df387d80 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -19,10 +19,11 @@
*/
#include "includes.h"
+#include <tevent.h>
+#include "../lib/util/tevent_ntstatus.h"
#include "../lib/util/dlinklist.h"
#include "auth/auth.h"
#include "auth/ntlm/auth_proto.h"
-#include "lib/events/events.h"
#include "param/param.h"
/***************************************************************************
@@ -42,7 +43,7 @@ _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, cons
/***************************************************************************
Set a fixed challenge
***************************************************************************/
-bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
+_PUBLIC_ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
{
return auth_ctx->challenge.may_be_modified;
}
@@ -51,42 +52,34 @@ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
Try to get a challenge out of the various authentication modules.
Returns a const char of length 8 bytes.
****************************************************************************/
-_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
+_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8])
{
NTSTATUS nt_status;
struct auth_method_context *method;
- if (auth_ctx->challenge.data.length) {
+ if (auth_ctx->challenge.data.length == 8) {
DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
auth_ctx->challenge.set_by));
- *_chal = auth_ctx->challenge.data.data;
+ memcpy(chal, auth_ctx->challenge.data.data, 8);
return NT_STATUS_OK;
}
for (method = auth_ctx->methods; method; method = method->next) {
- DATA_BLOB challenge = data_blob(NULL,0);
-
- nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
+ nt_status = method->ops->get_challenge(method, auth_ctx, chal);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
continue;
}
NT_STATUS_NOT_OK_RETURN(nt_status);
- if (challenge.length != 8) {
- DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
- (unsigned)challenge.length, method->ops->name));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- auth_ctx->challenge.data = challenge;
+ auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
+ NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
auth_ctx->challenge.set_by = method->ops->name;
break;
}
if (!auth_ctx->challenge.set_by) {
- uint8_t chal[8];
generate_random_buffer(chal, 8);
auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
@@ -99,7 +92,6 @@ _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_
DEBUG(10,("auth_get_challenge: challenge set by %s\n",
auth_ctx->challenge.set_by));
- *_chal = auth_ctx->challenge.data.data;
return NT_STATUS_OK;
}
@@ -133,22 +125,6 @@ _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
-struct auth_check_password_sync_state {
- bool finished;
- NTSTATUS status;
- struct auth_serversupplied_info *server_info;
-};
-
-static void auth_check_password_sync_callback(struct auth_check_password_request *req,
- void *private_data)
-{
- struct auth_check_password_sync_state *s = talloc_get_type(private_data,
- struct auth_check_password_sync_state);
-
- s->finished = true;
- s->status = auth_check_password_recv(req, s, &s->server_info);
-}
-
/**
* Check a user's Plaintext, LM or NTLM password.
* (sync version)
@@ -181,48 +157,43 @@ _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
const struct auth_usersupplied_info *user_info,
struct auth_serversupplied_info **server_info)
{
- struct auth_check_password_sync_state *sync_state;
+ struct tevent_req *subreq;
+ struct tevent_context *ev;
+ bool ok;
NTSTATUS status;
- sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
- NT_STATUS_HAVE_NO_MEMORY(sync_state);
-
- auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
+ /*TODO: create a new event context here! */
+ ev = auth_ctx->event_ctx;
- while (!sync_state->finished) {
- event_loop_once(auth_ctx->event_ctx);
+ subreq = auth_check_password_send(mem_ctx,
+ ev,
+ auth_ctx,
+ user_info);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- status = sync_state->status;
-
- if (NT_STATUS_IS_OK(status)) {
- *server_info = talloc_steal(mem_ctx, sync_state->server_info);
+ ok = tevent_req_poll(subreq, ev);
+ if (!ok) {
+ return NT_STATUS_INTERNAL_ERROR;
}
- talloc_free(sync_state);
+ status = auth_check_password_recv(subreq, mem_ctx, server_info);
+ TALLOC_FREE(subreq);
+
return status;
}
-struct auth_check_password_request {
+struct auth_check_password_state {
struct auth_context *auth_ctx;
const struct auth_usersupplied_info *user_info;
struct auth_serversupplied_info *server_info;
struct auth_method_context *method;
- NTSTATUS status;
- struct {
- void (*fn)(struct auth_check_password_request *req, void *private_data);
- void *private_data;
- } callback;
};
-static void auth_check_password_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
- struct timeval t, void *ptr)
-{
- struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
- req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
- req->callback.fn(req, req->callback.private_data);
-}
-
+static void auth_check_password_async_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
/**
* Check a user's Plaintext, LM or NTLM password.
* async send hook
@@ -234,6 +205,10 @@ static void auth_check_password_async_timed_handler(struct tevent_context *ev, s
* struct. When the return is other than NT_STATUS_OK the contents
* of that structure is undefined.
*
+ * @param mem_ctx The memory context the request should operate on
+ *
+ * @param ev The tevent context the request should operate on
+ *
* @param auth_ctx Supplies the challenges and some other data.
* Must be created with make_auth_context(), and the challenges should be
* filled in, either at creation or by calling the challenge geneation
@@ -241,93 +216,131 @@ static void auth_check_password_async_timed_handler(struct tevent_context *ev, s
*
* @param user_info Contains the user supplied components, including the passwords.
*
- * @param callback A callback function which will be called when the operation is finished.
- * The callback function needs to call auth_check_password_recv() to get the return values
- *
- * @param private_data A private pointer which will ba passed to the callback function
+ * @return The request handle or NULL on no memory error.
*
**/
-_PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx,
- const struct auth_usersupplied_info *user_info,
- void (*callback)(struct auth_check_password_request *req, void *private_data),
- void *private_data)
+_PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_context *auth_ctx,
+ const struct auth_usersupplied_info *user_info)
{
+ struct tevent_req *req;
+ struct auth_check_password_state *state;
/* if all the modules say 'not for me' this is reasonable */
NTSTATUS nt_status;
struct auth_method_context *method;
- const uint8_t *challenge;
+ uint8_t chal[8];
struct auth_usersupplied_info *user_info_tmp;
- struct auth_check_password_request *req = NULL;
+ struct tevent_immediate *im;
- DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
- user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
+ DEBUG(3,("auth_check_password_send: "
+ "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
+ user_info->client.domain_name, user_info->client.account_name,
+ user_info->workstation_name));
- req = talloc_zero(auth_ctx, struct auth_check_password_request);
- if (!req) {
- callback(NULL, private_data);
- return;
+ req = tevent_req_create(mem_ctx, &state,
+ struct auth_check_password_state);
+ if (req == NULL) {
+ return NULL;
}
- req->auth_ctx = auth_ctx;
- req->user_info = user_info;
- req->callback.fn = callback;
- req->callback.private_data = private_data;
+
+ state->auth_ctx = auth_ctx;
+ state->user_info = user_info;
+ state->method = NULL;
if (!user_info->mapped_state) {
- nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
- if (!NT_STATUS_IS_OK(nt_status)) goto failed;
+ nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx),
+ user_info, &user_info_tmp);
+ if (tevent_req_nterror(req, nt_status)) {
+ return tevent_req_post(req, ev);
+ }
user_info = user_info_tmp;
- req->user_info = user_info_tmp;
+ state->user_info = user_info_tmp;
}
- DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n",
- user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
-
- nt_status = auth_get_challenge(auth_ctx, &challenge);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
- (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
- goto failed;
+ DEBUGADD(3,("auth_check_password_send: "
+ "mapped user is: [%s]\\[%s]@[%s]\n",
+ user_info->mapped.domain_name,
+ user_info->mapped.account_name,
+ user_info->workstation_name));
+
+ nt_status = auth_get_challenge(auth_ctx, chal);
+ if (tevent_req_nterror(req, nt_status)) {
+ DEBUG(0,("auth_check_password_send: "
+ "Invalid challenge (length %u) stored for "
+ "this auth context set_by %s - cannot continue: %s\n",
+ (unsigned)auth_ctx->challenge.data.length,
+ auth_ctx->challenge.set_by,
+ nt_errstr(nt_status)));
+ return tevent_req_post(req, ev);
}
if (auth_ctx->challenge.set_by) {
- DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
- auth_ctx->challenge.set_by));
+ DEBUG(10,("auth_check_password_send: "
+ "auth_context challenge created by %s\n",
+ auth_ctx->challenge.set_by));
}
DEBUG(10, ("auth_check_password_send: challenge is: \n"));
- dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
+ dump_data(5, auth_ctx->challenge.data.data,
+ auth_ctx->challenge.data.length);
+
+ im = tevent_create_immediate(state);
+ if (tevent_req_nomem(im, req)) {
+ return tevent_req_post(req, ev);
+ }
- nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
for (method = auth_ctx->methods; method; method = method->next) {
NTSTATUS result;
- struct tevent_timer *te = NULL;
/* check if the module wants to chek the password */
result = method->ops->want_check(method, req, user_info);
if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
- DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
+ DEBUG(11,("auth_check_password_send: "
+ "%s had nothing to say\n",
+ method->ops->name));
continue;
}
- nt_status = result;
- req->method = method;
-
- if (!NT_STATUS_IS_OK(nt_status)) break;
+ state->method = method;
- te = event_add_timed(auth_ctx->event_ctx, req,
- timeval_zero(),
- auth_check_password_async_timed_handler, req);
- if (!te) {
- nt_status = NT_STATUS_NO_MEMORY;
- goto failed;
+ if (tevent_req_nterror(req, result)) {
+ return tevent_req_post(req, ev);
}
+
+ tevent_schedule_immediate(im,
+ auth_ctx->event_ctx,
+ auth_check_password_async_trigger,
+ req);
+
+ return req;
+ }
+
+ /* If all the modules say 'not for me', then this is reasonable */
+ tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
+ return tevent_req_post(req, ev);
+}
+
+static void auth_check_password_async_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data, struct tevent_req);
+ struct auth_check_password_state *state =
+ tevent_req_data(req, struct auth_check_password_state);
+ NTSTATUS status;
+
+ status = state->method->ops->check_password(state->method,
+ state,
+ state->user_info,
+ &state->server_info);
+ if (tevent_req_nterror(req, status)) {
return;
}
-failed:
- req->status = nt_status;
- req->callback.fn(req, req->callback.private_data);
+ tevent_req_done(req);
}
/**
@@ -339,7 +352,7 @@ failed:
* of that structure is undefined.
*
*
- * @param req The async auth_check_password state, passes to the callers callback function
+ * @param req The async request state
*
* @param mem_ctx The parent memory context for the server_info structure
*
@@ -350,30 +363,36 @@ failed:
*
**/
-_PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
+_PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct auth_serversupplied_info **server_info)
{
+ struct auth_check_password_state *state =
+ tevent_req_data(req, struct auth_check_password_state);
NTSTATUS status;
- NT_STATUS_HAVE_NO_MEMORY(req);
+ if (tevent_req_is_nterror(req, &status)) {
+ DEBUG(2,("auth_check_password_recv: "
+ "%s authentication for user [%s\\%s]"
+ "FAILED with error %s\n",
+ (state->method ? state->method->ops->name : "NO_METHOD"),
+ state->user_info->mapped.domain_name,
+ state->user_info->mapped.account_name,
+ nt_errstr(status)));
+ tevent_req_received(req);
+ return status;
+ }
- if (NT_STATUS_IS_OK(req->status)) {
- DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
- req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
+ DEBUG(5,("auth_check_password_recv: "
+ "%s authentication for user [%s\\%s] succeeded\n",
+ state->method->ops->name,
+ state->server_info->domain_name,
+ state->server_info->account_name));
- *server_info = talloc_steal(mem_ctx, req->server_info);
- } else {
- DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n",
- (req->method ? req->method->ops->name : "NO_METHOD"),
- req->user_info->mapped.domain_name,
- req->user_info->mapped.account_name,
- nt_errstr(req->status)));
- }
+ *server_info = talloc_move(mem_ctx, &state->server_info);
- status = req->status;
- talloc_free(req);
- return status;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
/***************************************************************************
diff --git a/source4/auth/ntlm/auth_proto.h b/source4/auth/ntlm/auth_proto.h
deleted file mode 100644
index 572c1a4ca7..0000000000
--- a/source4/auth/ntlm/auth_proto.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef __AUTH_NTLM_AUTH_PROTO_H__
-#define __AUTH_NTLM_AUTH_PROTO_H__
-
-#undef _PRINTF_ATTRIBUTE
-#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
-/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
-
-/* this file contains prototypes for functions that are private
- * to this subsystem or library. These functions should not be
- * used outside this particular subsystem! */
-
-
-/* The following definitions come from auth/ntlm/auth.c */
-
-
-/***************************************************************************
- Set a fixed challenge
-***************************************************************************/
-bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) ;
-const struct auth_operations *auth_backend_byname(const char *name);
-const struct auth_critical_sizes *auth_interface_version(void);
-NTSTATUS server_service_auth_init(void);
-
-/* The following definitions come from auth/ntlm/auth_util.c */
-
-NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge);
-
-/****************************************************************************
- Create an auth_usersupplied_data structure after appropriate mapping.
-****************************************************************************/
-NTSTATUS map_user_info(TALLOC_CTX *mem_ctx,
- const char *default_domain,
- const struct auth_usersupplied_info *user_info,
- struct auth_usersupplied_info **user_info_mapped);
-
-/****************************************************************************
- Create an auth_usersupplied_data structure after appropriate mapping.
-****************************************************************************/
-NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context,
- enum auth_password_state to_state,
- const struct auth_usersupplied_info *user_info_in,
- const struct auth_usersupplied_info **user_info_encrypted);
-
-/* The following definitions come from auth/ntlm/auth_simple.c */
-
-#undef _PRINTF_ATTRIBUTE
-#define _PRINTF_ATTRIBUTE(a1, a2)
-
-#endif /* __AUTH_NTLM_AUTH_PROTO_H__ */
-
diff --git a/source4/auth/ntlm/auth_server.c b/source4/auth/ntlm/auth_server.c
index 12849aa420..ae7b7dd3a8 100644
--- a/source4/auth/ntlm/auth_server.c
+++ b/source4/auth/ntlm/auth_server.c
@@ -40,7 +40,7 @@ static NTSTATUS server_want_check(struct auth_method_context *ctx,
/**
* The challenge from the target server, when operating in security=server
**/
-static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob)
+static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8])
{
struct smb_composite_connect io;
struct smbcli_options smb_options;
@@ -88,7 +88,10 @@ static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX
ctx->auth_ctx->event_ctx);
NT_STATUS_NOT_OK_RETURN(status);
- *_blob = io.out.tree->session->transport->negotiate.secblob;
+ if (io.out.tree->session->transport->negotiate.secblob.length != 8) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ memcpy(chal, io.out.tree->session->transport->negotiate.secblob.data, 8);
ctx->private_data = talloc_steal(ctx, io.out.tree->session);
return NT_STATUS_OK;
}
diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c
index 5543cbebea..92df0bfe80 100644
--- a/source4/auth/ntlm/auth_util.c
+++ b/source4/auth/ntlm/auth_util.c
@@ -29,7 +29,7 @@
/* this default function can be used by mostly all backends
* which don't want to set a challenge
*/
-NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge)
+NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8])
{
/* we don't want to set a challenge */
return NT_STATUS_NOT_IMPLEMENTED;
@@ -122,7 +122,7 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex
}
case AUTH_PASSWORD_HASH:
{
- const uint8_t *challenge;
+ uint8_t chal[8];
DATA_BLOB chall_blob;
user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info);
if (!user_info_temp) {
@@ -134,12 +134,12 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex
*user_info_temp = *user_info_in;
user_info_temp->mapped_state = to_state;
- nt_status = auth_get_challenge(auth_context, &challenge);
+ nt_status = auth_get_challenge(auth_context, chal);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
- chall_blob = data_blob_talloc(mem_ctx, challenge, 8);
+ chall_blob = data_blob_talloc(mem_ctx, chal, 8);
if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) {
DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx));
DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key;
@@ -162,12 +162,12 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex
data_blob_free(&ntlmv2_session_key);
} else {
DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24);
- SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data);
+ SMBOWFencrypt(user_info_in->password.hash.nt->hash, chal, blob.data);
user_info_temp->password.response.nt = blob;
if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) {
DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24);
- SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data);
+ SMBOWFencrypt(user_info_in->password.hash.lanman->hash, chal, blob.data);
user_info_temp->password.response.lanman = lm_blob;
} else {
/* if not sending the LM password, send the NT password twice */
diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c
index 568226dd87..173a895390 100644
--- a/source4/auth/ntlm/auth_winbind.c
+++ b/source4/auth/ntlm/auth_winbind.c
@@ -271,7 +271,7 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
s->req.in.logon.password= password_info;
} else {
struct netr_NetworkInfo *network_info;
- const uint8_t *challenge;
+ uint8_t chal[8];
status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE,
user_info, &user_info_new);
@@ -281,10 +281,10 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
network_info = talloc(s, struct netr_NetworkInfo);
NT_STATUS_HAVE_NO_MEMORY(network_info);
- status = auth_get_challenge(ctx->auth_ctx, &challenge);
+ status = auth_get_challenge(ctx->auth_ctx, chal);
NT_STATUS_NOT_OK_RETURN(status);
- memcpy(network_info->challenge, challenge, sizeof(network_info->challenge));
+ memcpy(network_info->challenge, chal, sizeof(network_info->challenge));
network_info->nt.length = user_info->password.response.nt.length;
network_info->nt.data = user_info->password.response.nt.data;
diff --git a/source4/auth/ntlm/config.mk b/source4/auth/ntlm/config.mk
index a0d668f748..6c75ae842d 100644
--- a/source4/auth/ntlm/config.mk
+++ b/source4/auth/ntlm/config.mk
@@ -71,10 +71,10 @@ PAM_ERRORS_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, pam_errors.o)
INIT_FUNCTION = server_service_auth_init
SUBSYSTEM = service
OUTPUT_TYPE = MERGED_OBJ
-PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS
+PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS UTIL_TEVENT
auth_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, auth.o auth_util.o auth_simple.o)
-$(eval $(call proto_header_template,$(authsrcdir)/auth_proto.h,$(auth_OBJ_FILES:.o=.c)))
+$(eval $(call proto_header_template,$(authsrcdir)/ntlm/auth_proto.h,$(auth_OBJ_FILES:.o=.c)))
# PUBLIC_HEADERS += auth/auth.h
diff --git a/source4/auth/ntlmssp/ntlmssp.h b/source4/auth/ntlmssp/ntlmssp.h
index 7743e7697e..7bed54d6d8 100644
--- a/source4/auth/ntlmssp/ntlmssp.h
+++ b/source4/auth/ntlmssp/ntlmssp.h
@@ -1,20 +1,20 @@
-/*
+/*
Unix SMB/CIFS implementation.
SMB parameters and setup
Copyright (C) Andrew Tridgell 1992-1997
Copyright (C) Luke Kenneth Casson Leighton 1996-1997
Copyright (C) Paul Ashton 1997
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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/>.
*/
@@ -37,7 +37,7 @@ enum ntlmssp_message_type
NTLMSSP_CHALLENGE = 2,
NTLMSSP_AUTH = 3,
NTLMSSP_UNKNOWN = 4,
- NTLMSSP_DONE = 5 /* samba final state */
+ NTLMSSP_DONE = 5 /* samba final state */
};
struct gensec_ntlmssp_state
@@ -65,29 +65,30 @@ struct gensec_ntlmssp_state
DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */
- DATA_BLOB lm_resp;
+ DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DATA_BLOB session_key;
-
+
uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
/* internal variables used by KEY_EXCH (client-supplied user session key */
DATA_BLOB encrypted_session_key;
/**
- * Callback to get the 'challenge' used for NTLM authentication.
+ * Callback to get the 'challenge' used for NTLM authentication.
*
* @param ntlmssp_state This structure
* @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication
*
*/
- const uint8_t *(*get_challenge)(const struct gensec_ntlmssp_state *);
+ NTSTATUS (*get_challenge)(const struct gensec_ntlmssp_state *,
+ uint8_t challenge[8]);
/**
- * Callback to find if the challenge used by NTLM authentication may be modified
+ * Callback to find if the challenge used by NTLM authentication may be modified
*
* The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the
- * current 'security=server' implementation..
+ * current 'security=server' implementation..
*
* @param ntlmssp_state This structure
* @return Can the challenge be set to arbitary values?
@@ -96,7 +97,7 @@ struct gensec_ntlmssp_state
bool (*may_set_challenge)(const struct gensec_ntlmssp_state *);
/**
- * Callback to set the 'challenge' used for NTLM authentication.
+ * Callback to set the 'challenge' used for NTLM authentication.
*
* The callback may use the void *auth_context to store state information, but the same value is always available
* from the DATA_BLOB chal on this structure.
@@ -108,21 +109,20 @@ struct gensec_ntlmssp_state
NTSTATUS (*set_challenge)(struct gensec_ntlmssp_state *, DATA_BLOB *challenge);
/**
- * Callback to check the user's password.
+ * Callback to check the user's password.
*
- * The callback must reads the feilds of this structure for the information it needs on the user
+ * The callback must reads the feilds of this structure for the information it needs on the user
* @param ntlmssp_state This structure
* @param nt_session_key If an NT session key is returned by the authentication process, return it here
* @param lm_session_key If an LM session key is returned by the authentication process, return it here
*
*/
- NTSTATUS (*check_password)(struct gensec_ntlmssp_state *,
- TALLOC_CTX *mem_ctx,
+ NTSTATUS (*check_password)(struct gensec_ntlmssp_state *,
DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
const char *server_name;
- bool doing_ntlm2;
+ bool doing_ntlm2;
union {
/* NTLM */
diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c
index 94de920772..c49bf2fea7 100644
--- a/source4/auth/ntlmssp/ntlmssp_server.c
+++ b/source4/auth/ntlmssp/ntlmssp_server.c
@@ -124,8 +124,9 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security,
DATA_BLOB struct_blob;
uint32_t neg_flags = 0;
uint32_t ntlmssp_command, chal_flags;
- const uint8_t *cryptkey;
+ uint8_t cryptkey[8];
const char *target_name;
+ NTSTATUS status;
/* parse the NTLMSSP packet */
#if 0
@@ -150,10 +151,11 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security,
ntlmssp_handle_neg_flags(gensec_ntlmssp_state, neg_flags, gensec_ntlmssp_state->allow_lm_key);
/* Ask our caller what challenge they would like in the packet */
- cryptkey = gensec_ntlmssp_state->get_challenge(gensec_ntlmssp_state);
- if (!cryptkey) {
- DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge\n"));
- return NT_STATUS_INTERNAL_ERROR;
+ status = gensec_ntlmssp_state->get_challenge(gensec_ntlmssp_state, cryptkey);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge: %s\n",
+ nt_errstr(status)));
+ return status;
}
/* Check if we may set the challenge */
@@ -180,7 +182,6 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security,
/* This creates the 'blob' of names that appears at the end of the packet */
if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
char dnsdomname[MAXHOSTNAMELEN], dnsname[MAXHOSTNAMELEN];
- const char *target_name_dns = "";
/* Find out the DNS domain name */
dnsdomname[0] = '\0';
@@ -194,12 +195,6 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security,
}
strlower_m(dnsname);
- if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
- target_name_dns = dnsdomname;
- } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
- target_name_dns = dnsname;
- }
-
msrpc_gen(out_mem_ctx,
&struct_blob, "aaaaa",
MsvAvNbDomainName, target_name,
@@ -268,6 +263,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_ntlmssp_state *gensec_ntlms
}
/* zero these out */
+ data_blob_free(&gensec_ntlmssp_state->session_key);
data_blob_free(&gensec_ntlmssp_state->lm_resp);
data_blob_free(&gensec_ntlmssp_state->nt_resp);
data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);
@@ -406,6 +402,11 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
NTSTATUS nt_status;
DATA_BLOB session_key = data_blob(NULL, 0);
+ if (!(gensec_security->want_features
+ & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY))) {
+ return NT_STATUS_OK;
+ }
+
if (user_session_key)
dump_data_pw("USER session key:\n", user_session_key->data, user_session_key->length);
@@ -548,20 +549,15 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security,
const DATA_BLOB in, DATA_BLOB *out)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
- DATA_BLOB user_session_key = data_blob(NULL, 0);
- DATA_BLOB lm_session_key = data_blob(NULL, 0);
+ DATA_BLOB user_session_key = data_blob_null;
+ DATA_BLOB lm_session_key = data_blob_null;
NTSTATUS nt_status;
- TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
-
/* zero the outbound NTLMSSP packet */
- *out = data_blob_talloc(out_mem_ctx, NULL, 0);
+ *out = data_blob_null;
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(gensec_ntlmssp_state, in))) {
- talloc_free(mem_ctx);
+ nt_status = ntlmssp_server_preauth(gensec_ntlmssp_state, in);
+ if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
@@ -573,23 +569,21 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security,
*/
/* Finally, actually ask if the password is OK */
-
- if (!NT_STATUS_IS_OK(nt_status = gensec_ntlmssp_state->check_password(gensec_ntlmssp_state, mem_ctx,
- &user_session_key, &lm_session_key))) {
- talloc_free(mem_ctx);
+ nt_status = gensec_ntlmssp_state->check_password(gensec_ntlmssp_state,
+ &user_session_key,
+ &lm_session_key);
+ if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
-
- if (gensec_security->want_features
- & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY)) {
- nt_status = ntlmssp_server_postauth(gensec_security, &user_session_key, &lm_session_key);
- talloc_free(mem_ctx);
+
+ nt_status = ntlmssp_server_postauth(gensec_security,
+ &user_session_key,
+ &lm_session_key);
+ if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
- } else {
- gensec_ntlmssp_state->session_key = data_blob(NULL, 0);
- talloc_free(mem_ctx);
- return NT_STATUS_OK;
}
+
+ return NT_STATUS_OK;
}
/**
@@ -597,19 +591,19 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security,
* @return an 8 byte random challenge
*/
-static const uint8_t *auth_ntlmssp_get_challenge(const struct gensec_ntlmssp_state *gensec_ntlmssp_state)
+static NTSTATUS auth_ntlmssp_get_challenge(const struct gensec_ntlmssp_state *gensec_ntlmssp_state,
+ uint8_t chal[8])
{
NTSTATUS status;
- const uint8_t *chal;
- status = gensec_ntlmssp_state->auth_context->get_challenge(gensec_ntlmssp_state->auth_context, &chal);
+ status = gensec_ntlmssp_state->auth_context->get_challenge(gensec_ntlmssp_state->auth_context, chal);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("auth_ntlmssp_get_challenge: failed to get challenge: %s\n",
nt_errstr(status)));
- return NULL;
+ return status;
}
- return chal;
+ return NT_STATUS_OK;
}
/**
@@ -651,12 +645,13 @@ static NTSTATUS auth_ntlmssp_set_challenge(struct gensec_ntlmssp_state *gensec_n
* Return the session keys used on the connection.
*/
-static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ntlmssp_state,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ntlmssp_state,
+ DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
{
NTSTATUS nt_status;
- struct auth_usersupplied_info *user_info = talloc(mem_ctx, struct auth_usersupplied_info);
+ struct auth_usersupplied_info *user_info;
+
+ user_info = talloc(gensec_ntlmssp_state, struct auth_usersupplied_info);
if (!user_info) {
return NT_STATUS_NO_MEMORY;
}
@@ -675,31 +670,21 @@ static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_
user_info->password.response.nt = gensec_ntlmssp_state->nt_resp;
user_info->password.response.nt.data = talloc_steal(user_info, gensec_ntlmssp_state->nt_resp.data);
- nt_status = gensec_ntlmssp_state->auth_context->check_password(gensec_ntlmssp_state->auth_context,
- mem_ctx,
- user_info,
+ nt_status = gensec_ntlmssp_state->auth_context->check_password(gensec_ntlmssp_state->auth_context,
+ gensec_ntlmssp_state,
+ user_info,
&gensec_ntlmssp_state->server_info);
talloc_free(user_info);
NT_STATUS_NOT_OK_RETURN(nt_status);
- talloc_steal(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info);
-
if (gensec_ntlmssp_state->server_info->user_session_key.length) {
- DEBUG(10, ("Got NT session key of length %u\n",
+ DEBUG(10, ("Got NT session key of length %u\n",
(unsigned)gensec_ntlmssp_state->server_info->user_session_key.length));
- if (!talloc_reference(mem_ctx, gensec_ntlmssp_state->server_info->user_session_key.data)) {
- return NT_STATUS_NO_MEMORY;
- }
-
*user_session_key = gensec_ntlmssp_state->server_info->user_session_key;
}
if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
- DEBUG(10, ("Got LM session key of length %u\n",
+ DEBUG(10, ("Got LM session key of length %u\n",
(unsigned)gensec_ntlmssp_state->server_info->lm_session_key.length));
- if (!talloc_reference(mem_ctx, gensec_ntlmssp_state->server_info->lm_session_key.data)) {
- return NT_STATUS_NO_MEMORY;
- }
-
*lm_session_key = gensec_ntlmssp_state->server_info->lm_session_key;
}
return nt_status;
diff --git a/source4/auth/ntlmssp/ntlmssp_sign.c b/source4/auth/ntlmssp/ntlmssp_sign.c
index 957d0a8fbc..9e0d80f788 100644
--- a/source4/auth/ntlmssp/ntlmssp_sign.c
+++ b/source4/auth/ntlmssp/ntlmssp_sign.c
@@ -171,7 +171,7 @@ NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
NTLMSSP_RECEIVE, &local_sig, true);
if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+ DEBUG(0, ("NTLMSSP packet sig creation failed with %s\n", nt_errstr(nt_status)));
return nt_status;
}
@@ -179,26 +179,25 @@ NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
if (local_sig.length != sig->length ||
memcmp(local_sig.data,
sig->data, sig->length) != 0) {
- DEBUG(5, ("BAD SIG NTLM2: wanted signature over %llu bytes of input:\n", (unsigned long long)pdu_length));
- dump_data(5, local_sig.data, local_sig.length);
+
+ DEBUG(10, ("BAD SIG NTLM2: wanted signature over %llu bytes of input:\n", (unsigned long long)pdu_length));
+ dump_data(10, local_sig.data, local_sig.length);
- DEBUG(5, ("BAD SIG: got signature over %llu bytes of input:\n", (unsigned long long)pdu_length));
- dump_data(5, sig->data, sig->length);
+ DEBUG(10, ("BAD SIG: got signature over %llu bytes of input:\n", (unsigned long long)pdu_length));
+ dump_data(10, sig->data, sig->length);
- DEBUG(1, ("NTLMSSP NTLM2 packet check failed due to invalid signature on %llu bytes of input!\n", (unsigned long long)pdu_length));
return NT_STATUS_ACCESS_DENIED;
}
} else {
if (local_sig.length != sig->length ||
memcmp(local_sig.data + 8,
sig->data + 8, sig->length - 8) != 0) {
- DEBUG(5, ("BAD SIG NTLM1: wanted signature of %llu bytes of input:\n", (unsigned long long)length));
+ DEBUG(10, ("BAD SIG NTLM1: wanted signature of %llu bytes of input:\n", (unsigned long long)length));
dump_data(5, local_sig.data, local_sig.length);
- DEBUG(5, ("BAD SIG: got signature of %llu bytes of input:\n", (unsigned long long)length));
- dump_data(5, sig->data, sig->length);
+ DEBUG(10, ("BAD SIG: got signature of %llu bytes of input:\n", (unsigned long long)length));
+ dump_data(10, sig->data, sig->length);
- DEBUG(1, ("NTLMSSP NTLM1 packet check failed due to invalid signature on %llu bytes of input:\n", (unsigned long long)length));
return NT_STATUS_ACCESS_DENIED;
}
}
@@ -281,6 +280,7 @@ NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
const uint8_t *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig)
{
+ NTSTATUS status;
struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
if (!gensec_ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot unseal packet\n"));
@@ -294,7 +294,12 @@ NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
arcfour_crypt_sbox(gensec_ntlmssp_state->crypt.ntlm.arcfour_state, data, length);
}
dump_data_pw("ntlmssp clear data\n", data, length);
- return gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig);
+ status = gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("NTLMSSP packet check for unseal failed due to invalid signature on %llu bytes of input:\n", (unsigned long long)length));
+ }
+ return status;
}
/**
@@ -585,6 +590,10 @@ NTSTATUS gensec_ntlmssp_unwrap(struct gensec_security *gensec_security,
status = check_status;
}
}
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("NTLMSSP packet check for unwrap failed due to invalid signature\n"));
+ }
return status;
} else {
*out = *in;
diff --git a/source4/build/smb_build/summary.pm b/source4/build/smb_build/summary.pm
index 153c3e20e9..09f5ff83ce 100644
--- a/source4/build/smb_build/summary.pm
+++ b/source4/build/smb_build/summary.pm
@@ -65,6 +65,7 @@ sub show($$)
showisexternal($output, "tdb", "LIBTDB");
showisexternal($output, "tevent", "LIBTEVENT");
showisexternal($output, "ldb", "LIBLDB");
+ showisexternal($output, "heimdal", "HEIMDAL_KRB5");
print "Developer mode: ".(enabled($config->{developer})?"yes":"no")."\n";
print "Automatic dependencies: ".
(enabled($config->{automatic_dependencies})
diff --git a/source4/dsdb/common/dsdb_dn.c b/source4/dsdb/common/dsdb_dn.c
index 660eaf7d40..9023b0347a 100644
--- a/source4/dsdb/common/dsdb_dn.c
+++ b/source4/dsdb/common/dsdb_dn.c
@@ -325,3 +325,72 @@ int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx,
{
return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2);
}
+
+
+/*
+ convert a dsdb_dn to a linked attribute data blob
+*/
+WERROR dsdb_dn_la_to_blob(struct ldb_context *sam_ctx,
+ const struct dsdb_attribute *schema_attrib,
+ const struct dsdb_schema *schema,
+ TALLOC_CTX *mem_ctx,
+ struct dsdb_dn *dsdb_dn, DATA_BLOB **blob)
+{
+ struct ldb_val v;
+ WERROR werr;
+ struct ldb_message_element val_el;
+ struct drsuapi_DsReplicaAttribute drs;
+
+ /* we need a message_element with just one value in it */
+ v = data_blob_string_const(dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1));
+
+ val_el.name = schema_attrib->lDAPDisplayName;
+ val_el.values = &v;
+ val_el.num_values = 1;
+
+ werr = schema_attrib->syntax->ldb_to_drsuapi(sam_ctx, schema, schema_attrib, &val_el, mem_ctx, &drs);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (drs.value_ctr.num_values != 1) {
+ DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s\n",
+ schema_attrib->lDAPDisplayName));
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ *blob = drs.value_ctr.values[0].blob;
+ return WERR_OK;
+}
+
+/*
+ convert a data blob to a dsdb_dn
+ */
+WERROR dsdb_dn_la_from_blob(struct ldb_context *sam_ctx,
+ const struct dsdb_attribute *schema_attrib,
+ const struct dsdb_schema *schema,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct dsdb_dn **dsdb_dn)
+{
+ WERROR werr;
+ struct ldb_message_element new_el;
+ struct drsuapi_DsReplicaAttribute drs;
+ struct drsuapi_DsAttributeValue val;
+
+ drs.value_ctr.num_values = 1;
+ drs.value_ctr.values = &val;
+ val.blob = blob;
+
+ werr = schema_attrib->syntax->drsuapi_to_ldb(sam_ctx, schema, schema_attrib, &drs, mem_ctx, &new_el);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (new_el.num_values != 1) {
+ return WERR_INTERNAL_ERROR;
+ }
+
+ *dsdb_dn = dsdb_dn_parse(mem_ctx, sam_ctx, &new_el.values[0], schema_attrib->syntax->ldap_oid);
+ if (!*dsdb_dn) {
+ return WERR_INTERNAL_ERROR;
+ }
+
+ return WERR_OK;
+}
diff --git a/source4/dsdb/common/dsdb_dn.h b/source4/dsdb/common/dsdb_dn.h
index 53e10535c8..b713bdd27b 100644
--- a/source4/dsdb/common/dsdb_dn.h
+++ b/source4/dsdb/common/dsdb_dn.h
@@ -15,3 +15,8 @@ struct dsdb_dn {
#define DSDB_SYNTAX_BINARY_DN "1.2.840.113556.1.4.903"
#define DSDB_SYNTAX_STRING_DN "1.2.840.113556.1.4.904"
#define DSDB_SYNTAX_OR_NAME "1.2.840.113556.1.4.1221"
+
+
+/* RMD_FLAGS component in a DN */
+#define DSDB_RMD_FLAG_DELETED 1
+#define DSDB_RMD_FLAG_INVISIBLE 2
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 61d065b85c..b8ba26a4ec 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -997,6 +997,81 @@ int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_m
}
/*
+ * Handle ldb_request in transaction
+ */
+static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
+ struct ldb_request *req)
+{
+ int ret;
+
+ ret = ldb_transaction_start(sam_ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(sam_ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ return ldb_transaction_commit(sam_ldb);
+ }
+ ldb_transaction_cancel(sam_ldb);
+
+ return ret;
+}
+
+/*
+ * replace elements in a record using LDB_CONTROL_AS_SYSTEM
+ * used to skip access checks on operations
+ * that are performed by the system
+ */
+int samdb_replace_as_system(struct ldb_context *sam_ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg)
+{
+ int i;
+ int ldb_ret;
+ struct ldb_request *req = NULL;
+
+ /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
+ for (i=0;i<msg->num_elements;i++) {
+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+
+ ldb_ret = ldb_msg_sanity_check(sam_ldb, msg);
+ if (ldb_ret != LDB_SUCCESS) {
+ return ldb_ret;
+ }
+
+ ldb_ret = ldb_build_mod_req(&req, sam_ldb, mem_ctx,
+ msg,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ldb_ret != LDB_SUCCESS) {
+ talloc_free(req);
+ return ldb_ret;
+ }
+
+ ldb_ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
+ if (ldb_ret != LDB_SUCCESS) {
+ talloc_free(req);
+ return ldb_ret;
+ }
+
+ /* do request and auto start a transaction */
+ ldb_ret = dsdb_autotransaction_request(sam_ldb, req);
+
+ talloc_free(req);
+ return ldb_ret;
+}
+
+/*
return a default security descriptor
*/
struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
@@ -1986,7 +2061,7 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA
{
struct ldb_message *msg;
struct ldb_dn *basedn;
- const char *sidstr;
+ char *sidstr;
int ret;
sidstr = dom_sid_string(mem_ctx, sid);
@@ -1995,45 +2070,47 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA
/* We might have to create a ForeignSecurityPrincipal, even if this user
* is in our own domain */
- msg = ldb_msg_new(mem_ctx);
+ msg = ldb_msg_new(sidstr);
if (msg == NULL) {
+ talloc_free(sidstr);
return NT_STATUS_NO_MEMORY;
}
- /* TODO: Hmmm. This feels wrong. How do I find the base dn to
- * put the ForeignSecurityPrincipals? d_state->domain_dn does
- * not work, this is wrong for the Builtin domain, there's no
- * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
- */
-
- basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
- "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
-
- if (basedn == NULL) {
+ ret = dsdb_wellknown_dn(sam_ctx, sidstr, samdb_base_dn(sam_ctx),
+ DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
+ &basedn);
+ if (ret != LDB_SUCCESS) {
DEBUG(0, ("Failed to find DN for "
- "ForeignSecurityPrincipal container\n"));
+ "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
+ talloc_free(sidstr);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
/* add core elements to the ldb_message for the alias */
- msg->dn = ldb_dn_copy(mem_ctx, basedn);
- if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
+ msg->dn = basedn;
+ if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
+ talloc_free(sidstr);
return NT_STATUS_NO_MEMORY;
+ }
- samdb_msg_add_string(sam_ctx, mem_ctx, msg,
+ samdb_msg_add_string(sam_ctx, msg, msg,
"objectClass",
"foreignSecurityPrincipal");
/* create the alias */
ret = ldb_add(sam_ctx, msg);
- if (ret != 0) {
+ if (ret != LDB_SUCCESS) {
DEBUG(0,("Failed to create foreignSecurityPrincipal "
"record %s: %s\n",
ldb_dn_get_linearized(msg->dn),
ldb_errstring(sam_ctx)));
+ talloc_free(sidstr);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- *ret_dn = msg->dn;
+
+ *ret_dn = talloc_steal(mem_ctx, msg->dn);
+ talloc_free(sidstr);
+
return NT_STATUS_OK;
}
@@ -2072,14 +2149,16 @@ struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_c
if (!ldb_dn_validate(dn)) {
DEBUG(2, ("Failed to validated DN %s\n",
ldb_dn_get_linearized(dn)));
+ talloc_free(tmp_ctx);
return NULL;
}
+ talloc_free(tmp_ctx);
return dn;
}
+
/*
Find the DN of a domain, be it the netbios or DNS name
*/
-
struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
const char *domain_name)
{
@@ -2151,13 +2230,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
return LDB_ERR_OPERATIONS_ERROR;
}
- res = talloc_zero(mem_ctx, struct ldb_result);
+ res = talloc_zero(expression, struct ldb_result);
if (!res) {
DEBUG(0, (__location__ ": out of memory\n"));
+ talloc_free(expression);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
+ ret = ldb_build_search_req(&search_req, ldb, expression,
ldb_get_default_basedn(ldb),
LDB_SCOPE_SUBTREE,
expression, attrs,
@@ -2165,6 +2245,7 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
res, ldb_search_default_callback,
NULL);
if (ret != LDB_SUCCESS) {
+ talloc_free(expression);
return ret;
}
@@ -2173,12 +2254,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
options = talloc(search_req, struct ldb_search_options_control);
if (options == NULL) {
DEBUG(0, (__location__ ": out of memory\n"));
+ talloc_free(expression);
return LDB_ERR_OPERATIONS_ERROR;
}
options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
if (ret != LDB_SUCCESS) {
+ talloc_free(expression);
return ret;
}
@@ -2186,16 +2269,19 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
LDB_CONTROL_SEARCH_OPTIONS_OID,
true, options);
if (ret != LDB_SUCCESS) {
+ talloc_free(expression);
return ret;
}
ret = ldb_request(ldb, search_req);
if (ret != LDB_SUCCESS) {
+ talloc_free(expression);
return ret;
}
ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
if (ret != LDB_SUCCESS) {
+ talloc_free(expression);
return ret;
}
@@ -2203,10 +2289,12 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
partitions module that can return two here with the
search_options control set */
if (res->count < 1) {
+ talloc_free(expression);
return LDB_ERR_NO_SUCH_OBJECT;
}
- *dn = res->msgs[0]->dn;
+ *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
+ talloc_free(expression);
return LDB_SUCCESS;
}
@@ -2229,6 +2317,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
+ talloc_free(tmp_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -2248,6 +2337,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
return ret;
}
@@ -2256,8 +2346,8 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
- talloc_free(req);
*_res = talloc_steal(mem_ctx, res);
+ talloc_free(tmp_ctx);
return ret;
}
@@ -2720,13 +2810,32 @@ int dsdb_functional_level(struct ldb_context *ldb)
}
/*
+ set a GUID in an extended DN structure
+ */
+int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
+{
+ struct ldb_val v;
+ NTSTATUS status;
+ int ret;
+
+ status = GUID_to_ndr_blob(guid, dn, &v);
+ if (!NT_STATUS_IS_OK(status)) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ ret = ldb_dn_set_extended_component(dn, component_name, &v);
+ data_blob_free(&v);
+ return ret;
+}
+
+/*
return a GUID from a extended DN structure
*/
-NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid)
+NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
{
const struct ldb_val *v;
- v = ldb_dn_get_extended_component(dn, "GUID");
+ v = ldb_dn_get_extended_component(dn, component_name);
if (v == NULL) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -2735,17 +2844,111 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid)
}
/*
+ return a uint64_t from a extended DN structure
+ */
+NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
+{
+ const struct ldb_val *v;
+ char *s;
+
+ v = ldb_dn_get_extended_component(dn, component_name);
+ if (v == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ s = talloc_strndup(dn, (const char *)v->data, v->length);
+ NT_STATUS_HAVE_NO_MEMORY(s);
+
+ *val = strtoull(s, NULL, 0);
+
+ talloc_free(s);
+ return NT_STATUS_OK;
+}
+
+/*
+ return a NTTIME from a extended DN structure
+ */
+NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
+{
+ return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
+}
+
+/*
+ return a uint32_t from a extended DN structure
+ */
+NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
+{
+ const struct ldb_val *v;
+ char *s;
+
+ v = ldb_dn_get_extended_component(dn, component_name);
+ if (v == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ s = talloc_strndup(dn, (const char *)v->data, v->length);
+ NT_STATUS_HAVE_NO_MEMORY(s);
+
+ *val = strtoul(s, NULL, 0);
+
+ talloc_free(s);
+ return NT_STATUS_OK;
+}
+
+/*
+ return RMD_FLAGS directly from a ldb_dn
+ returns 0 if not found
+ */
+uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
+{
+ const struct ldb_val *v;
+ char buf[32];
+ v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
+ if (!v || v->length > sizeof(buf)-1) return 0;
+ strncpy(buf, (const char *)v->data, v->length);
+ buf[v->length] = 0;
+ return strtoul(buf, NULL, 10);
+}
+
+/*
+ return RMD_FLAGS directly from a ldb_val for a DN
+ returns 0 if RMD_FLAGS is not found
+ */
+uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val)
+{
+ const char *p;
+ uint32_t flags;
+ char *end;
+
+ if (val->length < 13) {
+ return 0;
+ }
+ p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
+ if (!p) {
+ return 0;
+ }
+ flags = strtoul(p+11, &end, 10);
+ if (!end || *end != '>') {
+ /* it must end in a > */
+ return 0;
+ }
+ return flags;
+}
+
+/*
return true if a ldb_val containing a DN in storage form is deleted
*/
bool dsdb_dn_is_deleted_val(struct ldb_val *val)
{
- /* this relies on the sort order and exact format of
- linearized extended DNs */
- if (val->length >= 12 &&
- strncmp((const char *)val->data, "<DELETED=1>;", 12) == 0) {
- return true;
- }
- return false;
+ return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
+}
+
+/*
+ return true if a ldb_val containing a DN in storage form is
+ in the upgraded w2k3 linked attribute format
+ */
+bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
+{
+ return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
}
/*
@@ -2870,3 +3073,29 @@ int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
talloc_free(nc_root);
return ret;
}
+
+/*
+ return the tombstoneLifetime, in days
+ */
+int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
+{
+ struct ldb_dn *dn;
+ dn = samdb_config_dn(ldb);
+ if (!dn) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ dn = ldb_dn_copy(ldb, dn);
+ if (!dn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
+ be a wellknown GUID for this */
+ if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT")) {
+ talloc_free(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
+ talloc_free(dn);
+ return LDB_SUCCESS;
+}
diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk
index dfc5def64e..35a0c84903 100644
--- a/source4/dsdb/config.mk
+++ b/source4/dsdb/config.mk
@@ -22,7 +22,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/samdb_proto.h,$(SAMDB_OB
# PUBLIC_HEADERS += dsdb/samdb/samdb.h
[SUBSYSTEM::SAMDB_COMMON]
-PRIVATE_DEPENDENCIES = LIBLDB
+PRIVATE_DEPENDENCIES = LIBLDB NDR_DRSBLOBS LIBCLI_LDAP_NDR UTIL_LDB LIBCLI_AUTH
SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \
util.o \
@@ -31,7 +31,7 @@ SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \
$(eval $(call proto_header_template,$(dsdbsrcdir)/common/proto.h,$(SAMDB_COMMON_OBJ_FILES:.o=.c)))
[SUBSYSTEM::SAMDB_SCHEMA]
-PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS
+PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS LDBSAMBA
SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \
schema_init.o \
@@ -83,6 +83,7 @@ PRIVATE_DEPENDENCIES = \
KCC_SRV_OBJ_FILES = $(addprefix $(dsdbsrcdir)/kcc/, \
kcc_service.o \
kcc_connection.o \
+ kcc_deleted.o \
kcc_periodic.o)
$(eval $(call proto_header_template,$(dsdbsrcdir)/kcc/kcc_service_proto.h,$(KCC_SRV_OBJ_FILES:.o=.c)))
diff --git a/source4/dsdb/kcc/kcc_connection.c b/source4/dsdb/kcc/kcc_connection.c
index ee9a05a21e..73198040c4 100644
--- a/source4/dsdb/kcc/kcc_connection.c
+++ b/source4/dsdb/kcc/kcc_connection.c
@@ -133,7 +133,7 @@ void kccsrv_apply_connections(struct kccsrv_service *s,
{
int i, j, deleted = 0, added = 0, ret;
- for (i = 0; i < ntds_list->count; i++) {
+ for (i = 0; ntds_list && i < ntds_list->count; i++) {
struct kcc_connection *ntds = &ntds_list->servers[i];
for (j = 0; j < dsa_list->count; j++) {
struct kcc_connection *dsa = &dsa_list->servers[j];
@@ -152,13 +152,13 @@ void kccsrv_apply_connections(struct kccsrv_service *s,
for (i = 0; i < dsa_list->count; i++) {
struct kcc_connection *dsa = &dsa_list->servers[i];
- for (j = 0; j < ntds_list->count; j++) {
+ for (j = 0; ntds_list && j < ntds_list->count; j++) {
struct kcc_connection *ntds = &ntds_list->servers[j];
if (GUID_equal(&dsa->dsa_guid, &ntds->dsa_guid)) {
break;
}
}
- if (j == ntds_list->count) {
+ if (ntds_list == NULL || j == ntds_list->count) {
ret = kccsrv_add_connection(s, dsa);
if (ret == LDB_SUCCESS) {
added++;
diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c
new file mode 100644
index 0000000000..d19ac0cac2
--- /dev/null
+++ b/source4/dsdb/kcc/kcc_deleted.c
@@ -0,0 +1,156 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ handle removal of deleted objects
+
+ Copyright (C) 2009 Andrew Tridgell
+
+ 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 "dsdb/samdb/samdb.h"
+#include "auth/auth.h"
+#include "smbd/service.h"
+#include "lib/messaging/irpc.h"
+#include "dsdb/kcc/kcc_connection.h"
+#include "dsdb/kcc/kcc_service.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "../lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "param/param.h"
+
+/*
+ onelevel search with SHOW_DELETED control
+ */
+static int search_onelevel_with_deleted(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **_res,
+ struct ldb_dn *basedn,
+ const char * const *attrs)
+{
+ struct ldb_request *req;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ int ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req(&req, ldb, tmp_ctx,
+ basedn,
+ LDB_SCOPE_ONELEVEL,
+ NULL,
+ attrs,
+ NULL,
+ res,
+ ldb_search_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(req);
+ *_res = talloc_steal(mem_ctx, res);
+ return ret;
+}
+
+/*
+ check to see if any deleted objects need scavenging
+ */
+NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx)
+{
+ struct kccsrv_partition *part;
+ int ret;
+ uint32_t tombstoneLifetime;
+
+ time_t t = time(NULL);
+ if (t - s->last_deleted_check < lp_parm_int(s->task->lp_ctx, NULL, "kccsrv",
+ "check_deleted_interval", 600)) {
+ return NT_STATUS_OK;
+ }
+ s->last_deleted_check = t;
+
+ ret = dsdb_tombstone_lifetime(s->samdb, &tombstoneLifetime);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,(__location__ ": Failed to get tombstone lifetime\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ for (part=s->partitions; part; part=part->next) {
+ struct ldb_dn *do_dn;
+ struct ldb_result *res;
+ const char *attrs[] = { "whenChanged", NULL };
+ int i;
+
+ ret = dsdb_get_deleted_objects_dn(s->samdb, mem_ctx, part->dn, &do_dn);
+ if (ret != LDB_SUCCESS) {
+ /* some partitions have no Deleted Objects
+ container */
+ continue;
+ }
+ ret = search_onelevel_with_deleted(s->samdb, do_dn, &res, do_dn, attrs);
+
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,(__location__ ": Failed to search for deleted objects in %s\n",
+ ldb_dn_get_linearized(do_dn)));
+ talloc_free(do_dn);
+ continue;
+ }
+
+ for (i=0; i<res->count; i++) {
+ const char *tstring;
+ time_t whenChanged = 0;
+
+ tstring = samdb_result_string(res->msgs[i], "whenChanged", NULL);
+ if (tstring) {
+ whenChanged = ldb_string_to_time(tstring);
+ }
+ if (t - whenChanged > tombstoneLifetime*60*60*24) {
+ ret = ldb_delete(s->samdb, res->msgs[i]->dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn)));
+ } else {
+ DEBUG(4,("Removed deleted object %s\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn)));
+ }
+ }
+ }
+
+ talloc_free(do_dn);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c
index d24e5e90a5..3b0d8a0551 100644
--- a/source4/dsdb/kcc/kcc_periodic.c
+++ b/source4/dsdb/kcc/kcc_periodic.c
@@ -257,5 +257,10 @@ static void kccsrv_periodic_run(struct kccsrv_service *service)
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("kccsrv_simple_update failed - %s\n", nt_errstr(status)));
}
+
+ status = kccsrv_check_deleted(service, mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("kccsrv_check_deleted failed - %s\n", nt_errstr(status)));
+ }
talloc_free(mem_ctx);
}
diff --git a/source4/dsdb/kcc/kcc_service.h b/source4/dsdb/kcc/kcc_service.h
index 6a78d37a91..b4ce37bfc5 100644
--- a/source4/dsdb/kcc/kcc_service.h
+++ b/source4/dsdb/kcc/kcc_service.h
@@ -78,6 +78,8 @@ struct kccsrv_service {
/* here we have a reference to the timed event the schedules the periodic stuff */
struct tevent_timer *te;
} periodic;
+
+ time_t last_deleted_check;
};
#include "dsdb/kcc/kcc_service_proto.h"
diff --git a/source4/dsdb/repl/drepl_notify.c b/source4/dsdb/repl/drepl_notify.c
index e8652dcaf1..fe3b2d2497 100644
--- a/source4/dsdb/repl/drepl_notify.c
+++ b/source4/dsdb/repl/drepl_notify.c
@@ -404,7 +404,7 @@ WERROR dreplsrv_notify_schedule(struct dreplsrv_service *service, uint32_t next_
W_ERROR_HAVE_NO_MEMORY(new_te);
tmp_mem = talloc_new(service);
- DEBUG(2,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n",
+ DEBUG(4,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n",
next_interval,
(service->notify.te?"re":""),
nt_time_string(tmp_mem, timeval_to_nttime(&next_time))));
diff --git a/source4/dsdb/repl/drepl_partitions.c b/source4/dsdb/repl/drepl_partitions.c
index 85412a793c..5b8227e7de 100644
--- a/source4/dsdb/repl/drepl_partitions.c
+++ b/source4/dsdb/repl/drepl_partitions.c
@@ -39,16 +39,15 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
struct ldb_dn *basedn;
struct ldb_result *r;
struct ldb_message_element *el;
- static const char *attrs[] = { "namingContexts", NULL };
+ static const char *attrs[] = { "hasMasterNCs", NULL };
uint32_t i;
int ret;
- basedn = ldb_dn_new(s, s->samdb, NULL);
+ basedn = samdb_ntds_settings_dn(s->samdb);
W_ERROR_HAVE_NO_MEMORY(basedn);
ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
"(objectClass=*)");
- talloc_free(basedn);
if (ret != LDB_SUCCESS) {
return WERR_FOOBAR;
} else if (r->count != 1) {
@@ -56,7 +55,7 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
return WERR_FOOBAR;
}
- el = ldb_msg_find_element(r->msgs[0], "namingContexts");
+ el = ldb_msg_find_element(r->msgs[0], "hasMasterNCs");
if (!el) {
return WERR_FOOBAR;
}
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 1efbd29d93..c72b107b75 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -128,15 +128,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
}
status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
- if (!NT_STATUS_IS_OK(status) && a->value_ctr.num_values == 0) {
- /* w2k8-r2 occasionally sends bogus empty
- attributes with rubbish attribute IDs. The
- only think we can do is discard these */
- DEBUG(0,(__location__ ": Discarding bogus empty DsReplicaAttribute with attid 0x%x\n",
- a->attid));
- ZERO_STRUCTP(e);
- continue;
- }
W_ERROR_NOT_OK_RETURN(status);
m->attid = a->attid;
@@ -157,14 +148,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
}
}
- /* delete any empty elements */
- for (i=0; i < msg->num_elements; i++) {
- if (msg->elements[i].name == NULL) {
- ldb_msg_remove_element(msg, &msg->elements[i]);
- i--;
- }
- }
-
if (rdn_m) {
struct ldb_message_element *el;
el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
@@ -319,7 +302,8 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
ret = ldb_transaction_prepare_commit(ldb);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ " Failed to prepare commit of transaction\n"));
+ DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
+ ldb_errstring(ldb)));
return WERR_FOOBAR;
}
diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk
index 3bd38606ea..6128dc9d65 100644
--- a/source4/dsdb/samdb/ldb_modules/config.mk
+++ b/source4/dsdb/samdb/ldb_modules/config.mk
@@ -1,7 +1,7 @@
################################################
# Start SUBSYSTEM DSDB_MODULE_HELPERS
[SUBSYSTEM::DSDB_MODULE_HELPERS]
-PRIVATE_DEPENDENCIES = LIBLDB
+PRIVATE_DEPENDENCIES = LIBLDB LIBNDR SAMDB_SCHEMA
DSDB_MODULE_HELPERS_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/util.o
@@ -12,7 +12,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/util_proto.h
# Start MODULE ldb_samba_dsdb
[MODULE::ldb_samba_dsdb]
SUBSYSTEM = LIBLDB
-PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR
+PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR DSDB_MODULE_HELPERS
INIT_FUNCTION = LDB_MODULE(samba_dsdb)
# End MODULE ldb_samba_dsdb
################################################
@@ -119,7 +119,7 @@ ldb_pdc_fsmo_OBJ_FILES = \
# Start MODULE ldb_samldb
[MODULE::ldb_samldb]
SUBSYSTEM = LIBLDB
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB DSDB_MODULE_HELPERS
INIT_FUNCTION = LDB_MODULE(samldb)
#
# End MODULE ldb_samldb
@@ -242,7 +242,7 @@ ldb_extended_dn_out_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_out.
# Start MODULE ldb_extended_dn_store
[MODULE::ldb_extended_dn_store]
SUBSYSTEM = LIBLDB
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB DSDB_MODULE_HELPERS
INIT_FUNCTION = LDB_MODULE(extended_dn_store)
# End MODULE ldb_extended_dn_store
################################################
@@ -301,7 +301,7 @@ ldb_update_keytab_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/update_keytab.o
[MODULE::ldb_objectclass]
INIT_FUNCTION = LDB_MODULE(objectclass)
CFLAGS = -Ilib/ldb/include
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB DSDB_MODULE_HELPERS LIBSAMBA-UTIL
SUBSYSTEM = LIBLDB
# End MODULE ldb_objectclass
################################################
@@ -325,7 +325,7 @@ ldb_subtree_rename_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/subtree_rename.o
[MODULE::ldb_subtree_delete]
INIT_FUNCTION = LDB_MODULE(subtree_delete)
CFLAGS = -Ilib/ldb/include
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL DSDB_MODULE_HELPERS
SUBSYSTEM = LIBLDB
# End MODULE ldb_subtree_rename
################################################
@@ -385,7 +385,7 @@ ldb_instancetype_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/instancetype.o
[MODULE::ldb_operational]
SUBSYSTEM = LIBLDB
CFLAGS = -Ilib/ldb/include
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBSAMBA-UTIL SAMDB_COMMON DSDB_MODULE_HELPERS
INIT_FUNCTION = LDB_MODULE(operational)
# End MODULE ldb_operational
################################################
@@ -397,7 +397,8 @@ ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o
[MODULE::ldb_descriptor]
INIT_FUNCTION = LDB_MODULE(descriptor)
CFLAGS = -Ilib/ldb/include
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB \
+ DSDB_MODULE_HELPERS
SUBSYSTEM = LIBLDB
# End MODULE ldb_descriptor
################################################
diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c
index d5a5e36e0e..f07743c4a2 100644
--- a/source4/dsdb/samdb/ldb_modules/descriptor.c
+++ b/source4/dsdb/samdb/ldb_modules/descriptor.c
@@ -285,6 +285,14 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
if (!final_sd) {
return NULL;
}
+
+ if (final_sd->dacl) {
+ final_sd->dacl->revision = SECURITY_ACL_REVISION_ADS;
+ }
+ if (final_sd->sacl) {
+ final_sd->sacl->revision = SECURITY_ACL_REVISION_ADS;
+ }
+
sddl_sd = sddl_encode(mem_ctx, final_sd, domain_sid);
DEBUG(10, ("Object %s created with desriptor %s\n\n", ldb_dn_get_linearized(dn), sddl_sd));
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
index 89ba7bb04b..33931167c5 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
@@ -34,6 +34,11 @@
#include "ldb/include/ldb_errors.h"
#include "ldb/include/ldb_module.h"
+/*
+ TODO: if relax is not set then we need to reject the fancy RMD_* and
+ DELETED extended DN codes
+ */
+
/* search */
struct extended_search_context {
struct ldb_module *module;
diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
index f54693d809..4c326bc240 100644
--- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c
+++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
@@ -33,1227 +33,155 @@
#include "dlinklist.h"
#include "dsdb/samdb/samdb.h"
#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/ldb_modules/util.h"
-struct la_private {
- struct la_context *la_list;
-};
-
-struct la_op_store {
- struct la_op_store *next;
- struct la_op_store *prev;
- enum la_op {LA_OP_ADD, LA_OP_DEL} op;
- struct GUID guid;
- char *name;
- char *value;
-};
-
-struct replace_context {
- struct la_context *ac;
- unsigned int num_elements;
- struct ldb_message_element *el;
-};
-
-struct la_context {
- struct la_context *next, *prev;
- const struct dsdb_schema *schema;
- struct ldb_module *module;
- struct ldb_request *req;
- struct ldb_dn *partition_dn;
- struct ldb_dn *add_dn;
- struct ldb_dn *del_dn;
- struct replace_context *rc;
- struct la_op_store *ops;
- struct ldb_extended *op_response;
- struct ldb_control **op_controls;
-};
-
-static struct la_context *linked_attributes_init(struct ldb_module *module,
- struct ldb_request *req)
-{
- struct ldb_context *ldb;
- struct la_context *ac;
- const struct ldb_control *partition_ctrl;
-
- ldb = ldb_module_get_ctx(module);
-
- ac = talloc_zero(req, struct la_context);
- if (ac == NULL) {
- ldb_oom(ldb);
- return NULL;
- }
-
- ac->schema = dsdb_get_schema(ldb);
- ac->module = module;
- ac->req = req;
-
- /* remember the partition DN that came in, if given */
- partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
- if (partition_ctrl) {
- const struct dsdb_control_current_partition *partition;
- partition = talloc_get_type(partition_ctrl->data,
- struct dsdb_control_current_partition);
- SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
-
- ac->partition_dn = ldb_dn_copy(ac, partition->dn);
- }
-
- return ac;
-}
-/*
- turn a DN into a GUID
- */
-static int la_guid_from_dn(struct la_context *ac, struct ldb_dn *dn, struct GUID *guid)
+static int linked_attributes_fix_links(struct ldb_module *module,
+ struct ldb_dn *old_dn, struct ldb_dn *new_dn,
+ struct ldb_message_element *el, struct dsdb_schema *schema,
+ const struct dsdb_attribute *schema_attr)
{
- int ret;
- NTSTATUS status;
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const struct dsdb_attribute *target;
+ const char *attrs[2];
- status = dsdb_get_extended_dn_guid(dn, guid);
- if (NT_STATUS_IS_OK(status)) {
+ target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
+ if (target == NULL) {
+ /* there is no counterpart link to change */
return LDB_SUCCESS;
}
- if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
- DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
- ldb_dn_get_linearized(dn)));
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = dsdb_find_guid_by_dn(ldb_module_get_ctx(ac->module), dn, guid);
- if (ret != LDB_SUCCESS) {
- DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
- ldb_dn_get_linearized(dn)));
- return ret;
- }
- return LDB_SUCCESS;
-}
-
-
-/* Common routine to handle reading the attributes and creating a
- * series of modify requests */
-static int la_store_op(struct la_context *ac,
- enum la_op op, struct ldb_val *dn,
- const char *name)
-{
- struct ldb_context *ldb;
- struct la_op_store *os;
- struct ldb_dn *op_dn;
- int ret;
-
- ldb = ldb_module_get_ctx(ac->module);
-
- op_dn = ldb_dn_from_ldb_val(ac, ldb, dn);
- if (!op_dn) {
- ldb_asprintf_errstring(ldb,
- "could not parse attribute as a DN");
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
-
- os = talloc_zero(ac, struct la_op_store);
- if (!os) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- os->op = op;
-
- ret = la_guid_from_dn(ac, op_dn, &os->guid);
- if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
- /* we are deleting an object, and we've found it has a
- * forward link to a target that no longer
- * exists. This is not an error in the delete, and we
- * should just not do the deferred delete of the
- * target attribute
- */
- talloc_free(os);
- return LDB_SUCCESS;
- }
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- os->name = talloc_strdup(os, name);
- if (!os->name) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- /* Do deletes before adds */
- if (op == LA_OP_ADD) {
- DLIST_ADD_END(ac->ops, os, struct la_op_store *);
- } else {
- /* By adding to the head of the list, we do deletes before
- * adds when processing a replace */
- DLIST_ADD(ac->ops, os);
- }
-
- return LDB_SUCCESS;
-}
-
-static int la_op_search_callback(struct ldb_request *req,
- struct ldb_reply *ares);
-static int la_queue_mod_request(struct la_context *ac);
-static int la_down_req(struct la_context *ac);
-
-
-
-/* add */
-static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_context *ldb;
- const struct dsdb_attribute *target_attr;
- struct la_context *ac;
- const char *attr_name;
- int ret;
- int i, j;
-
- ldb = ldb_module_get_ctx(module);
-
- if (ldb_dn_is_special(req->op.add.message->dn)) {
- /* do not manipulate our control entries */
- return ldb_next_request(module, req);
- }
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ attrs[0] = target->lDAPDisplayName;
+ attrs[1] = NULL;
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- talloc_free(ac);
- return ldb_next_request(module, req);
- }
+ for (i=0; i<el->num_values; i++) {
+ struct dsdb_dn *dsdb_dn;
+ int ret, j;
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ struct ldb_message_element *el2;
- /* Need to ensure we only have forward links being specified */
- for (i=0; i < req->op.add.message->num_elements; i++) {
- const struct ldb_message_element *el = &req->op.add.message->elements[i];
- const struct dsdb_attribute *schema_attr
- = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute in schema", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
+ if (dsdb_dn == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
- /* We have a valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
- continue;
- }
-
- if ((schema_attr->linkID & 1) == 1) {
- /* Odd is for the target. Illegal to modify */
- ldb_asprintf_errstring(ldb,
- "attribute %s must not be modified directly, it is a linked attribute", el->name);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
- /* Even link IDs are for the originating attribute */
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
- if (!target_attr) {
- /*
- * windows 2003 has a broken schema where
- * the definition of msDS-IsDomainFor
- * is missing (which is supposed to be
- * the backlink of the msDS-HasDomainNCs
- * attribute
- */
- continue;
- }
-
- attr_name = target_attr->lDAPDisplayName;
- for (j = 0; j < el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_ADD,
- &el->values[j],
- attr_name);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn,
+ attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
+ DSDB_SEARCH_REVEAL_INTERNALS);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s",
+ el->name, target->lDAPDisplayName,
+ ldb_dn_get_linearized(old_dn),
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
}
- }
-
- /* if no linked attributes are present continue */
- if (ac->ops == NULL) {
- /* nothing to do for this module, proceed */
- talloc_free(ac);
- return ldb_next_request(module, req);
- }
-
- /* start with the original request */
- return la_down_req(ac);
-}
-
-/* For a delete or rename, we need to find out what linked attributes
- * are currently on this DN, and then deal with them. This is the
- * callback to the base search */
+ msg = res->msgs[0];
-static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- struct ldb_context *ldb;
- const struct dsdb_attribute *schema_attr;
- const struct dsdb_attribute *target_attr;
- struct ldb_message_element *search_el;
- struct replace_context *rc;
- struct la_context *ac;
- const char *attr_name;
- int i, j;
- int ret = LDB_SUCCESS;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
- rc = ac->rc;
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- /* Only entries are interesting, and we only want the olddn */
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
-
- if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
- ldb_asprintf_errstring(ldb,
- "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares->message->dn));
- /* Guh? We only asked for this DN */
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
+ if (msg->num_elements != 1 ||
+ ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
+ ldb_set_errstring(ldb, "Bad msg elements in linked_attributes_fix_links");
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ el2 = &msg->elements[0];
- ac->add_dn = ac->del_dn = talloc_steal(ac, ares->message->dn);
-
- /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
- for (i = 0; rc && i < rc->num_elements; i++) {
-
- schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute in schema",
- rc->el[i].name);
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OBJECT_CLASS_VIOLATION);
- }
-
- search_el = ldb_msg_find_element(ares->message,
- rc->el[i].name);
+ el2->flags = LDB_FLAG_MOD_REPLACE;
- /* See if this element already exists */
- /* otherwise just ignore as
- * the add has already been scheduled */
- if ( ! search_el) {
- continue;
+ /* find our DN in the values */
+ for (j=0; j<el2->num_values; j++) {
+ struct dsdb_dn *dsdb_dn2;
+ dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
+ if (dsdb_dn2 == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
-
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
- if (!target_attr) {
- /*
- * windows 2003 has a broken schema where
- * the definition of msDS-IsDomainFor
- * is missing (which is supposed to be
- * the backlink of the msDS-HasDomainNCs
- * attribute
- */
+ if (ldb_dn_compare(old_dn, dsdb_dn2->dn) != 0) {
continue;
}
- attr_name = target_attr->lDAPDisplayName;
-
- /* Now we know what was there, we can remove it for the re-add */
- for (j = 0; j < search_el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_DEL,
- &search_el->values[j],
- attr_name);
- if (ret != LDB_SUCCESS) {
- talloc_free(ares);
- return ldb_module_done(ac->req,
- NULL, NULL, ret);
- }
- }
- }
-
- break;
-
- case LDB_REPLY_REFERRAL:
- /* ignore */
- break;
-
- case LDB_REPLY_DONE:
-
- talloc_free(ares);
-
- if (ac->req->operation == LDB_ADD) {
- /* Start the modifies to the backlinks */
- ret = la_queue_mod_request(ac);
-
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
- } else {
- /* Start with the original request */
- ret = la_down_req(ac);
+ ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL, ret);
- }
- }
- return LDB_SUCCESS;
- }
-
- talloc_free(ares);
- return ret;
-}
-
-
-/* modify */
-static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
-{
- /* Look over list of modifications */
- /* Find if any are for linked attributes */
- /* Determine the effect of the modification */
- /* Apply the modify to the linked entry */
-
- struct ldb_context *ldb;
- int i, j;
- struct la_context *ac;
- struct ldb_request *search_req;
- const char **attrs;
-
- int ret;
-
- ldb = ldb_module_get_ctx(module);
-
- if (ldb_dn_is_special(req->op.mod.message->dn)) {
- /* do not manipulate our control entries */
- return ldb_next_request(module, req);
- }
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
-
- ac->rc = talloc_zero(ac, struct replace_context);
- if (!ac->rc) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- for (i=0; i < req->op.mod.message->num_elements; i++) {
- bool store_el = false;
- const char *attr_name;
- const struct dsdb_attribute *target_attr;
- const struct ldb_message_element *el = &req->op.mod.message->elements[i];
- const struct dsdb_attribute *schema_attr
- = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute in schema", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
- }
- /* We have a valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
- continue;
- }
-
- if ((schema_attr->linkID & 1) == 1) {
- /* Odd is for the target. Illegal to modify */
- ldb_asprintf_errstring(ldb,
- "attribute %s must not be modified directly, it is a linked attribute", el->name);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
- /* Even link IDs are for the originating attribute */
-
- /* Now find the target attribute */
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
- if (!target_attr) {
- /*
- * windows 2003 has a broken schema where
- * the definition of msDS-IsDomainFor
- * is missing (which is supposed to be
- * the backlink of the msDS-HasDomainNCs
- * attribute
- */
- continue;
- }
-
- attr_name = target_attr->lDAPDisplayName;
-
- switch (el->flags & LDB_FLAG_MOD_MASK) {
- case LDB_FLAG_MOD_REPLACE:
- /* treat as just a normal add the delete part is handled by the callback */
- store_el = true;
-
- /* break intentionally missing */
-
- case LDB_FLAG_MOD_ADD:
-
- /* For each value being added, we need to setup the adds */
- for (j = 0; j < el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_ADD,
- &el->values[j],
- attr_name);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
- break;
-
- case LDB_FLAG_MOD_DELETE:
-
- if (el->num_values) {
- /* For each value being deleted, we need to setup the delete */
- for (j = 0; j < el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_DEL,
- &el->values[j],
- attr_name);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
- } else {
- /* Flag that there was a DELETE
- * without a value specified, so we
- * need to look for the old value */
- store_el = true;
+ talloc_free(tmp_ctx);
+ return ret;
}
- break;
+ el2->values[j] = data_blob_string_const(
+ dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
}
- if (store_el) {
- struct ldb_message_element *search_el;
-
- search_el = talloc_realloc(ac->rc, ac->rc->el,
- struct ldb_message_element,
- ac->rc->num_elements +1);
- if (!search_el) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac->rc->el = search_el;
-
- ac->rc->el[ac->rc->num_elements] = *el;
- ac->rc->num_elements++;
- }
- }
-
- if (ac->ops || ac->rc->el) {
- /* both replace and delete without values are handled in the callback
- * after the search on the entry to be modified is performed */
-
- attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
- if (!attrs) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
- attrs[i] = ac->rc->el[i].name;
+ ret = dsdb_check_single_valued_link(target, el2);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
}
- attrs[i] = NULL;
-
- /* The callback does all the hard work here */
- ret = ldb_build_search_req(&search_req, ldb, ac,
- req->op.mod.message->dn,
- LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_mod_search_callback,
- req);
- /* We need to figure out our own extended DN, to fill in as the backlink target */
- if (ret == LDB_SUCCESS) {
- ret = ldb_request_add_control(search_req,
- LDB_CONTROL_EXTENDED_DN_OID,
- false, NULL);
- }
- if (ret == LDB_SUCCESS) {
- talloc_steal(search_req, attrs);
-
- ret = ldb_next_request(module, search_req);
+ ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
+ el->name, target->lDAPDisplayName,
+ ldb_dn_get_linearized(old_dn),
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
}
-
- } else {
- /* nothing to do for this module, proceed */
- talloc_free(ac);
- ret = ldb_next_request(module, req);
}
- return ret;
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
}
-/* delete */
-static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_context *ldb;
- struct ldb_request *search_req;
- struct la_context *ac;
- const char **attrs;
- WERROR werr;
- int ret;
-
- /* This gets complex: We need to:
- - Do a search for the entry
- - Wait for these result to appear
- - In the callback for the result, issue a modify
- request based on the linked attributes found
- - Wait for each modify result
- - Regain our sainity
- */
-
- ldb = ldb_module_get_ctx(module);
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
- if (!W_ERROR_IS_OK(werr)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req(&search_req, ldb, req,
- req->op.del.dn, LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_op_search_callback,
- req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(search_req, attrs);
-
- return ldb_next_request(module, search_req);
-}
/* rename */
static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
{
- struct la_context *ac;
-
- /* This gets complex: We need to:
- - Do a search for the entry
- - Wait for these result to appear
- - In the callback for the result, issue a modify
- request based on the linked attributes found
- - Wait for each modify result
- - Regain our sainity
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ int ret, i;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ /*
+ - load the current msg
+ - find any linked attributes
+ - if its a link then find the target object
+ - modify the target linked attributes with the new DN
*/
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
-
- /* start with the original request */
- return la_down_req(ac);
-}
-
-
-static int la_op_search_callback(struct ldb_request *req,
- struct ldb_reply *ares)
-{
- struct ldb_context *ldb;
- struct la_context *ac;
- const struct dsdb_attribute *schema_attr;
- const struct dsdb_attribute *target_attr;
- const struct ldb_message_element *el;
- const char *attr_name;
- int i, j;
- int ret;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- /* Only entries are interesting, and we only want the olddn */
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- ret = ldb_dn_compare(ares->message->dn, req->op.search.base);
- if (ret != 0) {
- /* Guh? We only asked for this DN */
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->message->num_elements == 0) {
- /* only bother at all if there were some
- * linked attributes found */
- talloc_free(ares);
- return LDB_SUCCESS;
- }
-
- switch (ac->req->operation) {
- case LDB_DELETE:
- ac->del_dn = talloc_steal(ac, ares->message->dn);
- break;
- case LDB_RENAME:
- ac->add_dn = talloc_steal(ac, ares->message->dn);
- ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn);
- break;
- default:
- talloc_free(ares);
- ldb_set_errstring(ldb,
- "operations must be delete or rename");
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- for (i = 0; i < ares->message->num_elements; i++) {
- el = &ares->message->elements[i];
-
- schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute"
- " in schema", el->name);
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OBJECT_CLASS_VIOLATION);
- }
-
- /* Valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
- /* Not a linked attribute, skip */
- continue;
- }
-
- if ((schema_attr->linkID & 1) == 0) {
- /* Odd is for the target. */
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
- if (!target_attr) {
- continue;
- }
- attr_name = target_attr->lDAPDisplayName;
- } else {
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1);
- if (!target_attr) {
- continue;
- }
- attr_name = target_attr->lDAPDisplayName;
- }
- for (j = 0; j < el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_DEL,
- &el->values[j],
- attr_name);
-
- /* for renames, ensure we add it back */
- if (ret == LDB_SUCCESS
- && ac->req->operation == LDB_RENAME) {
- ret = la_store_op(ac, LA_OP_ADD,
- &el->values[j],
- attr_name);
- }
- if (ret != LDB_SUCCESS) {
- talloc_free(ares);
- return ldb_module_done(ac->req,
- NULL, NULL, ret);
- }
- }
- }
-
- break;
-
- case LDB_REPLY_REFERRAL:
- /* ignore */
- break;
-
- case LDB_REPLY_DONE:
-
- talloc_free(ares);
-
-
- switch (ac->req->operation) {
- case LDB_DELETE:
- /* start the mod requests chain */
- ret = la_down_req(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL, ret);
- }
- return ret;
-
- case LDB_RENAME:
- /* start the mod requests chain */
- ret = la_queue_mod_request(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
- return ret;
-
- default:
- talloc_free(ares);
- ldb_set_errstring(ldb,
- "operations must be delete or rename");
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- }
-
- talloc_free(ares);
- return LDB_SUCCESS;
-}
-
-/* queue a linked attributes modify request in the la_private
- structure */
-static int la_queue_mod_request(struct la_context *ac)
-{
- struct la_private *la_private =
- talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
-
- if (la_private == NULL) {
- ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- talloc_steal(la_private, ac);
- DLIST_ADD(la_private->la_list, ac);
-
- return ldb_module_done(ac->req, ac->op_controls,
- ac->op_response, LDB_SUCCESS);
-}
-
-/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
-static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- int ret;
- struct la_context *ac;
- struct ldb_context *ldb;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- ldb_set_errstring(ldb,
- "invalid ldb_reply_type in callback");
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- ac->op_controls = talloc_steal(ac, ares->controls);
- ac->op_response = talloc_steal(ac, ares->response);
-
- /* If we have modfies to make, this is the time to do them for modify and delete */
- ret = la_queue_mod_request(ac);
-
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL, ret);
- }
- talloc_free(ares);
-
- /* la_queue_mod_request has already sent the callbacks */
- return LDB_SUCCESS;
-
-}
-
-/* Having done the original rename try to fix up all the linked attributes */
-static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- int ret;
- struct la_context *ac;
- struct ldb_request *search_req;
- const char **attrs;
- WERROR werr;
- struct ldb_context *ldb;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- ldb_set_errstring(ldb,
- "invalid ldb_reply_type in callback");
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
- if (!W_ERROR_IS_OK(werr)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req(&search_req, ldb, req,
- ac->req->op.rename.newdn, LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_op_search_callback,
- req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(search_req, attrs);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_request_add_control(search_req,
- LDB_CONTROL_EXTENDED_DN_OID,
- false, NULL);
- }
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
-
- ac->op_controls = talloc_steal(ac, ares->controls);
- ac->op_response = talloc_steal(ac, ares->response);
-
- return ldb_next_request(ac->module, search_req);
-}
-
-/* Having done the original add, then try to fix up all the linked attributes
-
- This is done after the add so the links can get the extended DNs correctly.
- */
-static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- int ret;
- struct la_context *ac;
- struct ldb_context *ldb;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- ldb_set_errstring(ldb,
- "invalid ldb_reply_type in callback");
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- if (ac->ops) {
- struct ldb_request *search_req;
- static const char *attrs[] = { NULL };
-
- /* The callback does all the hard work here - we need
- * the objectGUID and SID of the added record */
- ret = ldb_build_search_req(&search_req, ldb, ac,
- ac->req->op.add.message->dn,
- LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_mod_search_callback,
- ac->req);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_request_add_control(search_req,
- LDB_CONTROL_EXTENDED_DN_OID,
- false, NULL);
- }
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
-
- ac->op_controls = talloc_steal(ac, ares->controls);
- ac->op_response = talloc_steal(ac, ares->response);
-
- return ldb_next_request(ac->module, search_req);
-
- } else {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-}
-
-/* Reconstruct the original request, but pointing at our local callback to finish things off */
-static int la_down_req(struct la_context *ac)
-{
- struct ldb_request *down_req;
- int ret;
- struct ldb_context *ldb;
-
- ldb = ldb_module_get_ctx(ac->module);
-
- switch (ac->req->operation) {
- case LDB_ADD:
- ret = ldb_build_add_req(&down_req, ldb, ac,
- ac->req->op.add.message,
- ac->req->controls,
- ac, la_add_callback,
- ac->req);
- break;
- case LDB_MODIFY:
- ret = ldb_build_mod_req(&down_req, ldb, ac,
- ac->req->op.mod.message,
- ac->req->controls,
- ac, la_mod_del_callback,
- ac->req);
- break;
- case LDB_DELETE:
- ret = ldb_build_del_req(&down_req, ldb, ac,
- ac->req->op.del.dn,
- ac->req->controls,
- ac, la_mod_del_callback,
- ac->req);
- break;
- case LDB_RENAME:
- ret = ldb_build_rename_req(&down_req, ldb, ac,
- ac->req->op.rename.olddn,
- ac->req->op.rename.newdn,
- ac->req->controls,
- ac, la_rename_callback,
- ac->req);
- break;
- default:
- ret = LDB_ERR_OPERATIONS_ERROR;
- }
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- return ldb_next_request(ac->module, down_req);
-}
-
-/*
- use the GUID part of an extended DN to find the target DN, in case
- it has moved
- */
-static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
- struct GUID *guid, struct ldb_dn **dn)
-{
- return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, GUID_string(ac, guid), dn);
-}
-
-/* apply one la_context op change */
-static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
-{
- struct ldb_message_element *ret_el;
- struct ldb_request *mod_req;
- struct ldb_message *new_msg;
- struct ldb_context *ldb;
- int ret;
-
- ldb = ldb_module_get_ctx(ac->module);
-
- /* Create the modify request */
- new_msg = ldb_msg_new(ac);
- if (!new_msg) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- if (op->op == LA_OP_ADD) {
- ret = ldb_msg_add_empty(new_msg, op->name,
- LDB_FLAG_MOD_ADD, &ret_el);
- } else {
- ret = ldb_msg_add_empty(new_msg, op->name,
- LDB_FLAG_MOD_DELETE, &ret_el);
- }
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
- if (!ret_el->values) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ret_el->num_values = 1;
- if (op->op == LA_OP_ADD) {
- ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->add_dn, 1));
- } else {
- ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->del_dn, 1));
- }
-
-#if 0
- ldb_debug(ldb, LDB_DEBUG_WARNING,
- "link on %s %s: %s %s\n",
- ldb_dn_get_linearized(new_msg->dn), ret_el->name,
- ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
-#endif
-
- ret = ldb_build_mod_req(&mod_req, ldb, op,
- new_msg,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
+ ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
+ NULL, DSDB_SEARCH_SHOW_DELETED);
if (ret != LDB_SUCCESS) {
return ret;
}
- talloc_steal(mod_req, new_msg);
-
- if (DEBUGLVL(4)) {
- DEBUG(4,("Applying linked attribute change:\n%s\n",
- ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)));
- }
-
- /* Run the new request */
- ret = ldb_next_request(module, mod_req);
-
- /* we need to wait for this to finish, as we are being called
- from the synchronous end_transaction hook of this module */
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
- }
-
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
- ldb_errstring(ldb),
- ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg));
- }
-
- return ret;
-}
-
-/* apply one set of la_context changes */
-static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
-{
- struct la_op_store *op;
+ msg = res->msgs[0];
- for (op = ac->ops; op; op=op->next) {
- int ret = la_do_op_request(module, ac, op);
- if (ret != LDB_SUCCESS) {
- if (ret != LDB_ERR_NO_SUCH_OBJECT) {
- return ret;
- }
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct dsdb_attribute *schema_attr
+ = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ if (!schema_attr || schema_attr->linkID == 0) {
+ continue;
}
- }
-
- return LDB_SUCCESS;
-}
-
-
-/*
- we hook into the transaction operations to allow us to
- perform the linked attribute updates at the end of the whole
- transaction. This allows a forward linked attribute to be created
- before the target is created, as long as the target is created
- in the same transaction
- */
-static int linked_attributes_start_transaction(struct ldb_module *module)
-{
- /* create our private structure for this transaction */
- struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
- struct la_private);
- talloc_free(la_private);
- la_private = talloc(module, struct la_private);
- if (la_private == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- la_private->la_list = NULL;
- ldb_module_set_private(module, la_private);
- return ldb_next_start_trans(module);
-}
-
-/*
- on prepare commit we loop over our queued la_context structures
- and apply each of them
- */
-static int linked_attributes_prepare_commit(struct ldb_module *module)
-{
- struct la_private *la_private =
- talloc_get_type(ldb_module_get_private(module), struct la_private);
- struct la_context *ac;
-
- if (!la_private) {
- /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
- return ldb_next_prepare_commit(module);
- }
- /* walk the list backwards, to do the first entry first, as we
- * added the entries with DLIST_ADD() which puts them at the
- * start of the list */
- for (ac = la_private->la_list; ac && ac->next; ac=ac->next) ;
-
- for (; ac; ac=ac->prev) {
- int ret;
- ac->req = NULL;
- ret = la_do_mod_request(module, ac);
+ ret = linked_attributes_fix_links(module, msg->dn, req->op.rename.newdn, el,
+ schema, schema_attr);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
- talloc_free(la_private);
- ldb_module_set_private(module, NULL);
+ talloc_free(res);
return ret;
}
}
- talloc_free(la_private);
- ldb_module_set_private(module, NULL);
+ talloc_free(res);
- return ldb_next_prepare_commit(module);
-}
-
-static int linked_attributes_del_transaction(struct ldb_module *module)
-{
- struct la_private *la_private =
- talloc_get_type(ldb_module_get_private(module), struct la_private);
- talloc_free(la_private);
- ldb_module_set_private(module, NULL);
- return ldb_next_del_trans(module);
+ return ldb_next_request(module, req);
}
_PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = {
.name = "linked_attributes",
- .add = linked_attributes_add,
- .modify = linked_attributes_modify,
- .del = linked_attributes_del,
- .rename = linked_attributes_rename,
- .start_transaction = linked_attributes_start_transaction,
- .prepare_commit = linked_attributes_prepare_commit,
- .del_transaction = linked_attributes_del_transaction,
+ .rename = linked_attributes_rename,
};
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 3ae165c6da..890eb91d6d 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -46,10 +46,16 @@
#include "libcli/security/dom_sid.h"
#include "lib/util/dlinklist.h"
#include "dsdb/samdb/ldb_modules/util.h"
+#include "lib/util/binsearch.h"
+#include "libcli/security/security.h"
+
+#define W2K3_LINKED_ATTRIBUTES 1
struct replmd_private {
TALLOC_CTX *la_ctx;
struct la_entry *la_list;
+ TALLOC_CTX *bl_ctx;
+ struct la_backlink *la_backlinks;
struct nc_entry {
struct nc_entry *prev, *next;
struct ldb_dn *dn;
@@ -84,6 +90,7 @@ struct replmd_replicated_request {
static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
+
/*
initialise the module
allocate the private structure and build the list
@@ -104,6 +111,176 @@ static int replmd_init(struct ldb_module *module)
return ldb_next_init(module);
}
+/*
+ cleanup our per-transaction contexts
+ */
+static void replmd_txn_cleanup(struct replmd_private *replmd_private)
+{
+ talloc_free(replmd_private->la_ctx);
+ replmd_private->la_list = NULL;
+ replmd_private->la_ctx = NULL;
+
+ talloc_free(replmd_private->bl_ctx);
+ replmd_private->la_backlinks = NULL;
+ replmd_private->bl_ctx = NULL;
+}
+
+
+struct la_backlink {
+ struct la_backlink *next, *prev;
+ const char *attr_name;
+ struct GUID forward_guid, target_guid;
+ bool active;
+};
+
+/*
+ process a backlinks we accumulated during a transaction, adding and
+ deleting the backlinks from the target objects
+ */
+static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
+{
+ struct ldb_dn *target_dn, *source_dn;
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_message *msg;
+ TALLOC_CTX *tmp_ctx = talloc_new(bl);
+ char *dn_string;
+
+ /*
+ - find DN of target
+ - find DN of source
+ - construct ldb_message
+ - either an add or a delete
+ */
+ ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
+ GUID_string(bl, &bl->target_guid));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
+ GUID_string(bl, &bl->forward_guid));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* construct a ldb_message for adding/deleting the backlink */
+ msg->dn = target_dn;
+ dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
+ if (!dn_string) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
+
+ ret = dsdb_module_modify(module, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
+ bl->active?"add":"remove",
+ ldb_dn_get_linearized(source_dn),
+ ldb_dn_get_linearized(target_dn),
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ add a backlink to the list of backlinks to add/delete in the prepare
+ commit
+ */
+static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
+ struct GUID *forward_guid, struct GUID *target_guid,
+ bool active, const struct dsdb_attribute *schema_attr, bool immediate)
+{
+ const struct dsdb_attribute *target_attr;
+ struct la_backlink *bl;
+ struct replmd_private *replmd_private =
+ talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
+
+ target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
+ if (!target_attr) {
+ /*
+ * windows 2003 has a broken schema where the
+ * definition of msDS-IsDomainFor is missing (which is
+ * supposed to be the backlink of the
+ * msDS-HasDomainNCs attribute
+ */
+ return LDB_SUCCESS;
+ }
+
+ /* see if its already in the list */
+ for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
+ if (GUID_equal(forward_guid, &bl->forward_guid) &&
+ GUID_equal(target_guid, &bl->target_guid) &&
+ (target_attr->lDAPDisplayName == bl->attr_name ||
+ strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
+ break;
+ }
+ }
+
+ if (bl) {
+ /* we found an existing one */
+ if (bl->active == active) {
+ return LDB_SUCCESS;
+ }
+ DLIST_REMOVE(replmd_private->la_backlinks, bl);
+ talloc_free(bl);
+ return LDB_SUCCESS;
+ }
+
+ if (replmd_private->bl_ctx == NULL) {
+ replmd_private->bl_ctx = talloc_new(replmd_private);
+ if (replmd_private->bl_ctx == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ /* its a new one */
+ bl = talloc(replmd_private->bl_ctx, struct la_backlink);
+ if (bl == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ bl->attr_name = target_attr->lDAPDisplayName;
+ bl->forward_guid = *forward_guid;
+ bl->target_guid = *target_guid;
+ bl->active = active;
+
+ /* the caller may ask for this backlink to be processed
+ immediately */
+ if (immediate) {
+ int ret = replmd_process_backlink(module, bl);
+ talloc_free(bl);
+ return ret;
+ }
+
+ DLIST_ADD(replmd_private->la_backlinks, bl);
+
+ return LDB_SUCCESS;
+}
+
/*
* Callback for most write operations in this module:
@@ -142,6 +319,7 @@ static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
}
if (!partition_ctrl) {
+ ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
return ldb_module_done(ac->req, NULL,
NULL, LDB_ERR_OPERATIONS_ERROR);
}
@@ -336,7 +514,7 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta
return -1;
}
- return m1->attid - m2->attid;
+ return m1->attid > m2->attid ? 1 : -1;
}
static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
@@ -390,8 +568,10 @@ static int replmd_ldb_message_element_attid_sort(const struct ldb_message_elemen
if (!a1 || !a2) {
return strcasecmp(e1->name, e2->name);
}
-
- return a1->attributeID_id - a2->attributeID_id;
+ if (a1->attributeID_id == a2->attributeID_id) {
+ return 0;
+ }
+ return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
}
static void replmd_ldb_message_sort(struct ldb_message *msg,
@@ -401,6 +581,73 @@ static void replmd_ldb_message_sort(struct ldb_message *msg,
discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
}
+static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
+ const struct GUID *invocation_id, uint64_t seq_num,
+ uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
+
+
+/*
+ fix up linked attributes in replmd_add.
+ This involves setting up the right meta-data in extended DN
+ components, and creating backlinks to the object
+ */
+static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
+ uint64_t seq_num, const struct GUID *invocationId, time_t t,
+ struct GUID *guid, const struct dsdb_attribute *sa)
+{
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(el->values);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ NTTIME now;
+
+ unix_to_nt_time(&now, t);
+
+ for (i=0; i<el->num_values; i++) {
+ struct ldb_val *v = &el->values[i];
+ struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
+ struct GUID target_guid;
+ NTSTATUS status;
+ int ret;
+
+ /* note that the DN already has the extended
+ components from the extended_dn_store module */
+ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
+ if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
+ ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
+ seq_num, seq_num, now, 0, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+/*
+ intercept add requests
+ */
static int replmd_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb;
@@ -557,6 +804,19 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
continue;
}
+#if W2K3_LINKED_ATTRIBUTES
+ if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
+ ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
+ /* linked attributes are not stored in
+ replPropertyMetaData in FL above w2k */
+ continue;
+ }
+#endif
+
m->attid = sa->attributeID_id;
m->version = 1;
m->originating_change_time = now;
@@ -678,6 +938,20 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
for (i=0; i<omd->ctr.ctr1.count; i++) {
if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
}
+
+#if W2K3_LINKED_ATTRIBUTES
+ if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
+ /* linked attributes are not stored in
+ replPropertyMetaData in FL above w2k, but we do
+ raise the seqnum for the object */
+ if (*seq_num == 0 &&
+ ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ }
+#endif
+
if (i == omd->ctr.ctr1.count) {
/* we need to add a new one */
omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
@@ -719,13 +993,13 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
*/
static int replmd_update_rpmd(struct ldb_module *module,
const struct dsdb_schema *schema,
- struct ldb_message *msg, uint64_t *seq_num)
+ struct ldb_message *msg, uint64_t *seq_num,
+ time_t t)
{
const struct ldb_val *omd_value;
enum ndr_err_code ndr_err;
struct replPropertyMetaDataBlob omd;
int i;
- time_t t = time(NULL);
NTTIME now;
const struct GUID *our_invocation_id;
int ret;
@@ -828,13 +1102,822 @@ static int replmd_update_rpmd(struct ldb_module *module,
}
+struct parsed_dn {
+ struct dsdb_dn *dsdb_dn;
+ struct GUID *guid;
+ struct ldb_val *v;
+};
+
+static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
+{
+ return GUID_compare(pdn1->guid, pdn2->guid);
+}
+
+static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
+{
+ struct parsed_dn *ret;
+ if (dn && GUID_all_zero(guid)) {
+ /* when updating a link using DRS, we sometimes get a
+ NULL GUID. We then need to try and match by DN */
+ int i;
+ for (i=0; i<count; i++) {
+ if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
+ dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
+ return &pdn[i];
+ }
+ }
+ return NULL;
+ }
+ BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
+ return ret;
+}
+
+/*
+ get a series of message element values as an array of DNs and GUIDs
+ the result is sorted by GUID
+ */
+static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el, struct parsed_dn **pdn,
+ const char *ldap_oid)
+{
+ int i;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ if (el == NULL) {
+ *pdn = NULL;
+ return LDB_SUCCESS;
+ }
+
+ (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
+ if (!*pdn) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i=0; i<el->num_values; i++) {
+ struct ldb_val *v = &el->values[i];
+ NTSTATUS status;
+ struct ldb_dn *dn;
+ struct parsed_dn *p;
+
+ p = &(*pdn)[i];
+
+ p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
+ if (p->dsdb_dn == NULL) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ dn = p->dsdb_dn->dn;
+
+ p->guid = talloc(*pdn, struct GUID);
+ if (p->guid == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ /* we got a DN without a GUID - go find the GUID */
+ int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
+ ldb_dn_get_linearized(dn));
+ return ret;
+ }
+ ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* keep a pointer to the original ldb_val */
+ p->v = v;
+ }
+
+ qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ build a new extended DN, including all meta data fields
+
+ RMD_FLAGS = DSDB_RMD_FLAG_* bits
+ RMD_ADDTIME = originating_add_time
+ RMD_INVOCID = originating_invocation_id
+ RMD_CHANGETIME = originating_change_time
+ RMD_ORIGINATING_USN = originating_usn
+ RMD_LOCAL_USN = local_usn
+ RMD_VERSION = version
+ */
+static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
+ const struct GUID *invocation_id, uint64_t seq_num,
+ uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
+{
+ struct ldb_dn *dn = dsdb_dn->dn;
+ const char *tstring, *usn_string, *flags_string;
+ struct ldb_val tval;
+ struct ldb_val iid;
+ struct ldb_val usnv, local_usnv;
+ struct ldb_val vers, flagsv;
+ NTSTATUS status;
+ int ret;
+ const char *dnstring;
+ char *vstring;
+ uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
+
+ tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
+ if (!tstring) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tval = data_blob_string_const(tstring);
+
+ usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
+ if (!usn_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ usnv = data_blob_string_const(usn_string);
+
+ usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
+ if (!usn_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ local_usnv = data_blob_string_const(usn_string);
+
+ vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
+ if (!vstring) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ vers = data_blob_string_const(vstring);
+
+ status = GUID_to_ndr_blob(invocation_id, dn, &iid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
+ if (!flags_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ flagsv = data_blob_string_const(flags_string);
+
+ ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
+ if (ret != LDB_SUCCESS) return ret;
+ ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
+ if (ret != LDB_SUCCESS) return ret;
+
+ dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
+ if (dnstring == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *v = data_blob_string_const(dnstring);
+
+ return LDB_SUCCESS;
+}
+
+static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
+ struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
+ uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
+ uint32_t version, bool deleted);
+
+/*
+ check if any links need upgrading from w2k format
+ */
+static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
+{
+ int i;
+ for (i=0; i<count; i++) {
+ NTSTATUS status;
+ uint32_t version;
+ int ret;
+
+ status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ continue;
+ }
+
+ /* it's an old one that needs upgrading */
+ ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
+ 1, 1, 0, 0, false);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ update an extended DN, including all meta data fields
+
+ see replmd_build_la_val for value names
+ */
+static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
+ struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
+ uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
+ uint32_t version, bool deleted)
+{
+ struct ldb_dn *dn = dsdb_dn->dn;
+ const char *tstring, *usn_string, *flags_string;
+ struct ldb_val tval;
+ struct ldb_val iid;
+ struct ldb_val usnv, local_usnv;
+ struct ldb_val vers, flagsv;
+ const struct ldb_val *old_addtime;
+ uint32_t old_version;
+ NTSTATUS status;
+ int ret;
+ const char *dnstring;
+ char *vstring;
+ uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
+
+ tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
+ if (!tstring) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tval = data_blob_string_const(tstring);
+
+ usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
+ if (!usn_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ usnv = data_blob_string_const(usn_string);
+
+ usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
+ if (!usn_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ local_usnv = data_blob_string_const(usn_string);
+
+ status = GUID_to_ndr_blob(invocation_id, dn, &iid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
+ if (!flags_string) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ flagsv = data_blob_string_const(flags_string);
+
+ ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* get the ADDTIME from the original */
+ old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
+ if (old_addtime == NULL) {
+ old_addtime = &tval;
+ }
+ if (dsdb_dn != old_dsdb_dn) {
+ ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
+ if (ret != LDB_SUCCESS) return ret;
+ }
+
+ /* use our invocation id */
+ ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* changetime is the current time */
+ ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* update the USN */
+ ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
+ if (ret != LDB_SUCCESS) return ret;
+
+ ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* increase the version by 1 */
+ status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
+ if (NT_STATUS_IS_OK(status) && old_version >= version) {
+ version = old_version+1;
+ }
+ vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
+ vers = data_blob_string_const(vstring);
+ ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
+ if (ret != LDB_SUCCESS) return ret;
+
+ dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
+ if (dnstring == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *v = data_blob_string_const(dnstring);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ handle adding a linked attribute
+ */
+static int replmd_modify_la_add(struct ldb_module *module,
+ struct dsdb_schema *schema,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ struct ldb_message_element *old_el,
+ const struct dsdb_attribute *schema_attr,
+ uint64_t seq_num,
+ time_t t,
+ struct GUID *msg_guid)
+{
+ int i;
+ struct parsed_dn *dns, *old_dns;
+ TALLOC_CTX *tmp_ctx = talloc_new(msg);
+ int ret;
+ struct ldb_val *new_values = NULL;
+ unsigned int num_new_values = 0;
+ unsigned old_num_values = old_el?old_el->num_values:0;
+ const struct GUID *invocation_id;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ NTTIME now;
+
+ unix_to_nt_time(&now, t);
+
+ ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ invocation_id = samdb_ntds_invocation_id(ldb);
+ if (!invocation_id) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* for each new value, see if it exists already with the same GUID */
+ for (i=0; i<el->num_values; i++) {
+ struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
+ if (p == NULL) {
+ /* this is a new linked attribute value */
+ new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
+ if (new_values == NULL) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
+ invocation_id, seq_num, seq_num, now, 0, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ num_new_values++;
+ } else {
+ /* this is only allowed if the GUID was
+ previously deleted. */
+ uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
+
+ if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
+ ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
+ el->name, GUID_string(tmp_ctx, p->guid));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
+ invocation_id, seq_num, seq_num, now, 0, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ /* add the new ones on to the end of the old values, constructing a new el->values */
+ el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
+ struct ldb_val,
+ old_num_values+num_new_values);
+ if (el->values == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
+ el->num_values = old_num_values + num_new_values;
+
+ talloc_steal(msg->elements, el->values);
+ talloc_steal(el->values, new_values);
+
+ talloc_free(tmp_ctx);
+
+ /* we now tell the backend to replace all existing values
+ with the one we have constructed */
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ handle deleting all active linked attributes
+ */
+static int replmd_modify_la_delete(struct ldb_module *module,
+ struct dsdb_schema *schema,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ struct ldb_message_element *old_el,
+ const struct dsdb_attribute *schema_attr,
+ uint64_t seq_num,
+ time_t t,
+ struct GUID *msg_guid)
+{
+ int i;
+ struct parsed_dn *dns, *old_dns;
+ TALLOC_CTX *tmp_ctx = talloc_new(msg);
+ int ret;
+ const struct GUID *invocation_id;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ NTTIME now;
+
+ unix_to_nt_time(&now, t);
+
+ /* check if there is nothing to delete */
+ if ((!old_el || old_el->num_values == 0) &&
+ el->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+
+ if (!old_el || old_el->num_values == 0) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ invocation_id = samdb_ntds_invocation_id(ldb);
+ if (!invocation_id) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ el->values = NULL;
+
+ /* see if we are being asked to delete any links that
+ don't exist or are already deleted */
+ for (i=0; i<el->num_values; i++) {
+ struct parsed_dn *p = &dns[i];
+ struct parsed_dn *p2;
+ uint32_t rmd_flags;
+
+ p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
+ if (!p2) {
+ ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
+ el->name, GUID_string(tmp_ctx, p->guid));
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
+ if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
+ ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
+ el->name, GUID_string(tmp_ctx, p->guid));
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ }
+
+ /* for each new value, see if it exists already with the same GUID
+ if it is not already deleted and matches the delete list then delete it
+ */
+ for (i=0; i<old_el->num_values; i++) {
+ struct parsed_dn *p = &old_dns[i];
+ uint32_t rmd_flags;
+
+ if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
+ continue;
+ }
+
+ rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
+ if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
+
+ ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
+ invocation_id, seq_num, seq_num, now, 0, true);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ el->values = talloc_steal(msg->elements, old_el->values);
+ el->num_values = old_el->num_values;
+
+ talloc_free(tmp_ctx);
+
+ /* we now tell the backend to replace all existing values
+ with the one we have constructed */
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ handle replacing a linked attribute
+ */
+static int replmd_modify_la_replace(struct ldb_module *module,
+ struct dsdb_schema *schema,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ struct ldb_message_element *old_el,
+ const struct dsdb_attribute *schema_attr,
+ uint64_t seq_num,
+ time_t t,
+ struct GUID *msg_guid)
+{
+ int i;
+ struct parsed_dn *dns, *old_dns;
+ TALLOC_CTX *tmp_ctx = talloc_new(msg);
+ int ret;
+ const struct GUID *invocation_id;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_val *new_values = NULL;
+ uint32_t num_new_values = 0;
+ unsigned old_num_values = old_el?old_el->num_values:0;
+ NTTIME now;
+
+ unix_to_nt_time(&now, t);
+
+ /* check if there is nothing to replace */
+ if ((!old_el || old_el->num_values == 0) &&
+ el->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ invocation_id = samdb_ntds_invocation_id(ldb);
+ if (!invocation_id) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* mark all the old ones as deleted */
+ for (i=0; i<old_num_values; i++) {
+ struct parsed_dn *old_p = &old_dns[i];
+ struct parsed_dn *p;
+ uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
+
+ if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
+
+ ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
+ if (p) {
+ /* we don't delete it if we are re-adding it */
+ continue;
+ }
+
+ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
+ invocation_id, seq_num, seq_num, now, 0, true);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ /* for each new value, either update its meta-data, or add it
+ * to old_el
+ */
+ for (i=0; i<el->num_values; i++) {
+ struct parsed_dn *p = &dns[i], *old_p;
+
+ if (old_dns &&
+ (old_p = parsed_dn_find(old_dns,
+ old_num_values, p->guid, NULL)) != NULL) {
+ /* update in place */
+ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
+ old_p->dsdb_dn, invocation_id,
+ seq_num, seq_num, now, 0, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ } else {
+ /* add a new one */
+ new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
+ num_new_values+1);
+ if (new_values == NULL) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
+ invocation_id, seq_num, seq_num, now, 0, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ num_new_values++;
+ }
+
+ ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ /* add the new values to the end of old_el */
+ if (num_new_values != 0) {
+ el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
+ struct ldb_val, old_num_values+num_new_values);
+ if (el->values == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ memcpy(&el->values[old_num_values], &new_values[0],
+ sizeof(struct ldb_val)*num_new_values);
+ el->num_values = old_num_values + num_new_values;
+ talloc_steal(msg->elements, new_values);
+ } else {
+ el->values = old_el->values;
+ el->num_values = old_el->num_values;
+ talloc_steal(msg->elements, el->values);
+ }
+
+ talloc_free(tmp_ctx);
+
+ /* we now tell the backend to replace all existing values
+ with the one we have constructed */
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ handle linked attributes in modify requests
+ */
+static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
+ struct ldb_message *msg,
+ uint64_t seq_num, time_t t)
+{
+ struct ldb_result *res;
+ int ret, i;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_message *old_msg;
+ struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ struct GUID old_guid;
+
+ if (seq_num == 0) {
+ /* there the replmd_update_rpmd code has already
+ * checked and saw that there are no linked
+ * attributes */
+ return LDB_SUCCESS;
+ }
+
+#if !W2K3_LINKED_ATTRIBUTES
+ return LDB_SUCCESS;
+#endif
+
+ if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
+ /* don't do anything special for linked attributes */
+ return LDB_SUCCESS;
+ }
+
+ ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_REVEAL_INTERNALS |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ old_msg = res->msgs[0];
+
+ old_guid = samdb_result_guid(old_msg, "objectGUID");
+
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ struct ldb_message_element *old_el, *new_el;
+ const struct dsdb_attribute *schema_attr
+ = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ if (!schema_attr) {
+ ldb_asprintf_errstring(ldb,
+ "attribute %s is not a valid attribute in schema", el->name);
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+ if (schema_attr->linkID == 0) {
+ continue;
+ }
+ if ((schema_attr->linkID & 1) == 1) {
+ /* Odd is for the target. Illegal to modify */
+ ldb_asprintf_errstring(ldb,
+ "attribute %s must not be modified directly, it is a linked attribute", el->name);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ old_el = ldb_msg_find_element(old_msg, el->name);
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_REPLACE:
+ ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
+ break;
+ case LDB_FLAG_MOD_ADD:
+ ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
+ break;
+ default:
+ ldb_asprintf_errstring(ldb,
+ "invalid flags 0x%x for %s linked attribute",
+ el->flags, el->name);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (old_el) {
+ ldb_msg_remove_attr(old_msg, el->name);
+ }
+ ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
+ new_el->num_values = el->num_values;
+ new_el->values = talloc_steal(msg->elements, el->values);
+
+ /* TODO: this relises a bit too heavily on the exact
+ behaviour of ldb_msg_find_element and
+ ldb_msg_remove_element */
+ old_el = ldb_msg_find_element(msg, el->name);
+ if (old_el != el) {
+ ldb_msg_remove_element(msg, old_el);
+ i--;
+ }
+ }
+
+ talloc_free(res);
+ return ret;
+}
+
+
+
static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb;
struct replmd_replicated_request *ac;
struct ldb_request *down_req;
struct ldb_message *msg;
- struct ldb_result *res;
time_t t = time(NULL);
int ret;
@@ -860,24 +1943,16 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_OPERATIONS_ERROR;
}
- /* TODO:
- * - give an error when a readonly attribute should
- * be modified
- * - merge the changed into the old object
- * if the caller set values to the same value
- * ignore the attribute, return success when no
- * attribute was changed
- */
+ ldb_msg_remove_attr(msg, "whenChanged");
+ ldb_msg_remove_attr(msg, "uSNChanged");
- ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
- DSDB_SEARCH_SHOW_DELETED |
- DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
+ ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
if (ret != LDB_SUCCESS) {
talloc_free(ac);
return ret;
}
- ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num);
+ ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
if (ret != LDB_SUCCESS) {
talloc_free(ac);
return ret;
@@ -1030,6 +2105,329 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
return ldb_next_request(ac->module, down_req);
}
+/*
+ remove links from objects that point at this object when an object
+ is deleted
+ */
+static int replmd_delete_remove_link(struct ldb_module *module,
+ struct dsdb_schema *schema,
+ struct ldb_dn *dn,
+ struct ldb_message_element *el,
+ const struct dsdb_attribute *sa)
+{
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ for (i=0; i<el->num_values; i++) {
+ struct dsdb_dn *dsdb_dn;
+ NTSTATUS status;
+ int ret;
+ struct GUID guid2;
+ struct ldb_message *msg;
+ const struct dsdb_attribute *target_attr;
+ struct ldb_message_element *el2;
+ struct ldb_val dn_val;
+
+ if (dsdb_dn_is_deleted_val(&el->values[i])) {
+ continue;
+ }
+
+ dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
+ if (!dsdb_dn) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* remove the link */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+
+ msg->dn = dsdb_dn->dn;
+
+ target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
+ if (target_attr == NULL) {
+ continue;
+ }
+
+ ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
+ if (ret != LDB_SUCCESS) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
+ el2->values = &dn_val;
+ el2->num_values = 1;
+
+ ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+/*
+ handle update of replication meta data for deletion of objects
+
+ This also handles the mapping of delete to a rename operation
+ to allow deletes to be replicated.
+ */
+static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ int ret = LDB_ERR_OTHER;
+ bool retb;
+ struct ldb_dn *old_dn, *new_dn;
+ const char *rdn_name;
+ const struct ldb_val *rdn_value, *new_rdn_value;
+ struct GUID guid;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ struct ldb_message *msg, *old_msg;
+ struct ldb_message_element *el;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res, *parent_res;
+ const char *preserved_attrs[] = {
+ /* yes, this really is a hard coded list. See MS-ADTS
+ section 3.1.1.5.5.1.1 */
+ "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
+ "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
+ "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
+ "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
+ "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
+ "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
+ "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
+ "whenChanged", NULL};
+ uint32_t el_count = 0;
+ int i;
+
+ if (ldb_dn_is_special(req->op.del.dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ tmp_ctx = talloc_new(ldb);
+
+ old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
+
+ /* we need the complete msg off disk, so we can work out which
+ attributes need to be removed */
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_REVEAL_INTERNALS |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ old_msg = res->msgs[0];
+
+ if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
+ struct auth_session_info *session_info =
+ (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
+ if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
+ ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
+ ldb_dn_get_linearized(old_msg->dn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ /* it is already deleted - really remove it this time */
+ talloc_free(tmp_ctx);
+ return ldb_next_request(module, req);
+ }
+
+ /* work out where we will be renaming this object to */
+ ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
+ if (ret != LDB_SUCCESS) {
+ /* this is probably an attempted delete on a partition
+ * that doesn't allow delete operations, such as the
+ * schema partition */
+ ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
+ ldb_dn_get_linearized(old_dn));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(old_dn);
+ rdn_value = ldb_dn_get_rdn_val(old_dn);
+
+ /* get the objects GUID from the search we just did */
+ guid = samdb_result_guid(old_msg, "objectGUID");
+
+ /* Add a formatted child */
+ retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
+ rdn_name,
+ rdn_value->data,
+ GUID_string(tmp_ctx, &guid));
+ if (!retb) {
+ DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
+ ldb_dn_get_linearized(new_dn)));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ now we need to modify the object in the following ways:
+
+ - add isDeleted=TRUE
+ - update rDN and name, with new rDN
+ - remove linked attributes
+ - remove objectCategory and sAMAccountType
+ - remove attribs not on the preserved list
+ - preserved if in above list, or is rDN
+ - remove all linked attribs from this object
+ - remove all links from other objects to this object
+ - add lastKnownParent
+ - update replPropertyMetaData?
+
+ see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
+ */
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->dn = old_dn;
+
+ ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
+
+ /* we also mark it as recycled, meaning this object can't be
+ recovered (we are stripping its attributes) */
+ if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
+ ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
+ }
+
+ /* we need the storage form of the parent GUID */
+ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
+ ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
+ DSDB_SEARCH_REVEAL_INTERNALS);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
+ ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
+
+ /* work out which of the old attributes we will be removing */
+ for (i=0; i<old_msg->num_elements; i++) {
+ const struct dsdb_attribute *sa;
+ el = &old_msg->elements[i];
+ sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ if (!sa) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_attr_cmp(el->name, rdn_name) == 0) {
+ /* don't remove the rDN */
+ continue;
+ }
+
+ if (sa->linkID && sa->linkID & 1) {
+ ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ continue;
+ }
+
+ if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
+ continue;
+ }
+
+ ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ ldb_module_oom(module);
+ return ret;
+ }
+ }
+
+ /* work out what the new rdn value is, for updating the
+ rDN and name fields */
+ new_rdn_value = ldb_dn_get_rdn_val(new_dn);
+ ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ el = ldb_msg_find_element(old_msg, "name");
+ if (el) {
+ ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
+ ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* now rename onto the new DN */
+ ret = dsdb_module_rename(module, old_dn, new_dn, 0);
+ if (ret != LDB_SUCCESS){
+ DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
+ ldb_dn_get_linearized(old_dn),
+ ldb_dn_get_linearized(new_dn),
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ talloc_free(tmp_ctx);
+
+ return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
+}
+
+
static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
{
@@ -1094,14 +2492,15 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
/* remove any message elements that have zero values */
for (i=0; i<msg->num_elements; i++) {
- if (msg->elements[i].num_values == 0) {
+ struct ldb_message_element *el = &msg->elements[i];
+
+ if (el->num_values == 0) {
DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
- msg->elements[i].name));
- memmove(&msg->elements[i],
- &msg->elements[i+1],
- sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
+ el->name));
+ memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
msg->num_elements--;
i--;
+ continue;
}
}
@@ -1145,25 +2544,38 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
return ldb_next_request(ar->module, change_req);
}
-static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
- struct replPropertyMetaData1 *m2)
+/*
+ return true if an update is newer than an existing entry
+ see section 5.11 of MS-ADTS
+*/
+static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
+ const struct GUID *update_invocation_id,
+ uint32_t current_version,
+ uint32_t update_version,
+ NTTIME current_change_time,
+ NTTIME update_change_time)
{
- int ret;
-
- if (m1->version != m2->version) {
- return m1->version - m2->version;
+ if (update_version != current_version) {
+ return update_version > current_version;
}
-
- if (m1->originating_change_time != m2->originating_change_time) {
- return m1->originating_change_time - m2->originating_change_time;
+ if (update_change_time > current_change_time) {
+ return true;
}
-
- ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
- if (ret != 0) {
- return ret;
+ if (update_change_time == current_change_time) {
+ return GUID_compare(update_invocation_id, current_invocation_id) > 0;
}
+ return false;
+}
- return m1->originating_usn - m2->originating_usn;
+static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
+ struct replPropertyMetaData1 *new_m)
+{
+ return replmd_update_is_newer(&cur_m->originating_invocation_id,
+ &new_m->originating_invocation_id,
+ cur_m->version,
+ new_m->version,
+ cur_m->originating_change_time,
+ new_m->originating_change_time);
}
static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
@@ -1194,7 +2606,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
ldb_dn_get_linearized(ar->search_msg->dn),
ldb_dn_get_linearized(msg->dn));
- if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
+ if (dsdb_module_rename(ar->module,
+ ar->search_msg->dn, msg->dn,
+ DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
ldb_dn_get_linearized(ar->search_msg->dn),
ldb_dn_get_linearized(msg->dn),
@@ -1238,21 +2652,26 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
bool found = false;
for (j=0; j < ni; j++) {
- int cmp;
+ bool cmp;
if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
continue;
}
- cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
- &nmd.ctr.ctr1.array[j]);
- if (cmp > 0) {
+ cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
+ &rmd->ctr.ctr1.array[i]);
+ if (cmp) {
/* replace the entry */
nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
found = true;
break;
}
+ DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
+ msg->elements[i-removed_attrs].name,
+ ldb_dn_get_linearized(msg->dn),
+ GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
+
/* we don't want to apply this change so remove the attribute */
ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
removed_attrs++;
@@ -1954,24 +3373,22 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct dsdb_schema *schema = dsdb_get_schema(ldb);
- struct drsuapi_DsReplicaObjectIdentifier3 target;
struct ldb_message *msg;
TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
- struct ldb_request *mod_req;
int ret;
const struct dsdb_attribute *attr;
- struct ldb_dn *target_dn;
struct dsdb_dn *dsdb_dn;
uint64_t seq_num = 0;
- struct drsuapi_DsReplicaAttribute drs;
- struct drsuapi_DsAttributeValue val;
- struct ldb_message_element el;
- const struct ldb_val *guid;
+ struct ldb_message_element *old_el;
WERROR status;
-
- drs.value_ctr.num_values = 1;
- drs.value_ctr.values = &val;
- val.blob = la->value.blob;
+ time_t t = time(NULL);
+ struct ldb_result *res;
+ const char *attrs[2];
+ struct parsed_dn *pdn_list, *pdn;
+ struct GUID guid = GUID_zero();
+ NTSTATUS ntstatus;
+ bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
+ const struct GUID *our_invocation_id;
/*
linked_attributes[0]:
@@ -2016,155 +3433,212 @@ linked_attributes[0]:
return LDB_ERR_OPERATIONS_ERROR;
}
- status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el);
+ attrs[0] = attr->lDAPDisplayName;
+ attrs[1] = NULL;
- /* construct a modify request for this attribute change */
- msg = ldb_msg_new(tmp_ctx);
- if (!msg) {
- ldb_oom(ldb);
- talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
- GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
+ /* get the existing message from the db for the object with
+ this GUID, returning attribute being modified. We will then
+ use this msg as the basis for a modify call */
+ ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
+ DSDB_SEARCH_REVEAL_INTERNALS,
+ "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
+ if (res->count != 1) {
+ ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
+ GUID_string(tmp_ctx, &la->identifier->guid));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ msg = res->msgs[0];
- el.name = attr->lDAPDisplayName;
- if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
- ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD);
+ if (msg->num_elements == 0) {
+ ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
+ if (ret != LDB_SUCCESS) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
} else {
- ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE);
+ old_el = &msg->elements[0];
+ old_el->flags = LDB_FLAG_MOD_REPLACE;
}
+
+ /* parse the existing links */
+ ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
- dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid);
- if (!dsdb_dn) {
- DEBUG(0,(__location__ ": Failed to parse just-generated DN\n"));
+ /* get our invocationId */
+ our_invocation_id = samdb_ntds_invocation_id(ldb);
+ if (!our_invocation_id) {
+ ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
talloc_free(tmp_ctx);
- return LDB_ERR_INVALID_DN_SYNTAX;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID");
- if (!guid) {
- DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n"));
+ ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
- return LDB_ERR_INVALID_DN_SYNTAX;
+ return ret;
}
- ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn);
- if (ret != LDB_SUCCESS) {
- /* If this proves to be a problem in the future, then
- * just remove the return - perhaps we can just use
- * the details the replication peer supplied */
-
- DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
- talloc_free(tmp_ctx);
+ status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
+ if (!W_ERROR_IS_OK(status)) {
+ ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
+ old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
return LDB_ERR_OPERATIONS_ERROR;
- } else {
+ }
- /* Now update with full DN we just found in the DB (including extended components) */
- dsdb_dn->dn = target_dn;
- /* Now make a linearized version, using the original binary components (if any) */
- el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1));
+ ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
+ if (!NT_STATUS_IS_OK(ntstatus) && active) {
+ ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
+ old_el->name,
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_OPERATIONS_ERROR;
}
- ret = replmd_update_rpmd(module, schema, msg, &seq_num);
+ /* re-resolve the DN by GUID, as the DRS server may give us an
+ old DN value */
+ ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
+ GUID_string(tmp_ctx, &guid));
talloc_free(tmp_ctx);
return ret;
}
- /* we only change whenChanged and uSNChanged if the seq_num
- has changed */
- if (seq_num != 0) {
- time_t t = time(NULL);
-
- if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
+ /* see if this link already exists */
+ pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
+ if (pdn != NULL) {
+ /* see if this update is newer than what we have already */
+ struct GUID invocation_id = GUID_zero();
+ uint32_t version = 0;
+ NTTIME change_time = 0;
+ uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
+
+ dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
+ dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
+ dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
+
+ if (!replmd_update_is_newer(&invocation_id,
+ &la->meta_data.originating_invocation_id,
+ version,
+ la->meta_data.version,
+ change_time,
+ la->meta_data.originating_change_time)) {
+ DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
+ old_el->name, ldb_dn_get_linearized(msg->dn),
+ GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return LDB_SUCCESS;
}
- if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
+ /* get a seq_num for this change */
+ ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
}
- }
-
- ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
- msg,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
- talloc_steal(mod_req, msg);
-
- if (DEBUGLVL(4)) {
- DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
- ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
- }
- /* Run the new request */
- ret = ldb_next_request(module, mod_req);
+ if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
+ /* remove the existing backlink */
+ ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
- /* we need to wait for this to finish, as we are being called
- from the synchronous end_transaction hook of this module */
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
- }
+ ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
+ &la->meta_data.originating_invocation_id,
+ la->meta_data.originating_usn, seq_num,
+ la->meta_data.originating_change_time,
+ la->meta_data.version,
+ !active);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
- if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
- /* the link destination exists, we need to update it
- * by deleting the old one for the same DN then adding
- * the new one */
- msg->elements = talloc_realloc(msg, msg->elements,
- struct ldb_message_element,
- msg->num_elements+1);
- if (msg->elements == NULL) {
- ldb_oom(ldb);
+ if (active) {
+ /* add the new backlink */
+ ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+ } else {
+ /* get a seq_num for this change */
+ ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ old_el->values = talloc_realloc(msg->elements, old_el->values,
+ struct ldb_val, old_el->num_values+1);
+ if (!old_el->values) {
+ ldb_module_oom(module);
return LDB_ERR_OPERATIONS_ERROR;
}
- /* this relies on the backend matching the old entry
- only by the DN portion of the extended DN */
- msg->elements[1] = msg->elements[0];
- msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
- msg->num_elements++;
-
- ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
- msg,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
+ old_el->num_values++;
+
+ ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
+ &la->meta_data.originating_invocation_id,
+ la->meta_data.originating_usn, seq_num,
+ la->meta_data.originating_change_time,
+ la->meta_data.version,
+ (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
- /* Run the new request */
- ret = ldb_next_request(module, mod_req);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
+ if (active) {
+ ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
+ true, attr, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
}
}
+ /* we only change whenChanged and uSNChanged if the seq_num
+ has changed */
+ if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_check_single_valued_link(attr, old_el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
ldb_errstring(ldb),
ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
- ret = LDB_SUCCESS;
+ talloc_free(tmp_ctx);
+ return ret;
}
talloc_free(tmp_ctx);
@@ -2194,9 +3668,7 @@ static int replmd_start_transaction(struct ldb_module *module)
/* create our private structure for this transaction */
struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
struct replmd_private);
- talloc_free(replmd_private->la_ctx);
- replmd_private->la_list = NULL;
- replmd_private->la_ctx = NULL;
+ replmd_txn_cleanup(replmd_private);
/* free any leftover mod_usn records from cancelled
transactions */
@@ -2218,6 +3690,7 @@ static int replmd_prepare_commit(struct ldb_module *module)
struct replmd_private *replmd_private =
talloc_get_type(ldb_module_get_private(module), struct replmd_private);
struct la_entry *la, *prev;
+ struct la_backlink *bl;
int ret;
/* walk the list backwards, to do the first entry first, as we
@@ -2230,16 +3703,22 @@ static int replmd_prepare_commit(struct ldb_module *module)
DLIST_REMOVE(replmd_private->la_list, la);
ret = replmd_process_linked_attribute(module, la);
if (ret != LDB_SUCCESS) {
- talloc_free(replmd_private->la_ctx);
- replmd_private->la_list = NULL;
- replmd_private->la_ctx = NULL;
+ replmd_txn_cleanup(replmd_private);
return ret;
}
}
- talloc_free(replmd_private->la_ctx);
- replmd_private->la_list = NULL;
- replmd_private->la_ctx = NULL;
+ /* process our backlink list, creating and deleting backlinks
+ as necessary */
+ for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
+ ret = replmd_process_backlink(module, bl);
+ if (ret != LDB_SUCCESS) {
+ replmd_txn_cleanup(replmd_private);
+ return ret;
+ }
+ }
+
+ replmd_txn_cleanup(replmd_private);
/* possibly change @REPLCHANGED */
ret = replmd_notify_store(module);
@@ -2254,9 +3733,8 @@ static int replmd_del_transaction(struct ldb_module *module)
{
struct replmd_private *replmd_private =
talloc_get_type(ldb_module_get_private(module), struct replmd_private);
- talloc_free(replmd_private->la_ctx);
- replmd_private->la_list = NULL;
- replmd_private->la_ctx = NULL;
+ replmd_txn_cleanup(replmd_private);
+
return ldb_next_del_trans(module);
}
@@ -2267,6 +3745,7 @@ _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
.add = replmd_add,
.modify = replmd_modify,
.rename = replmd_rename,
+ .del = replmd_delete,
.extended = replmd_extended,
.start_transaction = replmd_start_transaction,
.prepare_commit = replmd_prepare_commit,
diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c
index ee7e42ef9b..a461a94806 100644
--- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c
+++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c
@@ -38,6 +38,7 @@
#include "dsdb/samdb/ldb_modules/util.h"
#include "dsdb/samdb/samdb.h"
+#include "librpc/ndr/libndr.h"
static int read_at_rootdse_record(struct ldb_context *ldb, struct ldb_module *module, TALLOC_CTX *mem_ctx,
struct ldb_message **msg)
@@ -135,6 +136,55 @@ static int prepare_modules_line(struct ldb_context *ldb,
return ret;
}
+
+
+/*
+ initialise the invocationID for a standalone server
+ */
+static int initialise_invocation_id(struct ldb_module *module, struct GUID *guid)
+{
+ struct ldb_message *msg;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret;
+
+ *guid = GUID_random();
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = ldb_dn_new(msg, ldb, "@SAMBA_DSDB");
+ if (!msg->dn) {
+ ldb_module_oom(module);
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = dsdb_msg_add_guid(msg, guid, "invocationID");
+ if (ret != LDB_SUCCESS) {
+ ldb_module_oom(module);
+ talloc_free(msg);
+ return ret;
+ }
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to setup standalone invocationID - %s",
+ ldb_errstring(ldb));
+ talloc_free(msg);
+ return ret;
+ }
+
+ DEBUG(1,("Initialised standalone invocationID to %s\n",
+ GUID_string(msg, guid)));
+
+ talloc_free(msg);
+
+ return LDB_SUCCESS;
+}
+
+
static int samba_dsdb_init(struct ldb_module *module)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
@@ -184,16 +234,11 @@ static int samba_dsdb_init(struct ldb_module *module)
"instancetype",
NULL };
- const char *objectguid_module;
- /* if serverrole == "domain controller": */
- const char *repl_meta_data = "repl_meta_data";
- /* else: */
- const char *objectguid = "objectguid";
-
const char **link_modules;
static const char *tdb_modules_list[] = {
- "subtree_rename",
"subtree_delete",
+ "repl_meta_data",
+ "subtree_rename",
"linked_attributes",
NULL};
@@ -213,7 +258,7 @@ static int samba_dsdb_init(struct ldb_module *module)
static const char *openldap_backend_modules[] = {
"entryuuid", "paged_searches", NULL };
- static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", NULL };
+ static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", "invocationID", NULL };
const char *backendType, *serverRole;
if (!tmp_ctx) {
@@ -248,17 +293,39 @@ static int samba_dsdb_init(struct ldb_module *module)
return ret;
}
+ if (strcmp(serverRole, "standalone") == 0 ||
+ strcmp(serverRole, "member server") == 0) {
+ struct GUID *guid;
+
+ guid = talloc(module, struct GUID);
+ if (!guid) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *guid = samdb_result_guid(res->msgs[0], "invocationID");
+ if (GUID_all_zero(guid)) {
+ ret = initialise_invocation_id(module, guid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ /* cache the domain_sid in the ldb. See the matching
+ * code in samdb_ntds_invocation_id() */
+ ret = ldb_set_opaque(ldb, "cache.invocation_id", guid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
backend_modules = NULL;
if (strcasecmp(backendType, "ldb") == 0) {
- if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) {
- objectguid_module = repl_meta_data;
- } else {
- objectguid_module = objectguid;
- }
extended_dn_module = extended_dn_module_ldb;
link_modules = tdb_modules_list;
} else {
- objectguid_module = NULL;
link_modules = NULL;
if (strcasecmp(backendType, "fedora-ds") == 0) {
backend_modules = fedora_ds_backend_modules;
@@ -281,9 +348,6 @@ static int samba_dsdb_init(struct ldb_module *module)
final_module_list = str_list_copy_const(tmp_ctx, modules_list);
CHECK_MODULE_LIST;
- final_module_list = str_list_add_const(final_module_list, objectguid_module);
- CHECK_MODULE_LIST;
-
final_module_list = str_list_append_const(final_module_list, link_modules);
CHECK_MODULE_LIST;
diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c
index ed10ae6d69..2e99113953 100644
--- a/source4/dsdb/samdb/ldb_modules/schema_data.c
+++ b/source4/dsdb/samdb/ldb_modules/schema_data.c
@@ -92,6 +92,37 @@ struct schema_data_search_data {
const struct dsdb_schema *schema;
};
+/* context to be used during async operations */
+struct schema_data_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ const struct dsdb_schema *schema;
+};
+
+/* Create new context using
+ * ldb_request as memory context */
+static int _schema_data_context_new(struct ldb_module *module,
+ struct ldb_request *req,
+ struct schema_data_context **pac)
+{
+ struct schema_data_context *ac;
+ struct ldb_context *ldb;
+
+ ldb = ldb_module_get_ctx(module);
+
+ *pac = ac = talloc_zero(req, struct schema_data_context);
+ if (ac == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->module = module;
+ ac->req = req;
+ ac->schema = dsdb_get_schema(ldb);
+
+ return LDB_SUCCESS;
+}
+
static int schema_data_init(struct ldb_module *module)
{
struct ldb_context *ldb;
@@ -132,6 +163,57 @@ static int schema_data_init(struct ldb_module *module)
return LDB_SUCCESS;
}
+
+/* Generate new value for msDs-IntId
+ * Value should be in 0x80000000..0xBFFFFFFF range
+ * Generated value is added ldb_msg */
+static int _schema_data_gen_msds_intid(struct schema_data_context *ac,
+ struct ldb_message *ldb_msg)
+{
+ uint32_t id;
+
+ /* generate random num in 0x80000000..0xBFFFFFFF */
+ id = generate_random() % 0X3FFFFFFF;
+ id += 0x80000000;
+
+ /* make sure id is unique and adjust if not */
+ while (dsdb_attribute_by_attributeID_id(ac->schema, id)) {
+ id++;
+ if (id > 0xBFFFFFFF) {
+ id = 0x80000001;
+ }
+ }
+
+ /* add generated msDS-IntId value to ldb_msg */
+ return ldb_msg_add_fmt(ldb_msg, "msDS-IntId", "%d", id);
+}
+
+static int _schema_data_add_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct schema_data_context *ac;
+
+ ac = talloc_get_type(req->context, struct schema_data_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+}
+
static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb;
@@ -140,7 +222,6 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
const struct ldb_val *governsID = NULL;
const char *oid_attr = NULL;
const char *oid = NULL;
- uint32_t attid;
WERROR status;
ldb = ldb_module_get_ctx(module);
@@ -170,6 +251,11 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
if (attributeID) {
+ /* Sanity check for not allowed attributes */
+ if (ldb_msg_find_ldb_val(req->op.add.message, "msDS-IntId")) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
oid_attr = "attributeID";
oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
} else if (governsID) {
@@ -183,25 +269,83 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
-
- status = dsdb_schema_pfm_make_attid(schema->prefixmap, oid, &attid);
- if (W_ERROR_IS_OK(status)) {
+
+ status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL);
+ if (!W_ERROR_IS_OK(status)) {
+ /* check for internal errors */
+ if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
+ ldb_debug_set(ldb, LDB_DEBUG_ERROR,
+ "schema_data_add: failed to map %s[%s]: %s\n",
+ oid_attr, oid, win_errstr(status));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ /* Update prefixMap and save it */
+ status = dsdb_create_prefix_mapping(ldb, schema, oid);
+ if (!W_ERROR_IS_OK(status)) {
+ ldb_debug_set(ldb, LDB_DEBUG_ERROR,
+ "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
+ oid_attr, oid, win_errstr(status));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ /* generate and add msDS-IntId attr value */
+ if (attributeID
+ && (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2003)
+ && !(ldb_msg_find_attr_as_uint(req->op.add.message, "systemFlags", 0) & SYSTEM_FLAG_SCHEMA_BASE_OBJECT)) {
+ struct ldb_message *msg;
+ struct schema_data_context *ac;
+ struct ldb_request *add_req;
+
+ if (_schema_data_context_new(module, req, &ac) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* we have to copy the message as the caller might have it as a const */
+ msg = ldb_msg_copy_shallow(ac, req->op.add.message);
+ if (msg == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* generate unique value for msDS-IntId attr value */
+ if (_schema_data_gen_msds_intid(ac, msg) != LDB_SUCCESS) {
+ ldb_debug_set(ldb, LDB_DEBUG_ERROR,
+ "_schema_data_gen_msds_intid() failed to generate msDS-IntId value\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_build_add_req(&add_req, ldb, ac,
+ msg,
+ req->controls,
+ ac, _schema_data_add_callback,
+ req);
+
+ return ldb_next_request(module, add_req);
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static int schema_data_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ /* special objects should always go through */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
return ldb_next_request(module, req);
- } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
- ldb_debug_set(ldb, LDB_DEBUG_ERROR,
- "schema_data_add: failed to map %s[%s]: %s\n",
- oid_attr, oid, win_errstr(status));
- return LDB_ERR_UNWILLING_TO_PERFORM;
}
- status = dsdb_create_prefix_mapping(ldb, schema, oid);
- if (!W_ERROR_IS_OK(status)) {
- ldb_debug_set(ldb, LDB_DEBUG_ERROR,
- "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
- oid_attr, oid, win_errstr(status));
- return LDB_ERR_UNWILLING_TO_PERFORM;
+ /* replicated update should always go through */
+ if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* msDS-IntId is not allowed to be modified */
+ if (ldb_msg_find_ldb_val(req->op.mod.message, "msDS-IntId")) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ /* go on with the call chain */
return ldb_next_request(module, req);
}
@@ -460,5 +604,6 @@ _PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = {
.name = "schema_data",
.init_context = schema_data_init,
.add = schema_data_add,
+ .modify = schema_data_modify,
.search = schema_data_search
};
diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
index 43402248c0..bf9cd4fdda 100644
--- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
+++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
@@ -181,7 +181,7 @@ static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx
static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
{
- char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
+ char *entryCSN = talloc_strndup(ctx, (const char *)val->data, val->length);
char *mod_per_sec;
time_t t;
unsigned long long usn;
@@ -232,10 +232,10 @@ static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ct
static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
{
struct ldb_val out;
- time_t t;
+ time_t t=0;
unsigned long long usn;
- t = ldb_string_to_time((const char *)val->data);
+ ldb_val_to_time(val, &t);
usn = ((unsigned long long)t <<24);
diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
index 8d9930a81f..32b79a6701 100644
--- a/source4/dsdb/samdb/ldb_modules/util.c
+++ b/source4/dsdb/samdb/ldb_modules/util.c
@@ -87,6 +87,13 @@ int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req
}
}
+ if (dsdb_flags & DSDB_MODIFY_RELAX) {
+ ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
return LDB_SUCCESS;
}
@@ -164,15 +171,21 @@ int dsdb_module_search(struct ldb_module *module,
struct ldb_dn *basedn, enum ldb_scope scope,
const char * const *attrs,
int dsdb_flags,
- const char *expression)
+ const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
{
int ret;
struct ldb_request *req;
TALLOC_CTX *tmp_ctx;
struct ldb_result *res;
+ va_list ap;
+ char *expression;
tmp_ctx = talloc_new(mem_ctx);
+ va_start(ap, format);
+ expression = talloc_vasprintf(tmp_ctx, format, ap);
+ va_end(ap);
+
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
return LDB_ERR_OPERATIONS_ERROR;
@@ -198,7 +211,12 @@ int dsdb_module_search(struct ldb_module *module,
return ret;
}
- ret = ldb_next_request(module, req);
+ if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
+ const struct ldb_module_ops *ops = ldb_module_get_ops(module);
+ ret = ops->search(module, req);
+ } else {
+ ret = ldb_next_request(module, req);
+ }
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
@@ -219,22 +237,15 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
{
struct ldb_result *res;
const char *attrs[] = { NULL };
- char *expression;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
int ret;
- expression = talloc_asprintf(tmp_ctx, "objectGUID=%s", GUID_string(tmp_ctx, guid));
- if (!expression) {
- ldb_module_oom(module);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
attrs,
DSDB_SEARCH_SHOW_DELETED |
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
- expression);
+ "objectGUID=%s", GUID_string(tmp_ctx, guid));
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
@@ -244,8 +255,8 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
return LDB_ERR_NO_SUCH_OBJECT;
}
if (res->count != 1) {
- ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching %s\n",
- expression);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
+ GUID_string(tmp_ctx, guid));
talloc_free(tmp_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -257,6 +268,37 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
}
/*
+ find a GUID given a DN.
+ */
+int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
+{
+ const char *attrs[] = { NULL };
+ struct ldb_result *res;
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+ int ret;
+ NTSTATUS status;
+
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
+ DSDB_SEARCH_SHOW_DELETED|
+ DSDB_SEARCH_SHOW_EXTENDED_DN);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
+ ldb_dn_get_linearized(dn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+/*
a ldb_modify request operating on modules below the
current module
*/
@@ -287,7 +329,12 @@ int dsdb_module_modify(struct ldb_module *module,
}
/* Run the new request */
- ret = ldb_next_request(module, mod_req);
+ if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
+ const struct ldb_module_ops *ops = ldb_module_get_ops(module);
+ ret = ops->modify(module, mod_req);
+ } else {
+ ret = ldb_next_request(module, mod_req);
+ }
if (ret == LDB_SUCCESS) {
ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
}
@@ -330,7 +377,12 @@ int dsdb_module_rename(struct ldb_module *module,
}
/* Run the new request */
- ret = ldb_next_request(module, req);
+ if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
+ const struct ldb_module_ops *ops = ldb_module_get_ops(module);
+ ret = ops->rename(module, req);
+ } else {
+ ret = ldb_next_request(module, req);
+ }
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
@@ -365,3 +417,32 @@ const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *sc
return last_class;
}
+
+/*
+ check if a single valued link has multiple non-deleted values
+
+ This is needed when we will be using the RELAX control to stop
+ ldb_tdb from checking single valued links
+ */
+int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
+ const struct ldb_message_element *el)
+{
+ bool found_active = false;
+ int i;
+
+ if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
+ el->num_values < 2) {
+ return LDB_SUCCESS;
+ }
+
+ for (i=0; i<el->num_values; i++) {
+ if (!dsdb_dn_is_deleted_val(&el->values[i])) {
+ if (found_active) {
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ found_active = true;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h
index 41ed883dc2..add39e110a 100644
--- a/source4/dsdb/samdb/ldb_modules/util.h
+++ b/source4/dsdb/samdb/ldb_modules/util.h
@@ -21,6 +21,8 @@
struct dsdb_schema; /* predeclare schema struct */
struct GUID;
+struct dsdb_attribute;
+
#include "dsdb/samdb/ldb_modules/util_proto.h"
#define DSDB_SEARCH_SEARCH_ALL_PARTITIONS 0x0001
@@ -28,3 +30,5 @@ struct GUID;
#define DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT 0x0004
#define DSDB_SEARCH_REVEAL_INTERNALS 0x0008
#define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010
+#define DSDB_MODIFY_RELAX 0x0020
+#define DSDB_FLAG_OWN_MODULE 0x0040
diff --git a/source4/dsdb/schema/prefixmap.h b/source4/dsdb/schema/prefixmap.h
index 816ddcfbb3..74acecb4ff 100644
--- a/source4/dsdb/schema/prefixmap.h
+++ b/source4/dsdb/schema/prefixmap.h
@@ -23,6 +23,17 @@
#define _DSDB_PREFIXMAP_H
/**
+ * ATTRTYP ranges
+ * Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP
+ */
+enum dsdb_attid_type {
+ dsdb_attid_type_pfm = 1, /* attid in [0x00000000..0x7FFFFFFF] */
+ dsdb_attid_type_intid = 2, /* attid in [0x80000000..0xBFFFFFFF] */
+ dsdb_attid_type_reserved = 3, /* attid in [0xC0000000..0xFFFEFFFF] */
+ dsdb_attid_type_internal = 4, /* attid in [0xFFFF0000..0xFFFFFFFF] */
+};
+
+/**
* oid-prefix in prefixmap
*/
struct dsdb_schema_prefixmap_oid {
diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c
index 4af36838cd..ccdf97cf2d 100644
--- a/source4/dsdb/schema/schema_init.c
+++ b/source4/dsdb/schema/schema_init.c
@@ -310,7 +310,7 @@ WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_co
return WERR_NOMEM;
}
- ldb_ret = samdb_replace( ldb, msg, msg );
+ ldb_ret = samdb_replace_as_system(ldb, temp_ctx, msg);
talloc_free(temp_ctx);
@@ -558,14 +558,19 @@ WERROR dsdb_attribute_from_ldb(struct ldb_context *ldb,
/* set an invalid value */
attr->attributeID_id = 0xFFFFFFFF;
} else {
- status = dsdb_schema_pfm_make_attid(schema->prefixmap,
- attr->attributeID_oid,
- &attr->attributeID_id);
- if (!W_ERROR_IS_OK(status)) {
- DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
- __location__, attr->lDAPDisplayName, attr->attributeID_oid,
- win_errstr(status)));
- return status;
+ /* check if msDS-IntId element is set */
+ attr->attributeID_id = samdb_result_uint(msg, "msDS-IntId", 0xFFFFFFFF);
+ if (attr->attributeID_id == 0xFFFFFFFF) {
+ /* msDS-IntId is not set, make */
+ status = dsdb_schema_pfm_make_attid(schema->prefixmap,
+ attr->attributeID_oid,
+ &attr->attributeID_id);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
+ __location__, attr->lDAPDisplayName, attr->attributeID_oid,
+ win_errstr(status)));
+ return status;
+ }
}
}
GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c
index 969b357a39..89d33779e4 100644
--- a/source4/dsdb/schema/schema_prefixmap.c
+++ b/source4/dsdb/schema/schema_prefixmap.c
@@ -27,6 +27,25 @@
/**
+ * Determine range type for supplied ATTID
+ */
+enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid)
+{
+ if (attid <= 0x7FFFFFFF) {
+ return dsdb_attid_type_pfm;
+ }
+ else if (attid <= 0xBFFFFFFF) {
+ return dsdb_attid_type_intid;
+ }
+ else if (attid <= 0xFFFEFFFF) {
+ return dsdb_attid_type_reserved;
+ }
+ else {
+ return dsdb_attid_type_internal;
+ }
+}
+
+/**
* Allocates schema_prefixMap object in supplied memory context
*/
static struct dsdb_schema_prefixmap *_dsdb_schema_prefixmap_talloc(TALLOC_CTX *mem_ctx,
@@ -303,6 +322,11 @@ WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_
struct dsdb_schema_prefixmap_oid *pfm_entry;
WERROR werr = WERR_OK;
+ /* sanity check for attid requested */
+ if (dsdb_pfm_get_attid_type(attid) != dsdb_attid_type_pfm) {
+ return WERR_INVALID_PARAMETER;
+ }
+
/* crack attid value */
hi_word = attid >> 16;
lo_word = attid & 0xFFFF;
diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c
index f563f01272..df17787f38 100644
--- a/source4/dsdb/schema/schema_query.c
+++ b/source4/dsdb/schema/schema_query.c
@@ -31,7 +31,8 @@ static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
static int uint32_cmp(uint32_t c1, uint32_t c2)
{
- return c1 - c2;
+ if (c1 == c2) return 0;
+ return c1 > c2 ? 1 : -1;
}
static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str)
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
index e65e372623..f59fc32696 100644
--- a/source4/dsdb/schema/schema_set.c
+++ b/source4/dsdb/schema/schema_set.c
@@ -180,13 +180,19 @@ op_error:
return LDB_ERR_OPERATIONS_ERROR;
}
+static int uint32_cmp(uint32_t c1, uint32_t c2)
+{
+ if (c1 == c2) return 0;
+ return c1 > c2 ? 1 : -1;
+}
+
static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
{
return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
}
static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
{
- return (*c1)->governsID_id - (*c2)->governsID_id;
+ return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
}
static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
{
@@ -203,7 +209,7 @@ static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return (*a1)->attributeID_id - (*a2)->attributeID_id;
+ return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
}
static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
@@ -211,7 +217,7 @@ static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return (*a1)->linkID - (*a2)->linkID;
+ return uint32_cmp((*a1)->linkID, (*a2)->linkID);
}
/*
diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c
index 1989db0699..de52b9c628 100644
--- a/source4/dsdb/schema/schema_syntax.c
+++ b/source4/dsdb/schema/schema_syntax.c
@@ -488,13 +488,17 @@ static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(struct ldb_context *ldb,
for (i=0; i < in->num_values; i++) {
NTTIME v;
time_t t;
+ int ret;
out->value_ctr.values[i].blob = &blobs[i];
blobs[i] = data_blob_talloc(blobs, NULL, 8);
W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
- t = ldb_string_to_time((const char *)in->values[i].data);
+ ret = ldb_val_to_time(&in->values[i], &t);
+ if (ret != LDB_SUCCESS) {
+ return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
+ }
unix_to_nt_time(&v, t);
v /= 10000000;
@@ -735,7 +739,10 @@ static WERROR _dsdb_syntax_OID_obj_ldb_to_drsuapi(struct ldb_context *ldb,
blobs[i] = data_blob_talloc(blobs, NULL, 4);
W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
- obj_class = dsdb_class_by_lDAPDisplayName(schema, (const char *)in->values[i].data);
+ /* in DRS windows puts the classes in the opposite
+ order to the order used in ldap */
+ obj_class = dsdb_class_by_lDAPDisplayName(schema,
+ (const char *)in->values[(in->num_values-1)-i].data);
if (!obj_class) {
return WERR_FOOBAR;
}
@@ -1074,20 +1081,21 @@ WERROR dsdb_syntax_one_DN_drsuapi_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context
W_ERROR_HAVE_NO_MEMORY(dn);
}
- status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- return ntstatus_to_werror(status);
- }
+ if (!GUID_all_zero(&id3.guid)) {
+ status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return ntstatus_to_werror(status);
+ }
- ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return WERR_FOOBAR;
+ ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return WERR_FOOBAR;
+ }
+ talloc_free(guid_blob.data);
}
- talloc_free(guid_blob.data);
-
if (id3.__ndr_size_sid) {
DATA_BLOB sid_blob;
ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, iconv_convenience, &id3.sid,
@@ -1183,7 +1191,7 @@ static WERROR dsdb_syntax_DN_ldb_to_drsuapi(struct ldb_context *ldb,
ZERO_STRUCT(id3);
- status = dsdb_get_extended_dn_guid(dn, &id3.guid);
+ status = dsdb_get_extended_dn_guid(dn, &id3.guid, "GUID");
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
talloc_free(tmp_ctx);
@@ -1367,7 +1375,7 @@ static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(struct ldb_context *ldb,
ZERO_STRUCT(id3);
- status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid);
+ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid, "GUID");
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
talloc_free(tmp_ctx);
diff --git a/source4/heimdal_build/external.m4 b/source4/heimdal_build/external.m4
index 3cd8900a12..ad9443f999 100644
--- a/source4/heimdal_build/external.m4
+++ b/source4/heimdal_build/external.m4
@@ -12,7 +12,7 @@ SMB_EXT_LIB(HEIMDAL_KRB5,
[${HEIMDAL_KRB5_CFLAGS}],
[${HEIMDAL_KRB5_CPPFLAGS}],
[${HEIMDAL_KRB5_LDFLAGS}])
-SMB_ENABLE(HEIMDAL_KRB5)
+SMB_ENABLE(HEIMDAL_KRB5,YES)
AC_DEFINE(HAVE_KRB5,1,[Whether kerberos is available])
HAVE_KRB5=YES
AC_DEFINE(HAVE_COM_ERR,1,[Whether com_err is available])
@@ -27,7 +27,7 @@ SMB_EXT_LIB(HEIMDAL_GSSAPI,
[${HEIMDAL_GSSAPI_CFLAGS}],
[${HEIMDAL_GSSAPI_CPPFLAGS}],
[${HEIMDAL_GSSAPI_LDFLAGS}])
-SMB_ENABLE(HEIMDAL_GSSAPI)
+SMB_ENABLE(HEIMDAL_GSSAPI,YES)
AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available])
HAVE_GSSAPI=YES
@@ -40,7 +40,7 @@ SMB_EXT_LIB(HEIMDAL_HDB,
[${HEIMDAL_HDB_CFLAGS}],
[${HEIMDAL_HDB_CPPFLAGS}],
[${HEIMDAL_HDB_LDFLAGS}])
-SMB_ENABLE(HEIMDAL_HDB)
+SMB_ENABLE(HEIMDAL_HDB,YES)
HEIMDAL_KDC_LIBS="-lkdc"
HEIMDAL_KDC_CFLAGS=""
@@ -51,4 +51,4 @@ SMB_EXT_LIB(HEIMDAL_KDC,
[${HEIMDAL_KDC_CFLAGS}],
[${HEIMDAL_KDC_CPPFLAGS}],
[${HEIMDAL_KDC_LDFLAGS}])
-SMB_ENABLE(HEIMDAL_KDC)
+SMB_ENABLE(HEIMDAL_KDC,YES)
diff --git a/source4/kdc/config.mk b/source4/kdc/config.mk
index 7a99857248..a9d01585f0 100644
--- a/source4/kdc/config.mk
+++ b/source4/kdc/config.mk
@@ -6,7 +6,8 @@
INIT_FUNCTION = server_service_kdc_init
SUBSYSTEM = service
PRIVATE_DEPENDENCIES = \
- HEIMDAL_KDC HDB_SAMBA4 PAC_GLUE LIBSAMBA-HOSTCONFIG
+ HEIMDAL_KDC HDB_SAMBA4 PAC_GLUE LIBSAMBA-HOSTCONFIG \
+ LIBTSOCKET
# End SUBSYSTEM KDC
#######################
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c
index 2418e5c63f..2f3c30c283 100644
--- a/source4/kdc/hdb-samba4.c
+++ b/source4/kdc/hdb-samba4.c
@@ -53,13 +53,13 @@
#include "kdc/kdc.h"
#include "../lib/crypto/md4.h"
-enum hdb_samba4_ent_type
-{ HDB_SAMBA4_ENT_TYPE_CLIENT, HDB_SAMBA4_ENT_TYPE_SERVER,
+enum hdb_samba4_ent_type
+{ HDB_SAMBA4_ENT_TYPE_CLIENT, HDB_SAMBA4_ENT_TYPE_SERVER,
HDB_SAMBA4_ENT_TYPE_KRBTGT, HDB_SAMBA4_ENT_TYPE_TRUST, HDB_SAMBA4_ENT_TYPE_ANY };
enum trust_direction {
UNKNOWN = 0,
- INBOUND = LSA_TRUST_DIRECTION_INBOUND,
+ INBOUND = LSA_TRUST_DIRECTION_INBOUND,
OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
};
@@ -93,7 +93,7 @@ static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, con
return timegm(&tm);
}
-static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_samba4_ent_type ent_type)
+static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_samba4_ent_type ent_type)
{
HDBFlags flags = int2HDBFlags(0);
@@ -115,7 +115,7 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h
}
flags.invalid = 0;
}
-
+
if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) {
flags.client = 1;
@@ -166,7 +166,7 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h
}
if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
flags.ok_as_delegate = 1;
- }
+ }
if (!(userAccountControl & UF_NOT_DELEGATED)) {
flags.forwardable = 1;
flags.proxiable = 1;
@@ -334,7 +334,7 @@ static krb5_error_code hdb_samba4_message2entry_keys(krb5_context context,
ret = krb5_keyblock_init(context,
ENCTYPE_ARCFOUR_HMAC,
- hash->hash, sizeof(hash->hash),
+ hash->hash, sizeof(hash->hash),
&key.key);
if (ret) {
goto out;
@@ -490,8 +490,8 @@ out:
/*
* Construct an hdb_entry from a directory entry.
*/
-static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
- struct loadparm_context *lp_ctx,
+static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
TALLOC_CTX *mem_ctx, krb5_const_principal principal,
enum hdb_samba4_ent_type ent_type,
struct ldb_dn *realm_dn,
@@ -514,7 +514,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
computer_val.data = discard_const_p(uint8_t,"computer");
computer_val.length = strlen((const char *)computer_val.data);
-
+
if (!samAccountName) {
ret = ENOENT;
krb5_set_error_message(context, ret, "hdb_samba4_message2entry: no samAccountName present");
@@ -522,7 +522,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
}
objectclasses = ldb_msg_find_element(msg, "objectClass");
-
+
if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
is_computer = TRUE;
}
@@ -534,7 +534,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
krb5_set_error_message(context, ret, "talloc_strdup: out of memory");
goto out;
}
-
+
p = talloc(mem_ctx, struct hdb_samba4_private);
if (!p) {
ret = ENOMEM;
@@ -557,7 +557,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
-
+
entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
if (ent_type == HDB_SAMBA4_ENT_TYPE_ANY && principal == NULL) {
krb5_make_principal(context, &entry_ex->entry.principal, realm, samAccountName, NULL);
@@ -573,7 +573,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
* the client-specified realm. This code attempts to
* replace the client principal's realm with the one
* we determine from our records */
-
+
/* this has to be with malloc() */
krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
}
@@ -598,19 +598,19 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
* of the Heimdal KDC. They are stored in a the traditional
* DB for audit purposes, and still form part of the structure
* we must return */
-
+
/* use 'whenCreated' */
entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
/* use '???' */
entry_ex->entry.created_by.principal = NULL;
-
+
entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event));
if (entry_ex->entry.modified_by == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
-
+
/* use 'whenChanged' */
entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
/* use '???' */
@@ -661,7 +661,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
} else {
NTTIME must_change_time
- = samdb_result_force_password_change((struct ldb_context *)db->hdb_db, mem_ctx,
+ = samdb_result_force_password_change((struct ldb_context *)db->hdb_db, mem_ctx,
realm_dn, msg);
if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
entry_ex->entry.pw_end = NULL;
@@ -722,7 +722,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db,
p->msg = talloc_steal(p, msg);
p->samdb = (struct ldb_context *)db->hdb_db;
-
+
out:
if (ret != 0) {
/* This doesn't free ent itself, that is for the eventual caller to do */
@@ -737,7 +737,7 @@ out:
/*
* Construct an hdb_entry from a directory entry.
*/
-static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB *db,
+static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB *db,
struct loadparm_context *lp_ctx,
TALLOC_CTX *mem_ctx, krb5_const_principal principal,
enum trust_direction direction,
@@ -745,7 +745,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB
struct ldb_message *msg,
hdb_entry_ex *entry_ex)
{
-
+
const char *dnsdomain;
char *realm;
DATA_BLOB password_utf16;
@@ -843,16 +843,16 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB
ret = ENOMEM;
goto out;
}
-
+
ret = krb5_keyblock_init(context,
ENCTYPE_ARCFOUR_HMAC,
- password_hash.hash, sizeof(password_hash.hash),
+ password_hash.hash, sizeof(password_hash.hash),
&key.key);
-
+
entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
entry_ex->entry.keys.len++;
}
-
+
entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
ret = copy_Principal(principal, entry_ex->entry.principal);
@@ -860,13 +860,13 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB
krb5_clear_error_message(context);
goto out;
}
-
+
/* While we have copied the client principal, tests
* show that Win2k3 returns the 'corrected' realm, not
* the client-specified realm. This code attempts to
* replace the client principal's realm with the one
* we determine from our records */
-
+
krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
entry_ex->entry.flags = int2HDBFlags(0);
entry_ex->entry.flags.immutable = 1;
@@ -875,7 +875,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB
entry_ex->entry.flags.require_preauth = 1;
entry_ex->entry.pw_end = NULL;
-
+
entry_ex->entry.max_life = NULL;
entry_ex->entry.max_renew = NULL;
@@ -902,7 +902,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB
p->msg = talloc_steal(p, msg);
p->samdb = (struct ldb_context *)db->hdb_db;
-
+
out:
if (ret != 0) {
/* This doesn't free ent itself, that is for the eventual caller to do */
@@ -915,7 +915,7 @@ out:
}
-static krb5_error_code hdb_samba4_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
+static krb5_error_code hdb_samba4_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
TALLOC_CTX *mem_ctx,
const char *realm,
struct ldb_dn *realm_dn,
@@ -959,7 +959,7 @@ static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags,
krb5_warnx(context, "hdb_samba4_open: use of a master key incompatible with LDB\n");
krb5_set_error_message(context, ret, "hdb_samba4_open: use of a master key incompatible with LDB\n");
return ret;
- }
+ }
return 0;
}
@@ -984,25 +984,25 @@ static krb5_error_code hdb_samba4_rename(krb5_context context, HDB *db, const ch
return HDB_ERR_DB_INUSE;
}
-static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db,
- struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
+static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
krb5_const_principal principal,
const char **attrs,
- struct ldb_dn **realm_dn,
+ struct ldb_dn **realm_dn,
struct ldb_message **msg) {
NTSTATUS nt_status;
char *principal_string;
krb5_error_code ret;
ret = krb5_unparse_name(context, principal, &principal_string);
-
+
if (ret != 0) {
return ret;
}
-
+
nt_status = sam_get_results_principal((struct ldb_context *)db->hdb_db,
- mem_ctx, principal_string, attrs,
+ mem_ctx, principal_string, attrs,
realm_dn, msg);
free(principal_string);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
@@ -1012,13 +1012,13 @@ static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db,
} else if (!NT_STATUS_IS_OK(nt_status)) {
return EINVAL;
}
-
+
return ret;
}
-static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
- struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
+static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
krb5_const_principal principal,
unsigned flags,
hdb_entry_ex *entry_ex) {
@@ -1026,22 +1026,22 @@ static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
krb5_error_code ret;
struct ldb_message *msg = NULL;
- ret = hdb_samba4_lookup_client(context, db, lp_ctx,
- mem_ctx, principal, user_attrs,
+ ret = hdb_samba4_lookup_client(context, db, lp_ctx,
+ mem_ctx, principal, user_attrs,
&realm_dn, &msg);
if (ret != 0) {
return ret;
}
-
- ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
+
+ ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
principal, HDB_SAMBA4_ENT_TYPE_CLIENT,
realm_dn, msg, entry_ex);
return ret;
}
-static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
- struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
+static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
krb5_const_principal principal,
unsigned flags,
hdb_entry_ex *entry_ex)
@@ -1062,18 +1062,18 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
if (lp_is_my_domain_or_realm(lp_ctx, principal->realm)
&& lp_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) {
- /* us */
+ /* us */
/* Cludge, cludge cludge. If the realm part of krbtgt/realm,
* is in our db, then direct the caller at our primary
* krbtgt */
int lret;
char *realm_fixed;
-
- lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,
+
+ lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,
realm_dn, LDB_SCOPE_SUBTREE,
- &msg, krbtgt_attrs,
- "(&(objectClass=user)(samAccountName=krbtgt))");
+ &msg, krbtgt_attrs,
+ "(&(objectClass=user)(samAccountName=krbtgt))");
if (lret == LDB_ERR_NO_SUCH_OBJECT) {
krb5_warnx(context, "hdb_samba4_fetch: could not find own KRBTGT in DB!");
krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB!");
@@ -1083,19 +1083,19 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(db->hdb_db));
return HDB_ERR_NOENTRY;
}
-
+
realm_fixed = strupper_talloc(mem_ctx, lp_realm(lp_ctx));
if (!realm_fixed) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "strupper_talloc: out of memory");
return ret;
}
-
+
ret = krb5_copy_principal(context, principal, &alloc_principal);
if (ret) {
return ret;
}
-
+
free(alloc_principal->name.name_string.val[1]);
alloc_principal->name.name_string.val[1] = strdup(realm_fixed);
talloc_free(realm_fixed);
@@ -1106,11 +1106,11 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
}
principal = alloc_principal;
- ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
- principal, HDB_SAMBA4_ENT_TYPE_KRBTGT,
+ ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
+ principal, HDB_SAMBA4_ENT_TYPE_KRBTGT,
realm_dn, msg, entry_ex);
if (ret != 0) {
- krb5_warnx(context, "hdb_samba4_fetch: self krbtgt message2entry failed");
+ krb5_warnx(context, "hdb_samba4_fetch: self krbtgt message2entry failed");
}
return ret;
@@ -1132,35 +1132,35 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,
}
/* Trusted domains are under CN=system */
-
- ret = hdb_samba4_lookup_trust(context, (struct ldb_context *)db->hdb_db,
- mem_ctx,
+
+ ret = hdb_samba4_lookup_trust(context, (struct ldb_context *)db->hdb_db,
+ mem_ctx,
realm, realm_dn, &msg);
-
+
if (ret != 0) {
krb5_warnx(context, "hdb_samba4_fetch: could not find principal in DB");
krb5_set_error_message(context, ret, "hdb_samba4_fetch: could not find principal in DB");
return ret;
}
-
- ret = hdb_samba4_trust_message2entry(context, db, lp_ctx, mem_ctx,
- principal, direction,
+
+ ret = hdb_samba4_trust_message2entry(context, db, lp_ctx, mem_ctx,
+ principal, direction,
realm_dn, msg, entry_ex);
if (ret != 0) {
- krb5_warnx(context, "hdb_samba4_fetch: trust_message2entry failed");
+ krb5_warnx(context, "hdb_samba4_fetch: trust_message2entry failed");
}
return ret;
-
+
/* we should lookup trusted domains */
return HDB_ERR_NOENTRY;
}
}
-static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
+static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
krb5_const_principal principal,
const char **attrs,
struct ldb_dn **realm_dn,
@@ -1174,35 +1174,35 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
NTSTATUS nt_status;
struct ldb_dn *user_dn;
char *principal_string;
-
- ret = krb5_unparse_name_flags(context, principal,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+
+ ret = krb5_unparse_name_flags(context, principal,
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM,
&principal_string);
if (ret != 0) {
return ret;
}
-
+
/* At this point we may find the host is known to be
* in a different realm, so we should generate a
* referral instead */
nt_status = crack_service_principal_name((struct ldb_context *)db->hdb_db,
- mem_ctx, principal_string,
+ mem_ctx, principal_string,
&user_dn, realm_dn);
free(principal_string);
-
+
if (!NT_STATUS_IS_OK(nt_status)) {
return HDB_ERR_NOENTRY;
}
-
+
ldb_ret = gendb_search_single_extended_dn((struct ldb_context *)db->hdb_db,
- mem_ctx,
+ mem_ctx,
user_dn, LDB_SCOPE_BASE,
msg, attrs,
"(objectClass=*)");
if (ldb_ret != LDB_SUCCESS) {
return HDB_ERR_NOENTRY;
}
-
+
} else {
int lret;
char *filter = NULL;
@@ -1210,20 +1210,20 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
/* server as client principal case, but we must not lookup userPrincipalNames */
*realm_dn = ldb_get_default_basedn(db->hdb_db);
realm = krb5_principal_get_realm(context, principal);
-
+
/* TODO: Check if it is our realm, otherwise give referall */
-
+
ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
-
+
if (ret != 0) {
krb5_set_error_message(context, ret, "hdb_samba4_lookup_principal: could not parse principal");
krb5_warnx(context, "hdb_samba4_lookup_principal: could not parse principal");
return ret;
}
-
- lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,
+
+ lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,
*realm_dn, LDB_SCOPE_SUBTREE,
- msg, attrs, "(&(objectClass=user)(samAccountName=%s))",
+ msg, attrs, "(&(objectClass=user)(samAccountName=%s))",
ldb_binary_encode_string(mem_ctx, short_princ));
free(short_princ);
if (lret == LDB_ERR_NO_SUCH_OBJECT) {
@@ -1231,7 +1231,7 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
return HDB_ERR_NOENTRY;
}
if (lret != LDB_SUCCESS) {
- DEBUG(3, ("Failed single search for for %s - %s\n",
+ DEBUG(3, ("Failed single search for for %s - %s\n",
filter, ldb_errstring(db->hdb_db)));
return HDB_ERR_NOENTRY;
}
@@ -1240,9 +1240,9 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,
return 0;
}
-static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db,
+static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db,
struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
krb5_const_principal principal,
unsigned flags,
hdb_entry_ex *entry_ex)
@@ -1251,23 +1251,23 @@ static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db,
struct ldb_dn *realm_dn;
struct ldb_message *msg;
- ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, principal,
+ ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, principal,
server_attrs, &realm_dn, &msg);
if (ret != 0) {
return ret;
}
- ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
+ ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
principal, HDB_SAMBA4_ENT_TYPE_SERVER,
realm_dn, msg, entry_ex);
if (ret != 0) {
- krb5_warnx(context, "hdb_samba4_fetch: message2entry failed");
+ krb5_warnx(context, "hdb_samba4_fetch: message2entry failed");
}
return ret;
}
-
-static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db,
+
+static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db,
krb5_const_principal principal,
unsigned flags,
hdb_entry_ex *entry_ex)
@@ -1345,9 +1345,9 @@ static krb5_error_code hdb_samba4_seq(krb5_context context, HDB *db, unsigned fl
}
if (priv->index < priv->count) {
- ret = hdb_samba4_message2entry(context, db, priv->lp_ctx,
- mem_ctx,
- NULL, HDB_SAMBA4_ENT_TYPE_ANY,
+ ret = hdb_samba4_message2entry(context, db, priv->lp_ctx,
+ mem_ctx,
+ NULL, HDB_SAMBA4_ENT_TYPE_ANY,
priv->realm_dn, priv->msgs[priv->index++], entry);
} else {
ret = HDB_ERR_NOENTRY;
@@ -1366,7 +1366,7 @@ static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsign
hdb_entry_ex *entry)
{
struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db;
- struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
+ struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
struct loadparm_context);
struct hdb_samba4_seq *priv = (struct hdb_samba4_seq *)db->hdb_dbc;
char *realm;
@@ -1407,7 +1407,7 @@ static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsign
talloc_free(priv);
return ret;
}
-
+
lret = ldb_search(ldb_ctx, priv, &res,
priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
"(objectClass=user)");
@@ -1449,14 +1449,14 @@ static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
/* Check if a given entry may delegate to this target principal
*
- * This is currently a very nasty hack - allowing only delegation to itself.
+ * This is currently a very nasty hack - allowing only delegation to itself.
*/
-krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db,
+krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db,
hdb_entry_ex *entry,
krb5_const_principal target_principal)
{
struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db;
- struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
+ struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
struct loadparm_context);
krb5_error_code ret;
krb5_principal enterprise_prinicpal = NULL;
@@ -1468,7 +1468,7 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD
const char *delegation_check_attrs[] = {
"objectSid", NULL
};
-
+
TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation");
if (!mem_ctx) {
@@ -1481,12 +1481,12 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD
/* Need to reparse the enterprise principal to find the real target */
if (target_principal->name.name_string.len != 1) {
ret = KRB5_PARSE_MALFORMED;
- krb5_set_error_message(context, ret, "hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components",
- target_principal->name.name_string.len);
+ krb5_set_error_message(context, ret, "hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components",
+ target_principal->name.name_string.len);
talloc_free(mem_ctx);
return ret;
}
- ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
+ ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
&enterprise_prinicpal);
if (ret) {
talloc_free(mem_ctx);
@@ -1495,7 +1495,7 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD
target_principal = enterprise_prinicpal;
}
- ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, target_principal,
+ ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, target_principal,
delegation_check_attrs, &realm_dn, &msg);
krb5_free_principal(context, enterprise_prinicpal);
@@ -1525,12 +1525,12 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD
* database. Allow a mismatch where they both refer to the same
* SID */
-krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db,
+krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db,
hdb_entry_ex *entry,
krb5_const_principal certificate_principal)
{
struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db;
- struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
+ struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
struct loadparm_context);
krb5_error_code ret;
struct ldb_dn *realm_dn;
@@ -1541,7 +1541,7 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *
const char *ms_upn_check_attrs[] = {
"objectSid", NULL
};
-
+
TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation");
if (!mem_ctx) {
@@ -1550,10 +1550,10 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *
return ret;
}
- ret = hdb_samba4_lookup_client(context, db, lp_ctx,
+ ret = hdb_samba4_lookup_client(context, db, lp_ctx,
mem_ctx, certificate_principal,
ms_upn_check_attrs, &realm_dn, &msg);
-
+
if (ret != 0) {
talloc_free(mem_ctx);
return ret;
@@ -1579,8 +1579,8 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *
* (hdb_samba4_create) from the kpasswdd -> krb5 -> keytab_hdb -> hdb
* code */
-NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
+NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev_ctx,
struct loadparm_context *lp_ctx,
krb5_context context, struct HDB **db)
{
@@ -1602,7 +1602,7 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
* allow us to share the samdb backend context with other parts of the
* system. For now we can't as we need to override the
* credentials to set CRED_DONT_USE_KERBEROS, which would
- * break other users of the system_session */
+ * break other users of the system_session */
DEBUG(0,("FIXME: Using new system session for hdb\n"));
nt_status = auth_system_session_info(*db, lp_ctx, &session_info);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1614,7 +1614,7 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
return NT_STATUS_INTERNAL_ERROR;
}
#endif
-
+
/* The idea here is very simple. Using Kerberos to
* authenticate the KDC to the LDAP server is higly likely to
* be circular.
@@ -1622,8 +1622,8 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
* In future we may set this up to use EXERNAL and SSL
* certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
*/
-
- cli_credentials_set_kerberos_state(session_info->credentials,
+
+ cli_credentials_set_kerberos_state(session_info->credentials,
CRED_DONT_USE_KERBEROS);
/* Setup the link to LDB */
@@ -1663,6 +1663,7 @@ static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db,
NTSTATUS nt_status;
void *ptr;
struct hdb_samba4_context *hdb_samba4_context;
+
if (sscanf(arg, "&%p", &ptr) != 1) {
return EINVAL;
}
@@ -1686,6 +1687,6 @@ static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db,
*/
struct hdb_method hdb_samba4 = {
.interface_version = HDB_INTERFACE_VERSION,
- .prefix = "samba4",
+ .prefix = "samba4",
.create = hdb_samba4_create
};
diff --git a/source4/kdc/hdb-samba4.h b/source4/kdc/hdb-samba4.h
index fc2f9c1310..5f85ce188c 100644
--- a/source4/kdc/hdb-samba4.h
+++ b/source4/kdc/hdb-samba4.h
@@ -1,21 +1,21 @@
-/*
+/*
Unix SMB/CIFS implementation.
KDC structures
Copyright (C) Andrew Tridgell 2005
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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/>.
*/
diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c
index 6a9df0bf02..93f1c7d6ec 100644
--- a/source4/kdc/kdc.c
+++ b/source4/kdc/kdc.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
KDC Server startup
@@ -11,12 +11,12 @@
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/>.
*/
@@ -42,22 +42,15 @@
#include "librpc/gen_ndr/ndr_misc.h"
-/* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when
+/* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when
* used as a keytab */
TALLOC_CTX *hdb_samba4_mem_ctx;
struct tevent_context *hdb_samba4_ev_ctx;
struct loadparm_context *hdb_samba4_lp_ctx;
-/* hold all the info needed to send a reply */
-struct kdc_reply {
- struct kdc_reply *next, *prev;
- struct socket_address *dest;
- DATA_BLOB packet;
-};
-
typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *input,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *input,
DATA_BLOB *reply,
struct tsocket_address *peer_addr,
struct tsocket_address *my_addr,
@@ -65,15 +58,11 @@ typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc,
/* hold information about one kdc socket */
struct kdc_socket {
- struct socket_context *sock;
struct kdc_server *kdc;
- struct tevent_fd *fde;
-
- /* a queue of outgoing replies that have been deferred */
- struct kdc_reply *send_queue;
-
+ struct tsocket_address *local_address;
kdc_process_fn_t process;
};
+
/*
state of an open tcp connection
*/
@@ -82,152 +71,11 @@ struct kdc_tcp_connection {
struct stream_connection *conn;
/* the kdc_server the connection belongs to */
- struct kdc_server *kdc;
+ struct kdc_socket *kdc_socket;
struct packet_context *packet;
-
- kdc_process_fn_t process;
};
-/*
- handle fd send events on a KDC socket
-*/
-static void kdc_send_handler(struct kdc_socket *kdc_socket)
-{
- while (kdc_socket->send_queue) {
- struct kdc_reply *rep = kdc_socket->send_queue;
- NTSTATUS status;
- size_t sendlen;
-
- status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,
- rep->dest);
- if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- break;
- }
- if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_BUFFER_SIZE)) {
- /* Replace with a krb err, response to big */
- }
-
- DLIST_REMOVE(kdc_socket->send_queue, rep);
- talloc_free(rep);
- }
-
- if (kdc_socket->send_queue == NULL) {
- EVENT_FD_NOT_WRITEABLE(kdc_socket->fde);
- }
-}
-
-
-/*
- handle fd recv events on a KDC socket
-*/
-static void kdc_recv_handler(struct kdc_socket *kdc_socket)
-{
- NTSTATUS status;
- TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket);
- DATA_BLOB blob;
- struct kdc_reply *rep;
- DATA_BLOB reply;
- size_t nread, dsize;
- struct socket_address *src;
- struct socket_address *my_addr;
- struct tsocket_address *tsrcaddr;
- struct tsocket_address *tmyaddr;
- int ret;
-
- status = socket_pending(kdc_socket->sock, &dsize);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- return;
- }
-
- blob = data_blob_talloc(tmp_ctx, NULL, dsize);
- if (blob.data == NULL) {
- /* hope this is a temporary low memory condition */
- talloc_free(tmp_ctx);
- return;
- }
-
- status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
- tmp_ctx, &src);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- return;
- }
- blob.length = nread;
-
- DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n",
- (long)blob.length, src->addr, (uint16_t)src->port));
-
- my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx);
- if (!my_addr) {
- talloc_free(tmp_ctx);
- return;
- }
-
- ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, src->sockaddr,
- src->sockaddrlen, &tsrcaddr);
- if (ret < 0) {
- talloc_free(tmp_ctx);
- return;
- }
-
- ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, my_addr->sockaddr,
- my_addr->sockaddrlen, &tmyaddr);
- if (ret < 0) {
- talloc_free(tmp_ctx);
- return;
- }
-
- /* Call krb5 */
- ret = kdc_socket->process(kdc_socket->kdc,
- tmp_ctx,
- &blob,
- &reply,
- tsrcaddr,
- tmyaddr,
- 1 /* Datagram */);
- if (!ret) {
- talloc_free(tmp_ctx);
- return;
- }
-
- /* queue a pending reply */
- rep = talloc(kdc_socket, struct kdc_reply);
- if (rep == NULL) {
- talloc_free(tmp_ctx);
- return;
- }
- rep->dest = talloc_steal(rep, src);
- rep->packet = reply;
- talloc_steal(rep, reply.data);
-
- if (rep->packet.data == NULL) {
- talloc_free(rep);
- talloc_free(tmp_ctx);
- return;
- }
-
- DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *);
- EVENT_FD_WRITEABLE(kdc_socket->fde);
- talloc_free(tmp_ctx);
-}
-
-/*
- handle fd events on a KDC socket
-*/
-static void kdc_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *private_data)
-{
- struct kdc_socket *kdc_socket = talloc_get_type(private_data, struct kdc_socket);
- if (flags & EVENT_FD_WRITE) {
- kdc_send_handler(kdc_socket);
- }
- if (flags & EVENT_FD_READ) {
- kdc_recv_handler(kdc_socket);
- }
-}
-
static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason)
{
stream_terminate_connection(kdcconn->conn, reason);
@@ -244,49 +92,18 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob)
TALLOC_CTX *tmp_ctx = talloc_new(kdcconn);
int ret;
DATA_BLOB input, reply;
- struct socket_address *src_addr;
- struct socket_address *my_addr;
- struct tsocket_address *tsrcaddr;
- struct tsocket_address *tmyaddr;
-
talloc_steal(tmp_ctx, blob.data);
- src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx);
- if (!src_addr) {
- talloc_free(tmp_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx);
- if (!my_addr) {
- talloc_free(tmp_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, src_addr->sockaddr,
- src_addr->sockaddrlen, &tsrcaddr);
- if (ret < 0) {
- talloc_free(tmp_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, my_addr->sockaddr,
- my_addr->sockaddrlen, &tmyaddr);
- if (ret < 0) {
- talloc_free(tmp_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
/* Call krb5 */
- input = data_blob_const(blob.data + 4, blob.length - 4);
-
- ret = kdcconn->process(kdcconn->kdc,
- tmp_ctx,
- &input,
- &reply,
- tsrcaddr,
- tmyaddr,
- 0 /* Not datagram */);
+ input = data_blob_const(blob.data + 4, blob.length - 4);
+
+ ret = kdcconn->kdc_socket->process(kdcconn->kdc_socket->kdc,
+ tmp_ctx,
+ &input,
+ &reply,
+ kdcconn->conn->remote_address,
+ kdcconn->conn->local_address,
+ 0 /* Not datagram */);
if (!ret) {
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_ERROR;
@@ -300,7 +117,7 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob)
}
RSIVAL(blob.data, 0, reply.length);
- memcpy(blob.data + 4, reply.data, reply.length);
+ memcpy(blob.data + 4, reply.data, reply.length);
status = packet_send(kdcconn->packet, blob);
if (!NT_STATUS_IS_OK(status)) {
@@ -349,8 +166,8 @@ static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
*/
static bool kdc_process(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *input,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *input,
DATA_BLOB *reply,
struct tsocket_address *peer_addr,
struct tsocket_address *my_addr,
@@ -377,7 +194,7 @@ static bool kdc_process(struct kdc_server *kdc,
DEBUG(10,("Received KDC packet of length %lu from %s\n",
(long)input->length - 4, pa));
- ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context,
+ ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context,
kdc->config,
input->data, input->length,
&k5_reply,
@@ -392,7 +209,7 @@ static bool kdc_process(struct kdc_server *kdc,
*reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
krb5_data_free(&k5_reply);
} else {
- *reply = data_blob(NULL, 0);
+ *reply = data_blob(NULL, 0);
}
return true;
}
@@ -410,9 +227,8 @@ static void kdc_tcp_accept(struct stream_connection *conn)
stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");
return;
}
- kdcconn->conn = conn;
- kdcconn->kdc = kdc_socket->kdc;
- kdcconn->process = kdc_socket->process;
+ kdcconn->conn = conn;
+ kdcconn->kdc_socket = kdc_socket;
conn->private_data = kdcconn;
kdcconn->packet = packet_init(kdcconn);
@@ -437,6 +253,105 @@ static const struct stream_server_ops kdc_tcp_stream_ops = {
.send_handler = kdc_tcp_send
};
+/* hold information about one kdc/kpasswd udp socket */
+struct kdc_udp_socket {
+ struct kdc_socket *kdc_socket;
+ struct tdgram_context *dgram;
+ struct tevent_queue *send_queue;
+};
+
+struct kdc_udp_call {
+ struct tsocket_address *src;
+ DATA_BLOB in;
+ DATA_BLOB out;
+};
+
+static void kdc_udp_call_sendto_done(struct tevent_req *subreq);
+
+static void kdc_udp_call_loop(struct tevent_req *subreq)
+{
+ struct kdc_udp_socket *sock = tevent_req_callback_data(subreq,
+ struct kdc_udp_socket);
+ struct kdc_udp_call *call;
+ uint8_t *buf;
+ ssize_t len;
+ int sys_errno;
+ int ret;
+
+ call = talloc(sock, struct kdc_udp_call);
+ if (call == NULL) {
+ talloc_free(call);
+ goto done;
+ }
+
+ len = tdgram_recvfrom_recv(subreq, &sys_errno,
+ call, &buf, &call->src);
+ TALLOC_FREE(subreq);
+ if (len == -1) {
+ talloc_free(call);
+ goto done;
+ }
+
+ call->in.data = buf;
+ call->in.length = len;
+
+ DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n",
+ (long)call->in.length,
+ tsocket_address_string(call->src, call)));
+
+ /* Call krb5 */
+ ret = sock->kdc_socket->process(sock->kdc_socket->kdc,
+ call,
+ &call->in,
+ &call->out,
+ call->src,
+ sock->kdc_socket->local_address,
+ 1 /* Datagram */);
+ if (!ret) {
+ talloc_free(call);
+ goto done;
+ }
+
+ subreq = tdgram_sendto_queue_send(call,
+ sock->kdc_socket->kdc->task->event_ctx,
+ sock->dgram,
+ sock->send_queue,
+ call->out.data,
+ call->out.length,
+ call->src);
+ if (subreq == NULL) {
+ talloc_free(call);
+ goto done;
+ }
+ tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call);
+
+done:
+ subreq = tdgram_recvfrom_send(sock,
+ sock->kdc_socket->kdc->task->event_ctx,
+ sock->dgram);
+ if (subreq == NULL) {
+ task_server_terminate(sock->kdc_socket->kdc->task,
+ "no memory for tdgram_recvfrom_send",
+ true);
+ return;
+ }
+ tevent_req_set_callback(subreq, kdc_udp_call_loop, sock);
+}
+
+static void kdc_udp_call_sendto_done(struct tevent_req *subreq)
+{
+ struct kdc_udp_call *call = tevent_req_callback_data(subreq,
+ struct kdc_udp_call);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
+
+ /* We don't care about errors */
+
+ talloc_free(call);
+}
+
/*
start listening on the given address
*/
@@ -447,47 +362,32 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc,
uint16_t port,
kdc_process_fn_t process)
{
- struct kdc_socket *kdc_socket;
- struct socket_address *socket_address;
+ struct kdc_socket *kdc_socket;
+ struct kdc_udp_socket *kdc_udp_socket;
+ struct tevent_req *udpsubreq;
NTSTATUS status;
+ int ret;
kdc_socket = talloc(kdc, struct kdc_socket);
NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
- status = socket_create("ip", SOCKET_TYPE_DGRAM, &kdc_socket->sock, 0);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(kdc_socket);
- return status;
- }
-
kdc_socket->kdc = kdc;
- kdc_socket->send_queue = NULL;
kdc_socket->process = process;
- talloc_steal(kdc_socket, kdc_socket->sock);
-
- kdc_socket->fde = event_add_fd(kdc->task->event_ctx, kdc,
- socket_get_fd(kdc_socket->sock), EVENT_FD_READ,
- kdc_socket_handler, kdc_socket);
-
- socket_address = socket_address_from_strings(kdc_socket, kdc_socket->sock->backend_name,
- address, port);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(socket_address, kdc_socket);
-
- status = socket_listen(kdc_socket->sock, socket_address, 0, 0);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("Failed to bind to %s:%d UDP for %s - %s\n",
- address, port, name, nt_errstr(status)));
- talloc_free(kdc_socket);
+ ret = tsocket_address_inet_from_strings(kdc_socket, "ip",
+ address, port,
+ &kdc_socket->local_address);
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
return status;
}
- status = stream_setup_socket(kdc->task->event_ctx,
+ status = stream_setup_socket(kdc->task->event_ctx,
kdc->task->lp_ctx,
- model_ops,
- &kdc_tcp_stream_ops,
- "ip", address, &port,
- lp_socket_options(kdc->task->lp_ctx),
+ model_ops,
+ &kdc_tcp_stream_ops,
+ "ip", address, &port,
+ lp_socket_options(kdc->task->lp_ctx),
kdc_socket);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
@@ -496,6 +396,32 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc,
return status;
}
+ kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket);
+ NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket);
+
+ kdc_udp_socket->kdc_socket = kdc_socket;
+
+ ret = tdgram_inet_udp_socket(kdc_socket->local_address,
+ NULL,
+ kdc_udp_socket,
+ &kdc_udp_socket->dgram);
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
+ address, port, nt_errstr(status)));
+ return status;
+ }
+
+ kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket,
+ "kdc_udp_send_queue");
+ NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue);
+
+ udpsubreq = tdgram_recvfrom_send(kdc_udp_socket,
+ kdc->task->event_ctx,
+ kdc_udp_socket->dgram);
+ NT_STATUS_HAVE_NO_MEMORY(udpsubreq);
+ tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket);
+
return NT_STATUS_OK;
}
@@ -522,7 +448,7 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
}
num_interfaces = iface_count(ifaces);
-
+
for (i=0; i<num_interfaces; i++) {
const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
uint16_t kdc_port = lp_krb5_port(lp_ctx);
@@ -549,7 +475,7 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
}
-static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
+static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
struct kdc_check_generic_kerberos *r)
{
struct PAC_Validate pac_validate;
@@ -567,14 +493,14 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
/* There is no reply to this request */
r->out.generic_reply = data_blob(NULL, 0);
- ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg,
- lp_iconv_convenience(kdc->task->lp_ctx),
+ ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg,
+ lp_iconv_convenience(kdc->task->lp_ctx),
&pac_validate,
(ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
if (pac_validate.MessageType != 3) {
/* We don't implement any other message types - such as certificate validation - yet */
return NT_STATUS_INVALID_PARAMETER;
@@ -585,10 +511,10 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
|| pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
return NT_STATUS_INVALID_PARAMETER;
}
-
- srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
+
+ srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
pac_validate.ChecksumLength);
-
+
if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) {
etype = ETYPE_ARCFOUR_HMAC_MD5;
} else {
@@ -599,16 +525,16 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
}
}
- ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
+ ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
lp_realm(kdc->task->lp_ctx),
- "krbtgt", lp_realm(kdc->task->lp_ctx),
+ "krbtgt", lp_realm(kdc->task->lp_ctx),
NULL);
if (ret != 0) {
return NT_STATUS_NO_MEMORY;
}
- ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context,
+ ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context,
kdc->config->db[0],
principal,
HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
@@ -617,10 +543,10 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
if (ret != 0) {
hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
-
+
return NT_STATUS_LOGON_FAILURE;
}
-
+
ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key);
if (ret != 0) {
@@ -630,11 +556,11 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
}
keyblock = key->key;
-
+
kdc_sig.type = pac_validate.SignatureType;
kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
pac_validate.SignatureLength);
- ret = check_pac_checksum(msg, srv_sig, &kdc_sig,
+ ret = check_pac_checksum(msg, srv_sig, &kdc_sig,
kdc->smb_krb5_context->krb5_context, &keyblock);
hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
@@ -643,7 +569,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
if (ret != 0) {
return NT_STATUS_LOGON_FAILURE;
}
-
+
return NT_STATUS_OK;
}
@@ -691,21 +617,21 @@ static void kdc_task_init(struct task_server *task)
ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
if (ret) {
- DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
+ DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
error_message(ret)));
task_server_terminate(task, "kdc: krb5_init_context failed", true);
- return;
+ return;
}
krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
- ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
+ ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
&kdc->config);
if(ret) {
task_server_terminate(task, "kdc: failed to get KDC configuration", true);
return;
}
-
+
kdc->config->logf = kdc->smb_krb5_context->logf;
kdc->config->db = talloc(kdc, struct HDB *);
if (!kdc->config->db) {
@@ -713,13 +639,13 @@ static void kdc_task_init(struct task_server *task)
return;
}
kdc->config->num_db = 1;
-
- status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx,
- kdc->smb_krb5_context->krb5_context,
+
+ status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx,
+ kdc->smb_krb5_context->krb5_context,
&kdc->config->db[0]);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
- return;
+ return;
}
/* Register hdb-samba4 hooks for use as a keytab */
@@ -727,13 +653,13 @@ static void kdc_task_init(struct task_server *task)
kdc->hdb_samba4_context = talloc(kdc, struct hdb_samba4_context);
if (!kdc->hdb_samba4_context) {
task_server_terminate(task, "kdc: out of memory", true);
- return;
+ return;
}
kdc->hdb_samba4_context->ev_ctx = task->event_ctx;
kdc->hdb_samba4_context->lp_ctx = task->lp_ctx;
- ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
+ ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
PLUGIN_TYPE_DATA, "hdb",
&hdb_samba4);
if(ret) {
@@ -748,7 +674,7 @@ static void kdc_task_init(struct task_server *task)
}
/* Registar WinDC hooks */
- ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
+ ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
PLUGIN_TYPE_DATA, "windc",
&windc_plugin_table);
if(ret) {
@@ -765,7 +691,7 @@ static void kdc_task_init(struct task_server *task)
return;
}
- status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
+ status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
kdc_check_generic_kerberos, kdc);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(task, "nbtd failed to setup monitoring", true);
diff --git a/source4/kdc/kdc.h b/source4/kdc/kdc.h
index 4a715fd498..b9cf621537 100644
--- a/source4/kdc/kdc.h
+++ b/source4/kdc/kdc.h
@@ -1,21 +1,21 @@
-/*
+/*
Unix SMB/CIFS implementation.
KDC structures
Copyright (C) Andrew Tridgell 2005
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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/>.
*/
@@ -33,8 +33,8 @@ struct tsocket_address;
bool kpasswdd_process(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *input,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *input,
DATA_BLOB *reply,
struct tsocket_address *peer_addr,
struct tsocket_address *my_addr,
diff --git a/source4/kdc/kpasswdd.c b/source4/kdc/kpasswdd.c
index 9b3336a7a1..8406887dad 100644
--- a/source4/kdc/kpasswdd.c
+++ b/source4/kdc/kpasswdd.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
kpasswd Server implementation
@@ -10,12 +10,12 @@
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/>.
*/
@@ -45,15 +45,15 @@
#endif
/* Return true if there is a valid error packet formed in the error_blob */
-static bool kpasswdd_make_error_reply(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- uint16_t result_code,
- const char *error_string,
- DATA_BLOB *error_blob)
+static bool kpasswdd_make_error_reply(struct kdc_server *kdc,
+ TALLOC_CTX *mem_ctx,
+ uint16_t result_code,
+ const char *error_string,
+ DATA_BLOB *error_blob)
{
char *error_string_utf8;
size_t len;
-
+
DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string));
if (!push_utf8_talloc(mem_ctx, &error_string_utf8, error_string, &len)) {
@@ -70,17 +70,17 @@ static bool kpasswdd_make_error_reply(struct kdc_server *kdc,
}
/* Return true if there is a valid error packet formed in the error_blob */
-static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- uint16_t result_code,
- const char *error_string,
- DATA_BLOB *error_blob)
+static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
+ TALLOC_CTX *mem_ctx,
+ uint16_t result_code,
+ const char *error_string,
+ DATA_BLOB *error_blob)
{
bool ret;
int kret;
DATA_BLOB error_bytes;
krb5_data k5_error_bytes, k5_error_blob;
- ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string,
+ ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string,
&error_bytes);
if (!ret) {
return false;
@@ -88,7 +88,7 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
k5_error_bytes.data = error_bytes.data;
k5_error_bytes.length = error_bytes.length;
kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context,
- result_code, NULL, &k5_error_bytes,
+ result_code, NULL, &k5_error_bytes,
NULL, NULL, NULL, NULL, &k5_error_blob);
if (kret) {
return false;
@@ -101,21 +101,21 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
return true;
}
-static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- NTSTATUS status,
+static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
+ TALLOC_CTX *mem_ctx,
+ NTSTATUS status,
enum samPwdChangeReason reject_reason,
struct samr_DomInfo1 *dominfo,
- DATA_BLOB *error_blob)
+ DATA_BLOB *error_blob)
{
if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_ACCESSDENIED,
"No such user when changing password",
error_blob);
}
if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_ACCESSDENIED,
"Not permitted to change password",
error_blob);
@@ -138,31 +138,31 @@ static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
dominfo->min_password_length, dominfo->password_history_length);
break;
}
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_SOFTERROR,
reject_string,
error_blob);
}
if (!NT_STATUS_IS_OK(status)) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)),
error_blob);
-
+
}
return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS,
"Password changed",
error_blob);
}
-/*
+/*
A user password change
-
+
Return true if there is a valid error packet (or sucess) formed in
the error_blob
*/
static bool kpasswdd_change_password(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
struct auth_session_info *session_info,
const DATA_BLOB *password,
DATA_BLOB *reply)
@@ -174,45 +174,45 @@ static bool kpasswdd_change_password(struct kdc_server *kdc,
samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx));
if (!samdb) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
"Failed to open samdb",
reply);
}
-
- DEBUG(3, ("Changing password of %s\\%s (%s)\n",
+
+ DEBUG(3, ("Changing password of %s\\%s (%s)\n",
session_info->server_info->domain_name,
session_info->server_info->account_name,
dom_sid_string(mem_ctx, session_info->security_token->user_sid)));
/* User password change */
- status = samdb_set_password_sid(samdb, mem_ctx,
+ status = samdb_set_password_sid(samdb, mem_ctx,
session_info->security_token->user_sid,
- password, NULL, NULL,
+ password, NULL, NULL,
true, /* this is a user password change */
&reject_reason,
&dominfo);
- return kpasswd_make_pwchange_reply(kdc, mem_ctx,
- status,
+ return kpasswd_make_pwchange_reply(kdc, mem_ctx,
+ status,
reject_reason,
- dominfo,
+ dominfo,
reply);
}
static bool kpasswd_process_request(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
struct gensec_security *gensec_security,
uint16_t version,
- DATA_BLOB *input,
+ DATA_BLOB *input,
DATA_BLOB *reply)
{
struct auth_session_info *session_info;
size_t pw_len;
- if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
+ if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
&session_info))) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
"gensec_session_info failed!",
reply);
@@ -222,16 +222,16 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
case KRB5_KPASSWD_VERS_CHANGEPW:
{
DATA_BLOB password;
- if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
- CH_UTF8, CH_UTF16,
- (const char *)input->data,
+ if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
+ CH_UTF8, CH_UTF16,
+ (const char *)input->data,
input->length,
(void **)&password.data, &pw_len, false)) {
return false;
}
password.length = pw_len;
-
- return kpasswdd_change_password(kdc, mem_ctx, session_info,
+
+ return kpasswdd_change_password(kdc, mem_ctx, session_info,
&password, reply);
break;
}
@@ -262,26 +262,26 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
ret = decode_ChangePasswdDataMS(input->data, input->length,
&chpw, &len);
if (ret) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_MALFORMED,
"failed to decode password change structure",
reply);
}
-
- if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
- CH_UTF8, CH_UTF16,
- (const char *)chpw.newpasswd.data,
+
+ if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
+ CH_UTF8, CH_UTF16,
+ (const char *)chpw.newpasswd.data,
chpw.newpasswd.length,
(void **)&password.data, &pw_len, false)) {
free_ChangePasswdDataMS(&chpw);
return false;
}
-
+
password.length = pw_len;
-
- if ((chpw.targname && !chpw.targrealm)
+
+ if ((chpw.targname && !chpw.targrealm)
|| (!chpw.targname && chpw.targrealm)) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_MALFORMED,
"Realm and principal must be both present, or neither present",
reply);
@@ -289,14 +289,14 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
if (chpw.targname && chpw.targrealm) {
#ifdef SAMBA4_INTERNAL_HEIMDAL
if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context,
- &principal, *chpw.targname,
+ &principal, *chpw.targname,
*chpw.targrealm) != 0) {
free_ChangePasswdDataMS(&chpw);
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_MALFORMED,
"failed to extract principal to set",
reply);
-
+
}
#else /* SAMBA4_INTERNAL_HEIMDAL */
return kpasswdd_make_error_reply(kdc, mem_ctx,
@@ -306,54 +306,54 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
#endif /* SAMBA4_INTERNAL_HEIMDAL */
} else {
free_ChangePasswdDataMS(&chpw);
- return kpasswdd_change_password(kdc, mem_ctx, session_info,
+ return kpasswdd_change_password(kdc, mem_ctx, session_info,
&password, reply);
}
free_ChangePasswdDataMS(&chpw);
if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) {
krb5_free_principal(context, principal);
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_MALFORMED,
"krb5_unparse_name failed!",
reply);
}
-
+
krb5_free_principal(context, principal);
-
+
samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info);
if (!samdb) {
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
"Unable to open database!",
reply);
}
- DEBUG(3, ("%s\\%s (%s) is changing password of %s\n",
+ DEBUG(3, ("%s\\%s (%s) is changing password of %s\n",
session_info->server_info->domain_name,
session_info->server_info->account_name,
- dom_sid_string(mem_ctx, session_info->security_token->user_sid),
+ dom_sid_string(mem_ctx, session_info->security_token->user_sid),
set_password_on_princ));
ret = ldb_transaction_start(samdb);
if (ret) {
status = NT_STATUS_TRANSACTION_ABORTED;
- return kpasswd_make_pwchange_reply(kdc, mem_ctx,
+ return kpasswd_make_pwchange_reply(kdc, mem_ctx,
status,
SAM_PWD_CHANGE_NO_ERROR,
- NULL,
+ NULL,
reply);
}
- status = crack_user_principal_name(samdb, mem_ctx,
- set_password_on_princ,
+ status = crack_user_principal_name(samdb, mem_ctx,
+ set_password_on_princ,
&set_password_on_dn, NULL);
free(set_password_on_princ);
if (!NT_STATUS_IS_OK(status)) {
ldb_transaction_cancel(samdb);
- return kpasswd_make_pwchange_reply(kdc, mem_ctx,
+ return kpasswd_make_pwchange_reply(kdc, mem_ctx,
status,
SAM_PWD_CHANGE_NO_ERROR,
- NULL,
+ NULL,
reply);
}
@@ -372,7 +372,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
/* Admin password set */
status = samdb_set_password(samdb, mem_ctx,
set_password_on_dn, NULL,
- msg, &password, NULL, NULL,
+ msg, &password, NULL, NULL,
false, /* this is not a user password change */
&reject_reason, &dominfo);
}
@@ -398,17 +398,17 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
} else {
ldb_transaction_cancel(samdb);
}
- return kpasswd_make_pwchange_reply(kdc, mem_ctx,
+ return kpasswd_make_pwchange_reply(kdc, mem_ctx,
status,
- reject_reason,
- dominfo,
+ reject_reason,
+ dominfo,
reply);
}
default:
- return kpasswdd_make_error_reply(kdc, mem_ctx,
+ return kpasswdd_make_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_BAD_VERSION,
- talloc_asprintf(mem_ctx,
- "Protocol version %u not supported",
+ talloc_asprintf(mem_ctx,
+ "Protocol version %u not supported",
version),
reply);
}
@@ -416,8 +416,8 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
}
bool kpasswdd_process(struct kdc_server *kdc,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *input,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *input,
DATA_BLOB *reply,
struct tsocket_address *peer_addr,
struct tsocket_address *my_addr,
@@ -466,11 +466,11 @@ bool kpasswdd_process(struct kdc_server *kdc,
talloc_free(tmp_ctx);
return false;
}
-
+
krb_priv_len = len - ap_req_len;
ap_req = data_blob_const(&input->data[header_len], ap_req_len);
krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len);
-
+
server_credentials = cli_credentials_init(tmp_ctx);
if (!server_credentials) {
DEBUG(1, ("Failed to init server credentials\n"));
@@ -478,7 +478,7 @@ bool kpasswdd_process(struct kdc_server *kdc,
}
/* We want the credentials subsystem to use the krb5 context
- * we already have, rather than a new context */
+ * we already have, rather than a new context */
cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context);
cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx);
@@ -487,10 +487,10 @@ bool kpasswdd_process(struct kdc_server *kdc,
cli_credentials_set_username(server_credentials, "kadmin/changepw", CRED_SPECIFIED);
ret = cli_credentials_set_keytab_name(server_credentials, kdc->task->event_ctx, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED);
if (ret != 0) {
- ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
+ ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
- talloc_asprintf(mem_ctx,
- "Failed to obtain server credentials for kadmin/changepw: %s\n",
+ talloc_asprintf(mem_ctx,
+ "Failed to obtain server credentials for kadmin/changepw: %s\n",
nt_errstr(nt_status)),
&krb_priv_rep);
ap_rep.length = 0;
@@ -500,16 +500,16 @@ bool kpasswdd_process(struct kdc_server *kdc,
talloc_free(tmp_ctx);
return ret;
}
-
+
/* We don't strictly need to call this wrapper, and could call
* gensec_server_start directly, as we have no need for NTLM
* and we have a PAC, but this ensures that the wrapper can be
* safely extended for other helpful things in future */
- nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx,
+ nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx,
kdc->task->msg_ctx,
kdc->task->lp_ctx,
server_credentials,
- "kpasswd",
+ "kpasswd",
&gensec_security);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(tmp_ctx);
@@ -549,11 +549,11 @@ bool kpasswdd_process(struct kdc_server *kdc,
/* Accept the AP-REQ and generate teh AP-REP we need for the reply */
nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep);
if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-
- ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
+
+ ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
- talloc_asprintf(mem_ctx,
- "gensec_update failed: %s",
+ talloc_asprintf(mem_ctx,
+ "gensec_update failed: %s",
nt_errstr(nt_status)),
&krb_priv_rep);
ap_rep.length = 0;
@@ -567,10 +567,10 @@ bool kpasswdd_process(struct kdc_server *kdc,
/* Extract the data from the KRB-PRIV half of the message */
nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req);
if (!NT_STATUS_IS_OK(nt_status)) {
- ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
+ ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
- talloc_asprintf(mem_ctx,
- "gensec_unwrap failed: %s",
+ talloc_asprintf(mem_ctx,
+ "gensec_unwrap failed: %s",
nt_errstr(nt_status)),
&krb_priv_rep);
ap_rep.length = 0;
@@ -582,10 +582,10 @@ bool kpasswdd_process(struct kdc_server *kdc,
}
/* Figure out something to do with it (probably changing a password...) */
- ret = kpasswd_process_request(kdc, tmp_ctx,
- gensec_security,
- version,
- &kpasswd_req, &kpasswd_rep);
+ ret = kpasswd_process_request(kdc, tmp_ctx,
+ gensec_security,
+ version,
+ &kpasswd_req, &kpasswd_rep);
if (!ret) {
/* Argh! */
return false;
@@ -593,13 +593,13 @@ bool kpasswdd_process(struct kdc_server *kdc,
/* And wrap up the reply: This ensures that the error message
* or success can be verified by the client */
- nt_status = gensec_wrap(gensec_security, tmp_ctx,
+ nt_status = gensec_wrap(gensec_security, tmp_ctx,
&kpasswd_rep, &krb_priv_rep);
if (!NT_STATUS_IS_OK(nt_status)) {
- ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
+ ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
KRB5_KPASSWD_HARDERROR,
- talloc_asprintf(mem_ctx,
- "gensec_wrap failed: %s",
+ talloc_asprintf(mem_ctx,
+ "gensec_wrap failed: %s",
nt_errstr(nt_status)),
&krb_priv_rep);
ap_rep.length = 0;
@@ -609,7 +609,7 @@ bool kpasswdd_process(struct kdc_server *kdc,
talloc_free(tmp_ctx);
return ret;
}
-
+
reply:
*reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len);
if (!reply->data) {
@@ -619,11 +619,11 @@ reply:
RSSVAL(reply->data, 0, reply->length);
RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */
RSSVAL(reply->data, 4, ap_rep.length);
- memcpy(reply->data + header_len,
- ap_rep.data,
+ memcpy(reply->data + header_len,
+ ap_rep.data,
ap_rep.length);
- memcpy(reply->data + header_len + ap_rep.length,
- krb_priv_rep.data,
+ memcpy(reply->data + header_len + ap_rep.length,
+ krb_priv_rep.data,
krb_priv_rep.length);
talloc_free(tmp_ctx);
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index 3d542d9a94..d921899c61 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -1,21 +1,21 @@
-/*
+/*
Unix SMB/CIFS implementation.
PAC Glue between Samba and the KDC
-
+
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
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/>.
*/
@@ -34,22 +34,22 @@
struct krb5_dh_moduli;
struct _krb5_krb_auth_data;
-static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr)
+static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr)
{
*ptr = NULL;
return 0;
}
-static void samba_kdc_plugin_fini(void *ptr)
+static void samba_kdc_plugin_fini(void *ptr)
{
return;
}
static krb5_error_code make_pac(krb5_context context,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
struct smb_iconv_convenience *iconv_convenience,
struct auth_serversupplied_info *server_info,
- krb5_pac *pac)
+ krb5_pac *pac)
{
union PAC_INFO info;
struct netr_SamInfo3 *info3;
@@ -105,7 +105,7 @@ static krb5_error_code make_pac(krb5_context context,
/* Given the right private pointer from hdb_samba4, get a PAC from the attached ldb messages */
static krb5_error_code samba_kdc_get_pac(void *priv,
- krb5_context context,
+ krb5_context context,
struct hdb_entry_ex *client,
krb5_pac *pac)
{
@@ -151,7 +151,7 @@ static krb5_error_code samba_kdc_get_pac(void *priv,
static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context,
const krb5_principal client_principal,
- struct hdb_entry_ex *client,
+ struct hdb_entry_ex *client,
struct hdb_entry_ex *server, krb5_pac *pac)
{
krb5_error_code ret;
@@ -163,7 +163,7 @@ static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context,
struct auth_serversupplied_info *server_info_out;
TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context");
-
+
if (!mem_ctx) {
return ENOMEM;
}
@@ -230,8 +230,8 @@ static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data,
* the account_ok routine in auth/auth_sam.c for consistancy */
-static krb5_error_code samba_kdc_check_client_access(void *priv,
- krb5_context context,
+static krb5_error_code samba_kdc_check_client_access(void *priv,
+ krb5_context context,
krb5_kdc_configuration *config,
hdb_entry_ex *client_ex, const char *client_name,
hdb_entry_ex *server_ex, const char *server_name,
@@ -253,7 +253,7 @@ static krb5_error_code samba_kdc_check_client_access(void *priv,
if (!tmp_ctx) {
return ENOMEM;
}
-
+
if (addresses) {
for (i=0; i < addresses->len; i++) {
if (addresses->val->addr_type == KRB5_ADDRESS_NETBIOS) {
@@ -276,7 +276,7 @@ static krb5_error_code samba_kdc_check_client_access(void *priv,
password_change = (server_ex && server_ex->entry.flags.change_pw);
/* we allow all kinds of trusts here */
- nt_status = authsam_account_ok(tmp_ctx,
+ nt_status = authsam_account_ok(tmp_ctx,
p->samdb,
MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
p->realm_dn,
diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h
index 1c14f7fdb6..f838ec353a 100644
--- a/source4/kdc/pac-glue.h
+++ b/source4/kdc/pac-glue.h
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
KDC Server startup
@@ -9,12 +9,12 @@
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/>.
*/
diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c
index 5f709e6320..4611eba3f1 100644
--- a/source4/lib/ldb-samba/ldif_handlers.c
+++ b/source4/lib/ldb-samba/ldif_handlers.c
@@ -678,20 +678,43 @@ static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
v1, v2);
}
-/* Canonicalisation of two 32-bit integers */
-static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
+/* length limited conversion of a ldb_val to a int32_t */
+static int val_to_int32(const struct ldb_val *in, int32_t *v)
{
char *end;
+ char buf[64];
+
+ /* make sure we don't read past the end of the data */
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (char *)in->data, in->length);
+ buf[in->length] = 0;
+
/* We've to use "strtoll" here to have the intended overflows.
* Otherwise we may get "LONG_MAX" and the conversion is wrong. */
- int32_t i = (int32_t) strtoll((char *)in->data, &end, 0);
+ *v = (int32_t) strtoll(buf, &end, 0);
if (*end != 0) {
- return -1;
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ return LDB_SUCCESS;
+}
+
+/* Canonicalisation of two 32-bit integers */
+static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ int32_t i;
+ int ret;
+
+ ret = val_to_int32(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
if (out->data == NULL) {
- return -1;
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
}
out->length = strlen((char *)out->data);
return 0;
@@ -699,12 +722,13 @@ static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
/* Comparison of two 32-bit integers */
static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
+ const struct ldb_val *v1, const struct ldb_val *v2)
{
- /* We've to use "strtoll" here to have the intended overflows.
- * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
- return (int32_t) strtoll((char *)v1->data, NULL, 0)
- - (int32_t) strtoll((char *)v2->data, NULL, 0);
+ int32_t i1=0, i2=0;
+ val_to_int32(v1, &i1);
+ val_to_int32(v2, &i2);
+ if (i1 == i2) return 0;
+ return i1 > i2? 1 : -1;
}
/*
@@ -846,7 +870,7 @@ static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
.write_clear_fn = ldif_write_objectGUID,
.write_hex_fn = extended_dn_write_hex
},{
- .name = "DELETED",
+ .name = "RMD_FLAGS",
.read_fn = ldb_handler_copy,
.write_clear_fn = ldb_handler_copy,
.write_hex_fn = ldb_handler_copy
@@ -861,7 +885,12 @@ static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
.write_clear_fn = ldb_handler_copy,
.write_hex_fn = ldb_handler_copy
},{
- .name = "RMD_USN",
+ .name = "RMD_LOCAL_USN",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_ORIGINATING_USN",
.read_fn = ldb_handler_copy,
.write_clear_fn = ldb_handler_copy,
.write_hex_fn = ldb_handler_copy
diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c
index 1c08741f7d..464707530e 100644
--- a/source4/lib/ldb/common/attrib_handlers.c
+++ b/source4/lib/ldb/common/attrib_handlers.c
@@ -100,6 +100,27 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
return 0;
}
+/* length limited conversion of a ldb_val to a int32_t */
+static int val_to_int64(const struct ldb_val *in, int64_t *v)
+{
+ char *end;
+ char buf[64];
+
+ /* make sure we don't read past the end of the data */
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (char *)in->data, in->length);
+ buf[in->length] = 0;
+
+ /* We've to use "strtoll" here to have the intended overflows.
+ * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
+ *v = (int64_t) strtoll(buf, &end, 0);
+ if (*end != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ return LDB_SUCCESS;
+}
/*
@@ -109,14 +130,17 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
- char *end;
- long long i = strtoll((char *)in->data, &end, 0);
- if (*end != 0) {
- return -1;
+ int64_t i;
+ int ret;
+
+ ret = val_to_int64(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
if (out->data == NULL) {
- return -1;
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
}
out->length = strlen((char *)out->data);
return 0;
@@ -128,7 +152,11 @@ static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
- return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
+ int64_t i1=0, i2=0;
+ val_to_int64(v1, &i1);
+ val_to_int64(v2, &i2);
+ if (i1 == i2) return 0;
+ return i1 > i2? 1 : -1;
}
/*
@@ -338,10 +366,11 @@ static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
- time_t t1, t2;
- t1 = ldb_string_to_time((char *)v1->data);
- t2 = ldb_string_to_time((char *)v2->data);
- return (int)t2 - (int)t1;
+ time_t t1=0, t2=0;
+ ldb_val_to_time(v1, &t1);
+ ldb_val_to_time(v2, &t2);
+ if (t1 == t2) return 0;
+ return t1 > t2? 1 : -1;
}
/*
@@ -350,10 +379,16 @@ static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
- time_t t = ldb_string_to_time((char *)in->data);
+ time_t t;
+ int ret;
+ ret = ldb_val_to_time(in, &t);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
if (out->data == NULL) {
- return -1;
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
}
out->length = strlen((char *)out->data);
return 0;
diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c
index e79f072d50..3b8934702a 100644
--- a/source4/lib/ldb/common/ldb_modules.c
+++ b/source4/lib/ldb/common/ldb_modules.c
@@ -527,6 +527,11 @@ struct ldb_context *ldb_module_get_ctx(struct ldb_module *module)
return module->ldb;
}
+const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module)
+{
+ return module->ops;
+}
+
void *ldb_module_get_private(struct ldb_module *module)
{
return module->private_data;
@@ -601,7 +606,7 @@ int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
* all our modules, and leaves us one less sharp
* corner for module developers to cut themselves on
*/
- ldb_module_done(request, NULL, NULL, ret);
+ ret = ldb_module_done(request, NULL, NULL, ret);
}
return ret;
}
@@ -824,8 +829,7 @@ int ldb_module_done(struct ldb_request *req,
ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
}
- req->callback(req, ares);
- return error;
+ return req->callback(req, ares);
}
/* to be used *only* in modules init functions.
diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c
index fbf49fbb23..9b33d7e351 100644
--- a/source4/lib/ldb/common/ldb_msg.c
+++ b/source4/lib/ldb/common/ldb_msg.c
@@ -832,6 +832,33 @@ time_t ldb_string_to_time(const char *s)
}
/*
+ convert a LDAP GeneralizedTime string in ldb_val format to a
+ time_t.
+*/
+int ldb_val_to_time(const struct ldb_val *v, time_t *t)
+{
+ struct tm tm;
+
+ if (v == NULL || !v->data || v->length < 14) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ memset(&tm, 0, sizeof(tm));
+
+ if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ *t = timegm(&tm);
+
+ return LDB_SUCCESS;
+}
+
+/*
return a LDAP formatted UTCTime string
*/
char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk
index 4a1f814baa..7d110fc618 100644
--- a/source4/lib/ldb/config.mk
+++ b/source4/lib/ldb/config.mk
@@ -11,6 +11,19 @@ ldb_asq_OBJ_FILES = $(ldbsrcdir)/modules/asq.o
################################################
################################################
+# Start MODULE sample_module
+[MODULE::sample]
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT
+CFLAGS = -I$(ldbsrcdir)/include
+INIT_FUNCTION = LDB_MODULE(sample)
+SUBSYSTEM = LIBTESTLDB
+
+# End MODULE sample_module
+################################################
+sample_OBJ_FILES = $(ldbsrcdir)/tests/sample_module.o
+
+
+################################################
# Start MODULE ldb_server_sort
[MODULE::ldb_server_sort]
PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT
diff --git a/source4/lib/ldb/external/libtalloc.m4 b/source4/lib/ldb/external/libtalloc.m4
index 8c63fcc041..dfccaf4fb7 100644
--- a/source4/lib/ldb/external/libtalloc.m4
+++ b/source4/lib/ldb/external/libtalloc.m4
@@ -2,7 +2,7 @@ AC_SUBST(TALLOC_OBJ)
AC_SUBST(TALLOC_CFLAGS)
AC_SUBST(TALLOC_LIBS)
-PKG_CHECK_MODULES(TALLOC, talloc >= 2.0.0,
+PKG_CHECK_MODULES(TALLOC, talloc >= 2.0.1,
[ ],
[ AC_CHECK_HEADER(talloc.h,
[ AC_CHECK_LIB(talloc, talloc_init, [TALLOC_LIBS="-ltalloc"])])])
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index c8bfa24832..1958fd740b 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -1951,6 +1951,12 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t);
time_t ldb_string_to_time(const char *s);
/**
+ convert a LDAP GeneralizedTime string in ldb_val format to a
+ time_t.
+*/
+int ldb_val_to_time(const struct ldb_val *v, time_t *t);
+
+/**
Convert a time structure to a string
This function converts a time_t structure to an LDAP formatted
diff --git a/source4/lib/ldb/include/ldb_module.h b/source4/lib/ldb/include/ldb_module.h
index 0b0f863fec..2d14634ca8 100644
--- a/source4/lib/ldb/include/ldb_module.h
+++ b/source4/lib/ldb/include/ldb_module.h
@@ -140,6 +140,7 @@ const char * ldb_module_get_name(struct ldb_module *module);
struct ldb_context *ldb_module_get_ctx(struct ldb_module *module);
void *ldb_module_get_private(struct ldb_module *module);
void ldb_module_set_private(struct ldb_module *module, void *private_data);
+const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module);
int ldb_next_request(struct ldb_module *module, struct ldb_request *request);
int ldb_next_start_trans(struct ldb_module *module);
diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk
index e87db64574..0c9b115672 100644
--- a/source4/lib/ldb/ldb.mk
+++ b/source4/lib/ldb/ldb.mk
@@ -34,26 +34,26 @@ lib/libldb.a: $(OBJS)
sample.$(SHLIBEXT): tests/sample_module.o
$(MDLD) $(MDLD_FLAGS) -o $@ tests/sample_module.o
-bin/ldbadd: tools/ldbadd.o tools/cmdline.o
- $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbadd: tools/ldbadd.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o
- $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbdel: tools/ldbdel.o tools/cmdline.o
- $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbdel: tools/ldbdel.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o
- $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbedit: tools/ldbedit.o tools/cmdline.o
- $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbedit: tools/ldbedit.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbrename: tools/ldbrename.o tools/cmdline.o
- $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbrename: tools/ldbrename.o tools/cmdline.o tools/ldbutil.o
+ $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
-bin/ldbtest: tools/ldbtest.o tools/cmdline.o
- $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
+bin/ldbtest: tools/ldbtest.o tools/cmdline.o
+ $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC)
examples/ldbreader: examples/ldbreader.o
$(CC) -o examples/ldbreader examples/ldbreader.o $(LIB_FLAGS)
diff --git a/source4/lib/ldb/ldb_tdb/ldb_cache.c b/source4/lib/ldb/ldb_tdb/ldb_cache.c
index cd2249d4a2..aa19f75e9c 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_cache.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_cache.c
@@ -463,7 +463,7 @@ int ltdb_increase_sequence_number(struct ldb_module *module)
val_time.data = (uint8_t *)s;
val_time.length = strlen(s);
- ret = ltdb_modify_internal(module, msg);
+ ret = ltdb_modify_internal(module, msg, NULL);
talloc_free(msg);
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 227a202a6f..a146b96b20 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -592,9 +592,12 @@ static int msg_delete_element(struct ldb_module *module,
yuck - this is O(n^2). Luckily n is usually small so we probably
get away with it, but if we ever have really large attribute lists
then we'll need to look at this again
+
+ 'req' is optional, and is used to specify controls if supplied
*/
int ltdb_modify_internal(struct ldb_module *module,
- const struct ldb_message *msg)
+ const struct ldb_message *msg,
+ struct ldb_request *req)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
void *data = ldb_module_get_private(module);
@@ -731,7 +734,15 @@ int ltdb_modify_internal(struct ldb_module *module,
case LDB_FLAG_MOD_REPLACE:
if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
- if (el->num_values > 1) {
+ /* the RELAX control overrides this
+ check for replace. This is needed as
+ DRS replication can produce multiple
+ values here for a single valued
+ attribute when the values are deleted
+ links
+ */
+ if (el->num_values > 1 &&
+ (!req || !ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))) {
ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
el->name, ldb_dn_get_linearized(msg2->dn));
ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
@@ -852,7 +863,7 @@ static int ltdb_modify(struct ltdb_context *ctx)
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_modify_internal(module, req->op.mod.message);
+ ret = ltdb_modify_internal(module, req->op.mod.message, req);
return ret;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
index bb4cb3f8b5..70b99c340c 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -130,7 +130,7 @@ int ltdb_lock_read(struct ldb_module *module);
int ltdb_unlock_read(struct ldb_module *module);
struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
-int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg);
+int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req);
int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn);
int ltdb_err_map(enum TDB_ERROR tdb_code);
diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c
index 0ba69e1c48..a19768d41b 100644
--- a/source4/lib/ldb/pyldb.c
+++ b/source4/lib/ldb/pyldb.c
@@ -61,6 +61,8 @@ PyAPI_DATA(PyTypeObject) PyLdb;
PyAPI_DATA(PyTypeObject) PyLdbMessageElement;
PyAPI_DATA(PyTypeObject) PyLdbTree;
+static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx);
+
static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx,
struct ldb_message_element *el,
struct ldb_val *val)
@@ -1357,7 +1359,7 @@ static PySequenceMethods py_ldb_seq = {
.sq_contains = (objobjproc)py_ldb_contains,
};
-PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
+static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
{
PyLdbObject *ret;
diff --git a/source4/lib/ldb/pyldb.h b/source4/lib/ldb/pyldb.h
index a0954158bd..289159c5b3 100644
--- a/source4/lib/ldb/pyldb.h
+++ b/source4/lib/ldb/pyldb.h
@@ -35,7 +35,6 @@ typedef struct {
TALLOC_CTX *mem_ctx;
} PyLdbObject;
-PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx);
#define PyLdb_AsLdbContext(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx
#define PyLdb_Check(ob) PyObject_TypeCheck(ob, &PyLdb)
diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py
index 54b623a903..c90727d720 100755
--- a/source4/lib/ldb/tests/python/ldap.py
+++ b/source4/lib/ldb/tests/python/ldap.py
@@ -26,7 +26,7 @@ from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
from ldb import Message, MessageElement, Dn
from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
-from samba import Ldb, param, dom_sid_to_rid
+from samba import Ldb, param
from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT
from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT
from samba import UF_INTERDOMAIN_TRUST_ACCOUNT
@@ -456,7 +456,7 @@ class BasicTests(unittest.TestCase):
self.fail()
except LdbError, (num, _):
self.assertEquals(num, ERR_NAMING_VIOLATION)
-
+
self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
self.ldb.add({
@@ -642,17 +642,17 @@ objectClass: container
res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
scope=SCOPE_BASE, attrs=["objectSID"])
self.assertTrue(len(res1) == 1)
- group_rid_1 = dom_sid_to_rid(ldb.schema_format_value("objectSID",
- res1[0]["objectSID"][0]))
+ group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
+ res1[0]["objectSID"][0])).split()[1]
res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
scope=SCOPE_BASE, attrs=["objectSID"])
self.assertTrue(len(res1) == 1)
- group_rid_2 = dom_sid_to_rid(ldb.schema_format_value("objectSID",
- res1[0]["objectSID"][0]))
+ group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
+ res1[0]["objectSID"][0])).split()[1]
# Try to create a user with an invalid primary group
- try:
+ try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
"objectclass": ["user", "person"],
@@ -704,7 +704,8 @@ objectClass: container
# Make group 1 secondary
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
+ m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
+ FLAG_MOD_REPLACE, "member")
ldb.modify(m)
# Make group 1 primary
@@ -724,7 +725,8 @@ objectClass: container
# Try to add group 1 also as secondary - should be denied
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
+ m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
+ FLAG_MOD_ADD, "member")
try:
ldb.modify(m)
self.fail()
@@ -746,7 +748,8 @@ objectClass: container
# Make group 2 secondary
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
- m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
+ m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
+ FLAG_MOD_ADD, "member")
ldb.modify(m)
# Swap the groups
@@ -833,7 +836,7 @@ objectClass: container
self.assertTrue(len(res1) == 1)
self.assertFalse("primaryGroupToken" in res1[0])
- res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
scope=SCOPE_BASE)
self.assertTrue(len(res1) == 1)
self.assertFalse("primaryGroupToken" in res1[0])
@@ -843,7 +846,7 @@ objectClass: container
self.assertTrue(len(res1) == 1)
primary_group_token = int(res1[0]["primaryGroupToken"][0])
- rid = dom_sid_to_rid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0]))
+ rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
self.assertEquals(primary_group_token, rid)
m = Message()
@@ -1990,137 +1993,6 @@ class BaseDnTests(unittest.TestCase):
self.assertTrue(res[0]["configurationNamingContext"][0] in ncs)
self.assertTrue(res[0]["schemaNamingContext"][0] in ncs)
-class SchemaTests(unittest.TestCase):
- def delete_force(self, ldb, dn):
- try:
- ldb.delete(dn)
- except LdbError, (num, _):
- self.assertEquals(num, ERR_NO_SUCH_OBJECT)
-
- def find_schemadn(self, ldb):
- res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
- self.assertEquals(len(res), 1)
- return res[0]["schemaNamingContext"][0]
-
- def find_basedn(self, ldb):
- res = ldb.search(base="", expression="", scope=SCOPE_BASE,
- attrs=["defaultNamingContext"])
- self.assertEquals(len(res), 1)
- return res[0]["defaultNamingContext"][0]
-
- def setUp(self):
- self.ldb = ldb
- self.schema_dn = self.find_schemadn(ldb)
- self.base_dn = self.find_basedn(ldb)
-
- def test_generated_schema(self):
- """Testing we can read the generated schema via LDAP"""
- res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
- attrs=["objectClasses", "attributeTypes", "dITContentRules"])
- self.assertEquals(len(res), 1)
- self.assertTrue("dITContentRules" in res[0])
- self.assertTrue("objectClasses" in res[0])
- self.assertTrue("attributeTypes" in res[0])
-
- def test_generated_schema_is_operational(self):
- """Testing we don't get the generated schema via LDAP by default"""
- res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
- attrs=["*"])
- self.assertEquals(len(res), 1)
- self.assertFalse("dITContentRules" in res[0])
- self.assertFalse("objectClasses" in res[0])
- self.assertFalse("attributeTypes" in res[0])
-
-
- def test_schemaUpdateNow(self):
- """Testing schemaUpdateNow"""
- attr_name = "test-Attr" + time.strftime("%s", time.gmtime())
- attr_ldap_display_name = attr_name.replace("-", "")
-
- ldif = """
-dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
-objectClass: top
-objectClass: attributeSchema
-adminDescription: """ + attr_name + """
-adminDisplayName: """ + attr_name + """
-cn: """ + attr_name + """
-attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
-attributeSyntax: 2.5.5.12
-omSyntax: 64
-instanceType: 4
-isSingleValued: TRUE
-systemOnly: FALSE
-"""
- self.ldb.add_ldif(ldif)
-
- class_name = "test-Class" + time.strftime("%s", time.gmtime())
- class_ldap_display_name = class_name.replace("-", "")
-
- ldif = """
-dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
-objectClass: top
-objectClass: classSchema
-adminDescription: """ + class_name + """
-adminDisplayName: """ + class_name + """
-cn: """ + class_name + """
-governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
-instanceType: 4
-objectClassCategory: 1
-subClassOf: organizationalPerson
-systemFlags: 16
-rDNAttID: cn
-systemMustContain: cn
-systemMustContain: """ + attr_ldap_display_name + """
-systemOnly: FALSE
-"""
- self.ldb.add_ldif(ldif)
-
- ldif = """
-dn:
-changetype: modify
-add: schemaUpdateNow
-schemaUpdateNow: 1
-"""
- self.ldb.modify_ldif(ldif)
-
- object_name = "obj" + time.strftime("%s", time.gmtime())
-
- ldif = """
-dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
-objectClass: organizationalPerson
-objectClass: person
-objectClass: """ + class_ldap_display_name + """
-objectClass: top
-cn: """ + object_name + """
-instanceType: 4
-objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
-distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
-name: """ + object_name + """
-""" + attr_ldap_display_name + """: test
-"""
- self.ldb.add_ldif(ldif)
-
- # Search for created attribute
- res = []
- res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
- self.assertEquals(len(res), 1)
- self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
- self.assertTrue("schemaIDGUID" in res[0])
-
- # Search for created objectclass
- res = []
- res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
- self.assertEquals(len(res), 1)
- self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
- self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
- self.assertTrue("schemaIDGUID" in res[0])
-
- # Search for created object
- res = []
- res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["*"])
- self.assertEquals(len(res), 1)
- # Delete the object
- self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
if not "://" in host:
if os.path.isfile(host):
@@ -2141,6 +2013,4 @@ if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful():
rc = 1
if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful():
rc = 1
-if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful():
- rc = 1
sys.exit(rc)
diff --git a/source4/lib/ldb/tests/python/ldap_schema.py b/source4/lib/ldb/tests/python/ldap_schema.py
new file mode 100755
index 0000000000..0a31db82f7
--- /dev/null
+++ b/source4/lib/ldb/tests/python/ldap_schema.py
@@ -0,0 +1,500 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# This is a port of the original in testprogs/ejs/ldap.js
+
+import getopt
+import optparse
+import sys
+import time
+import random
+import base64
+import os
+
+sys.path.append("bin/python")
+sys.path.append("../lib/subunit/python")
+
+import samba.getopt as options
+
+from samba.auth import system_session
+from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
+from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
+from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
+from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
+from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INSUFFICIENT_ACCESS_RIGHTS
+from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
+from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
+from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
+from ldb import Message, MessageElement, Dn
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
+from samba import Ldb
+from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT
+from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT
+from samba import UF_INTERDOMAIN_TRUST_ACCOUNT
+from samba import UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE
+from samba import GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
+from samba import GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
+from samba import GTYPE_SECURITY_UNIVERSAL_GROUP
+from samba import GTYPE_DISTRIBUTION_GLOBAL_GROUP
+from samba import GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP
+from samba import GTYPE_DISTRIBUTION_UNIVERSAL_GROUP
+from samba import ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST
+from samba import ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP
+from samba import ATYPE_SECURITY_UNIVERSAL_GROUP
+from samba import ATYPE_DISTRIBUTION_GLOBAL_GROUP
+from samba import ATYPE_DISTRIBUTION_LOCAL_GROUP
+from samba import ATYPE_DISTRIBUTION_UNIVERSAL_GROUP
+from samba import DS_DC_FUNCTION_2003
+
+from subunit import SubunitTestRunner
+import unittest
+
+from samba.ndr import ndr_pack, ndr_unpack
+from samba.dcerpc import security
+
+parser = optparse.OptionParser("ldap [options] <host>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+opts, args = parser.parse_args()
+
+if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+host = args[0]
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+
+
+class SchemaTests(unittest.TestCase):
+ def delete_force(self, ldb, dn):
+ try:
+ ldb.delete(dn)
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_NO_SUCH_OBJECT)
+
+ def find_schemadn(self, ldb):
+ res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
+ self.assertEquals(len(res), 1)
+ return res[0]["schemaNamingContext"][0]
+
+ def find_basedn(self, ldb):
+ res = ldb.search(base="", expression="", scope=SCOPE_BASE,
+ attrs=["defaultNamingContext"])
+ self.assertEquals(len(res), 1)
+ return res[0]["defaultNamingContext"][0]
+
+ def setUp(self):
+ self.ldb = ldb
+ self.schema_dn = self.find_schemadn(ldb)
+ self.base_dn = self.find_basedn(ldb)
+
+ def test_generated_schema(self):
+ """Testing we can read the generated schema via LDAP"""
+ res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
+ attrs=["objectClasses", "attributeTypes", "dITContentRules"])
+ self.assertEquals(len(res), 1)
+ self.assertTrue("dITContentRules" in res[0])
+ self.assertTrue("objectClasses" in res[0])
+ self.assertTrue("attributeTypes" in res[0])
+
+ def test_generated_schema_is_operational(self):
+ """Testing we don't get the generated schema via LDAP by default"""
+ res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
+ attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertFalse("dITContentRules" in res[0])
+ self.assertFalse("objectClasses" in res[0])
+ self.assertFalse("attributeTypes" in res[0])
+
+ def test_schemaUpdateNow(self):
+ """Testing schemaUpdateNow"""
+ attr_name = "test-Attr" + time.strftime("%s", time.gmtime())
+ attr_ldap_display_name = attr_name.replace("-", "")
+
+ ldif = """
+dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """
+adminDisplayName: """ + attr_name + """
+cn: """ + attr_name + """
+attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+ self.ldb.add_ldif(ldif)
+
+ class_name = "test-Class" + time.strftime("%s", time.gmtime())
+ class_ldap_display_name = class_name.replace("-", "")
+
+ ldif = """
+dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
+objectClass: top
+objectClass: classSchema
+adminDescription: """ + class_name + """
+adminDisplayName: """ + class_name + """
+cn: """ + class_name + """
+governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
+instanceType: 4
+objectClassCategory: 1
+subClassOf: organizationalPerson
+systemFlags: 16
+rDNAttID: cn
+systemMustContain: cn
+systemMustContain: """ + attr_ldap_display_name + """
+systemOnly: FALSE
+"""
+ self.ldb.add_ldif(ldif)
+
+ ldif = """
+dn:
+changetype: modify
+add: schemaUpdateNow
+schemaUpdateNow: 1
+"""
+ self.ldb.modify_ldif(ldif)
+
+ object_name = "obj" + time.strftime("%s", time.gmtime())
+
+ ldif = """
+dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
+objectClass: organizationalPerson
+objectClass: person
+objectClass: """ + class_ldap_display_name + """
+objectClass: top
+cn: """ + object_name + """
+instanceType: 4
+objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
+distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
+name: """ + object_name + """
+""" + attr_ldap_display_name + """: test
+"""
+ self.ldb.add_ldif(ldif)
+
+ # Search for created attribute
+ res = []
+ res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
+ self.assertTrue("schemaIDGUID" in res[0])
+
+ # Search for created objectclass
+ res = []
+ res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
+ self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
+ self.assertTrue("schemaIDGUID" in res[0])
+
+ # Search for created object
+ res = []
+ res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ # Delete the object
+ self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
+
+
+class SchemaTests_msDS_IntId(unittest.TestCase):
+
+ def setUp(self):
+ self.ldb = ldb
+ res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.schema_dn = res[0]["schemaNamingContext"][0]
+ self.base_dn = res[0]["defaultNamingContext"][0]
+ self.forest_level = int(res[0]["forestFunctionality"][0])
+
+ def _ldap_schemaUpdateNow(self):
+ ldif = """
+dn:
+changetype: modify
+add: schemaUpdateNow
+schemaUpdateNow: 1
+"""
+ self.ldb.modify_ldif(ldif)
+
+ def _make_obj_names(self, prefix):
+ class_name = prefix + time.strftime("%s", time.gmtime())
+ class_ldap_name = class_name.replace("-", "")
+ class_dn = "CN=%s,%s" % (class_name, self.schema_dn)
+ return (class_name, class_ldap_name, class_dn)
+
+ def _is_schema_base_object(self, ldb_msg):
+ """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)"""
+ systemFlags = 0
+ if "systemFlags" in ldb_msg:
+ systemFlags = int(ldb_msg["systemFlags"][0])
+ return (systemFlags & 16) != 0
+
+ def _make_attr_ldif(self, attr_name, attr_dn):
+ ldif = """
+dn: """ + attr_dn + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """
+adminDisplayName: """ + attr_name + """
+cn: """ + attr_name + """
+attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+ return ldif
+
+ def test_msDS_IntId_on_attr(self):
+ """Testing msDs-IntId creation for Attributes.
+ See MS-ADTS - 3.1.1.Attributes
+
+ This test should verify that:
+ - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM
+ - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION
+ - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag
+ set fails with ERR_UNWILLING_TO_PERFORM
+ - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have
+ 'msDS-IntId' attribute added internally
+ """
+
+ # 1. Create attribute without systemFlags
+ # msDS-IntId should be created if forest functional
+ # level is >= DS_DC_FUNCTION_2003
+ # and missing otherwise
+ (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-")
+ ldif = self._make_attr_ldif(attr_name, attr_dn)
+
+ # try to add msDS-IntId during Attribute creation
+ ldif_fail = ldif + "msDS-IntId: -1993108831\n"
+ try:
+ self.ldb.add_ldif(ldif_fail)
+ self.fail("Adding attribute with preset msDS-IntId should fail")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ # add the new attribute and update schema
+ self.ldb.add_ldif(ldif)
+ self._ldap_schemaUpdateNow()
+
+ # Search for created attribute
+ res = []
+ res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
+ if self.forest_level >= DS_DC_FUNCTION_2003:
+ if self._is_schema_base_object(res[0]):
+ self.assertTrue("msDS-IntId" not in res[0])
+ else:
+ self.assertTrue("msDS-IntId" in res[0])
+ else:
+ self.assertTrue("msDS-IntId" not in res[0])
+
+ msg = Message()
+ msg.dn = Dn(self.ldb, attr_dn)
+ msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
+ try:
+ self.ldb.modify(msg)
+ self.fail("Modifying msDS-IntId should return error")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+
+ # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT
+ # msDS-IntId should be created if forest functional
+ # level is >= DS_DC_FUNCTION_2003
+ # and missing otherwise
+ (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-")
+ ldif = self._make_attr_ldif(attr_name, attr_dn)
+ ldif += "systemFlags: 16\n"
+
+ # try to add msDS-IntId during Attribute creation
+ ldif_fail = ldif + "msDS-IntId: -1993108831\n"
+ try:
+ self.ldb.add_ldif(ldif_fail)
+ self.fail("Adding attribute with preset msDS-IntId should fail")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ # add the new attribute and update schema
+ self.ldb.add_ldif(ldif)
+ self._ldap_schemaUpdateNow()
+
+ # Search for created attribute
+ res = []
+ res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
+ if self.forest_level >= DS_DC_FUNCTION_2003:
+ if self._is_schema_base_object(res[0]):
+ self.assertTrue("msDS-IntId" not in res[0])
+ else:
+ self.assertTrue("msDS-IntId" in res[0])
+ else:
+ self.assertTrue("msDS-IntId" not in res[0])
+
+ msg = Message()
+ msg.dn = Dn(self.ldb, attr_dn)
+ msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
+ try:
+ self.ldb.modify(msg)
+ self.fail("Modifying msDS-IntId should return error")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+
+
+ def _make_class_ldif(self, class_dn, class_name):
+ ldif = """
+dn: """ + class_dn + """
+objectClass: top
+objectClass: classSchema
+adminDescription: """ + class_name + """
+adminDisplayName: """ + class_name + """
+cn: """ + class_name + """
+governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
+instanceType: 4
+objectClassCategory: 1
+subClassOf: organizationalPerson
+rDNAttID: cn
+systemMustContain: cn
+systemOnly: FALSE
+"""
+ return ldif
+
+ def test_msDS_IntId_on_class(self):
+ """Testing msDs-IntId creation for Class
+ Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema"""
+
+ # 1. Create Class without systemFlags
+ # msDS-IntId should be created if forest functional
+ # level is >= DS_DC_FUNCTION_2003
+ # and missing otherwise
+ (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-")
+ ldif = self._make_class_ldif(class_dn, class_name)
+
+ # try to add msDS-IntId during Class creation
+ ldif_add = ldif + "msDS-IntId: -1993108831\n"
+ self.ldb.add_ldif(ldif_add)
+ self._ldap_schemaUpdateNow()
+
+ res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
+
+ # add a new Class and update schema
+ (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-")
+ ldif = self._make_class_ldif(class_dn, class_name)
+
+ self.ldb.add_ldif(ldif)
+ self._ldap_schemaUpdateNow()
+
+ # Search for created Class
+ res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertFalse("msDS-IntId" in res[0])
+
+ msg = Message()
+ msg.dn = Dn(self.ldb, class_dn)
+ msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
+ try:
+ self.ldb.modify(msg)
+ self.fail("Modifying msDS-IntId should return error")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+
+ # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT
+ # msDS-IntId should be created if forest functional
+ # level is >= DS_DC_FUNCTION_2003
+ # and missing otherwise
+ (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-")
+ ldif = self._make_class_ldif(class_dn, class_name)
+ ldif += "systemFlags: 16\n"
+
+ # try to add msDS-IntId during Class creation
+ ldif_add = ldif + "msDS-IntId: -1993108831\n"
+ self.ldb.add_ldif(ldif_add)
+
+ res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
+
+ # add the new Class and update schema
+ (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-")
+ ldif = self._make_class_ldif(class_dn, class_name)
+ ldif += "systemFlags: 16\n"
+
+ self.ldb.add_ldif(ldif)
+ self._ldap_schemaUpdateNow()
+
+ # Search for created Class
+ res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertFalse("msDS-IntId" in res[0])
+
+ msg = Message()
+ msg.dn = Dn(self.ldb, class_dn)
+ msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
+ try:
+ self.ldb.modify(msg)
+ self.fail("Modifying msDS-IntId should return error")
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+ res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"])
+ self.assertEquals(len(res), 1)
+ self.assertFalse("msDS-IntId" in res[0])
+
+
+ def test_verify_msDS_IntId(self):
+ """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set"""
+ count = 0
+ res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL,
+ expression="objectClass=attributeSchema",
+ attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"])
+ self.assertTrue(len(res) > 1)
+ for ldb_msg in res:
+ if self.forest_level >= DS_DC_FUNCTION_2003:
+ if self._is_schema_base_object(ldb_msg):
+ self.assertTrue("msDS-IntId" not in ldb_msg)
+ else:
+ # don't assert here as there are plenty of
+ # attributes under w2k8 that are not part of
+ # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set)
+ # has not msDS-IntId attribute set
+ #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn)
+ if "msDS-IntId" not in ldb_msg:
+ count = count + 1
+ print "%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"])
+ else:
+ self.assertTrue("msDS-IntId" not in ldb_msg)
+
+
+if not "://" in host:
+ if os.path.isfile(host):
+ host = "tdb://%s" % host
+ else:
+ host = "ldap://%s" % host
+
+ldb_options = []
+if host.startswith("ldap://"):
+ # user 'paged_search' module when connecting remotely
+ ldb_options = ["modules:paged_searches"]
+
+ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp, options=ldb_options)
+if not "tdb://" in host:
+ gc_ldb = Ldb("%s:3268" % host, credentials=creds,
+ session_info=system_session(), lp=lp)
+else:
+ gc_ldb = None
+
+runner = SubunitTestRunner()
+rc = 0
+if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful():
+ rc = 1
+if not runner.run(unittest.makeSuite(SchemaTests_msDS_IntId)).wasSuccessful():
+ rc = 1
+sys.exit(rc)
diff --git a/source4/lib/ldb/tests/sample_module.c b/source4/lib/ldb/tests/sample_module.c
index bbe4419b59..bb7906e7ba 100644
--- a/source4/lib/ldb/tests/sample_module.c
+++ b/source4/lib/ldb/tests/sample_module.c
@@ -25,12 +25,40 @@
int sample_add(struct ldb_module *mod, struct ldb_request *req)
{
+ struct ldb_control *control;
+ struct ldb_control *controls;
ldb_msg_add_fmt(req->op.add.message, "touchedBy", "sample");
- return ldb_next_request(mod, req);
+
+ /* check if there's a relax control */
+ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(mod, req);
+ } else {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+}
+
+int sample_modify(struct ldb_module *mod, struct ldb_request *req)
+{
+ struct ldb_control *control;
+ struct ldb_control *controls;
+
+ /* check if there's a relax control */
+ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(mod, req);
+ } else {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
}
+
const struct ldb_module_ops ldb_sample_module_ops = {
.name = "sample",
.add = sample_add,
+ .del = sample_modify,
+ .modify = sample_modify,
};
diff --git a/source4/lib/ldb/tests/test-controls.sh b/source4/lib/ldb/tests/test-controls.sh
new file mode 100755
index 0000000000..db139bbec7
--- /dev/null
+++ b/source4/lib/ldb/tests/test-controls.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+if [ -n "$TEST_DATA_PREFIX" ]; then
+ LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb"
+else
+ LDB_URL="tdbtest.ldb"
+fi
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+rm -f $LDB_URL*
+LDB_MODULES_PATH=`dirname $0`/../../../bin/modules/testldb
+echo $LDB_MODULES_PATH
+
+echo "LDB_URL: $LDB_URL"
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: sample
+EOF
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: dc=bar
+dc: bar
+someThing: someThingElse
+EOF
+
+$VALGRIND ldbsearch "(touchedBy=sample)" | grep "touchedBy: sample" || exit 1
+# This action are expected to fails because the sample module return an error when presented the relax control
+
+cat <<EOF | $VALGRIND ldbadd --controls "relax:0" && exit 1
+dn: dc=foobar
+dc: foobar
+someThing: someThingElse
+EOF
+
+cat <<EOF | $VALGRIND ldbmodify --controls "relax:0" && exit 1
+dn: dc=bar
+changetype: replace
+replace someThing
+someThing: someThingElseBetter
+EOF
+
+
+set
diff --git a/source4/lib/ldb/tests/test-tdb.sh b/source4/lib/ldb/tests/test-tdb.sh
index 1c35451962..9da1e57060 100755
--- a/source4/lib/ldb/tests/test-tdb.sh
+++ b/source4/lib/ldb/tests/test-tdb.sh
@@ -29,3 +29,5 @@ $VALGRIND ldbadd$EXEEXT $LDBDIR/tests/init.ldif || exit 1
. $LDBDIR/tests/test-extended.sh
. $LDBDIR/tests/test-tdb-features.sh
+
+. $LDBDIR/tests/test-controls.sh
diff --git a/source4/lib/ldb/tools/config.mk b/source4/lib/ldb/tools/config.mk
index 6b57929df0..f0d0e85e6f 100644
--- a/source4/lib/ldb/tools/config.mk
+++ b/source4/lib/ldb/tools/config.mk
@@ -1,4 +1,14 @@
################################################
+# Start SUBSYSTEM LIBLDB_UTIL
+[SUBSYSTEM::LIBLDB_UTIL]
+CFLAGS = -I$(ldbsrcdir) -I$(ldbsrcdir)/include
+PUBLIC_DEPENDENCIES = LIBLDB
+# End SUBSYSTEM LIBLDB_UTIL
+################################################
+
+LIBLDB_UTIL_OBJ_FILES = $(ldbsrcdir)/tools/ldbutil.o
+
+################################################
# Start SUBSYSTEM LIBLDB_CMDLINE
[SUBSYSTEM::LIBLDB_CMDLINE]
CFLAGS = -I$(ldbsrcdir) -I$(ldbsrcdir)/include
@@ -14,6 +24,7 @@ LIBLDB_CMDLINE_OBJ_FILES = $(ldbsrcdir)/tools/cmdline.o
[BINARY::ldbadd]
INSTALLDIR = BINDIR
PRIVATE_DEPENDENCIES = \
+ LIBLDB_UTIL \
LIBLDB_CMDLINE LIBCLI_RESOLVE
# End BINARY ldbadd
################################################
@@ -28,6 +39,7 @@ MANPAGES += $(ldbsrcdir)/man/ldbadd.1
[BINARY::ldbdel]
INSTALLDIR = BINDIR
PRIVATE_DEPENDENCIES = \
+ LIBLDB_UTIL \
LIBLDB_CMDLINE
# End BINARY ldbdel
################################################
@@ -41,6 +53,7 @@ MANPAGES += $(ldbsrcdir)/man/ldbdel.1
[BINARY::ldbmodify]
INSTALLDIR = BINDIR
PRIVATE_DEPENDENCIES = \
+ LIBLDB_UTIL \
LIBLDB_CMDLINE
# End BINARY ldbmodify
################################################
diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c
index a87c99aaee..e618ab52f7 100644
--- a/source4/lib/ldb/tools/ldbadd.c
+++ b/source4/lib/ldb/tools/ldbadd.c
@@ -33,6 +33,7 @@
#include "ldb.h"
#include "tools/cmdline.h"
+#include "ldbutil.h"
static int failures;
static struct ldb_cmdline *options;
@@ -53,6 +54,12 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count)
{
struct ldb_ldif *ldif;
int ret = LDB_SUCCESS;
+ struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
while ((ldif = ldb_ldif_read_file(ldb, f))) {
if (ldif->changetype != LDB_CHANGETYPE_ADD &&
@@ -63,10 +70,11 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count)
ldif->msg = ldb_msg_canonicalize(ldb, ldif->msg);
- ret = ldb_add(ldb, ldif->msg);
+ ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls);
if (ret != LDB_SUCCESS) {
- fprintf(stderr, "ERR: \"%s\" on DN %s\n",
- ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn));
+ fprintf(stderr, "ERR: %s : \"%s\" on DN %s\n",
+ ldb_strerror(ret), ldb_errstring(ldb),
+ ldb_dn_get_linearized(ldif->msg->dn));
failures++;
} else {
(*count)++;
diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c
index 5740f22503..6de15ee042 100644
--- a/source4/lib/ldb/tools/ldbdel.c
+++ b/source4/lib/ldb/tools/ldbdel.c
@@ -33,6 +33,7 @@
#include "ldb.h"
#include "tools/cmdline.h"
+#include "ldbutil.h"
static int dn_cmp(const void *p1, const void *p2)
{
@@ -42,7 +43,7 @@ static int dn_cmp(const void *p1, const void *p2)
return ldb_dn_compare(msg1->dn, msg2->dn);
}
-static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn)
+static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn,struct ldb_control **req_ctrls)
{
int ret, i, total=0;
const char *attrs[] = { NULL };
@@ -55,7 +56,7 @@ static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn)
qsort(res->msgs, res->count, sizeof(res->msgs[0]), dn_cmp);
for (i = 0; i < res->count; i++) {
- if (ldb_delete(ldb, res->msgs[i]->dn) == 0) {
+ if (ldb_delete_ctrl(ldb, res->msgs[i]->dn,req_ctrls) == 0) {
total++;
} else {
printf("Failed to delete '%s' - %s\n",
@@ -83,9 +84,10 @@ static void usage(void)
int main(int argc, const char **argv)
{
+ struct ldb_control **req_ctrls;
+ struct ldb_cmdline *options;
struct ldb_context *ldb;
int ret = 0, i;
- struct ldb_cmdline *options;
ldb = ldb_init(NULL, NULL);
@@ -96,6 +98,12 @@ int main(int argc, const char **argv)
exit(1);
}
+ req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
for (i=0;i<options->argc;i++) {
struct ldb_dn *dn;
@@ -105,17 +113,18 @@ int main(int argc, const char **argv)
exit(1);
}
if (options->recursive) {
- ret = ldb_delete_recursive(ldb, dn);
+ ret = ldb_delete_recursive(ldb, dn,req_ctrls);
} else {
- ret = ldb_delete(ldb, dn);
+ ret = ldb_delete_ctrl(ldb, dn,req_ctrls);
if (ret == 0) {
printf("Deleted 1 record\n");
}
}
if (ret != 0) {
- printf("delete of '%s' failed - %s\n",
- ldb_dn_get_linearized(dn),
- ldb_errstring(ldb));
+ printf("delete of '%s' failed - (%s) %s\n",
+ ldb_dn_get_linearized(dn),
+ ldb_strerror(ret),
+ ldb_errstring(ldb));
}
}
diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c
index 4936880d09..57988cbb30 100644
--- a/source4/lib/ldb/tools/ldbmodify.c
+++ b/source4/lib/ldb/tools/ldbmodify.c
@@ -33,6 +33,7 @@
#include "ldb.h"
#include "tools/cmdline.h"
+#include "ldbutil.h"
static int failures;
static struct ldb_cmdline *options;
@@ -52,22 +53,28 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count)
{
struct ldb_ldif *ldif;
int ret = LDB_SUCCESS;
-
+ struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
while ((ldif = ldb_ldif_read_file(ldb, f))) {
switch (ldif->changetype) {
case LDB_CHANGETYPE_NONE:
case LDB_CHANGETYPE_ADD:
- ret = ldb_add(ldb, ldif->msg);
+ ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls);
break;
case LDB_CHANGETYPE_DELETE:
- ret = ldb_delete(ldb, ldif->msg->dn);
+ ret = ldb_delete_ctrl(ldb, ldif->msg->dn,req_ctrls);
break;
case LDB_CHANGETYPE_MODIFY:
- ret = ldb_modify(ldb, ldif->msg);
+ ret = ldb_modify_ctrl(ldb, ldif->msg,req_ctrls);
break;
}
if (ret != LDB_SUCCESS) {
- fprintf(stderr, "ERR: \"%s\" on DN %s\n",
+ fprintf(stderr, "ERR: (%s) \"%s\" on DN %s\n",
+ ldb_strerror(ret),
ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn));
failures++;
} else {
diff --git a/source4/lib/ldb/tools/ldbutil.c b/source4/lib/ldb/tools/ldbutil.c
new file mode 100644
index 0000000000..5f7ea894df
--- /dev/null
+++ b/source4/lib/ldb/tools/ldbutil.c
@@ -0,0 +1,149 @@
+/*
+ ldb database library utility
+
+ Copyright (C) Matthieu Patou 2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Description: Common function used by ldb_add/ldb_modify/ldb_delete
+ *
+ * Author: Matthieu Patou
+ */
+
+#include "ldb.h"
+#include "ldb_module.h"
+
+/* autostarts a transacion if none active */
+static int ldb_do_autotransaction(struct ldb_context *ldb,
+ struct ldb_request *req)
+{
+ int ret;
+
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ return ldb_transaction_commit(ldb);
+ }
+ ldb_transaction_cancel(ldb);
+
+ if (ldb_errstring(ldb) == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret);
+ }
+
+ return ret;
+}
+/*
+ Same as ldb_add but accept control
+*/
+int ldb_add_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_add_req(&req, ldb, ldb,
+ message,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ same as ldb_delete but accept control
+*/
+int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_del_req(&req, ldb, ldb,
+ dn,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ same as ldb_modify, but accepts controls
+*/
+int ldb_modify_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_mod_req(&req, ldb, ldb,
+ message,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
diff --git a/source4/lib/ldb/tools/ldbutil.h b/source4/lib/ldb/tools/ldbutil.h
new file mode 100644
index 0000000000..7747dbec64
--- /dev/null
+++ b/source4/lib/ldb/tools/ldbutil.h
@@ -0,0 +1,41 @@
+/*
+ ldb database library utility header file
+
+ Copyright (C) Matthieu Patou 2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Description: Common function used by ldb_add/ldb_modify/ldb_delete
+ *
+ * Author: Matthieu Patou
+ */
+
+#include "ldb.h"
+
+int ldb_add_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls);
+int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn,
+ struct ldb_control **controls);
+int ldb_modify_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls);
diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c
index 134c2271fd..d5178467b1 100644
--- a/source4/lib/ldb_wrap.c
+++ b/source4/lib/ldb_wrap.c
@@ -34,7 +34,7 @@
#include "ldb_wrap.h"
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
-#include "dlinklist.h"
+#include "../lib/util/dlinklist.h"
#include "../tdb/include/tdb.h"
/*
diff --git a/source4/lib/registry/util.c b/source4/lib/registry/util.c
index f9ea2a1934..5d451df33a 100644
--- a/source4/lib/registry/util.c
+++ b/source4/lib/registry/util.c
@@ -89,6 +89,7 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx,
/* FIXME: We don't support this yet */
break;
default:
+ /* FIXME */
/* Other datatypes aren't supported -> return "NULL" */
break;
}
@@ -156,6 +157,7 @@ _PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx,
/* FIXME: We don't support this yet */
return false;
default:
+ /* FIXME */
/* Other datatypes aren't supported -> return no success */
return false;
}
diff --git a/source4/lib/socket/config.mk b/source4/lib/socket/config.mk
index ac515c8f6d..07491e115a 100644
--- a/source4/lib/socket/config.mk
+++ b/source4/lib/socket/config.mk
@@ -34,7 +34,7 @@ socket_unix_OBJ_FILES = $(libsocketsrcdir)/socket_unix.o
################################################
# Start SUBSYSTEM SOCKET
[SUBSYSTEM::samba_socket]
-PUBLIC_DEPENDENCIES = LIBTALLOC
+PUBLIC_DEPENDENCIES = LIBTALLOC LIBTSOCKET
PRIVATE_DEPENDENCIES = SOCKET_WRAPPER LIBCLI_COMPOSITE LIBCLI_RESOLVE
# End SUBSYSTEM SOCKET
################################################
diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c
index 8e2f1683f2..30db03fd97 100644
--- a/source4/lib/socket/socket.c
+++ b/source4/lib/socket/socket.c
@@ -24,6 +24,7 @@
#include "system/filesys.h"
#include "system/network.h"
#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
/*
auto-close sockets on free
@@ -344,6 +345,77 @@ _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock,
return sock->ops->fn_get_my_addr(sock, mem_ctx);
}
+_PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
+ const struct socket_address *a)
+{
+ struct tsocket_address *r;
+ int ret;
+
+ if (a->sockaddr) {
+ ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
+ a->sockaddr,
+ a->sockaddrlen,
+ &r);
+ } else {
+ ret = tsocket_address_inet_from_strings(mem_ctx,
+ a->family,
+ a->addr,
+ a->port,
+ &r);
+ }
+
+ if (ret != 0) {
+ return NULL;
+ }
+
+ return r;
+}
+
+_PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *a)
+{
+ ssize_t ret;
+ struct sockaddr_storage ss;
+ size_t sslen = sizeof(ss);
+
+ ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
+ if (ret < 0) {
+ return NULL;
+ }
+
+ return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
+}
+
+_PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ struct socket_address *a;
+ struct tsocket_address *r;
+
+ a = socket_get_peer_addr(sock, mem_ctx);
+ if (a == NULL) {
+ return NULL;
+ }
+
+ r = socket_address_to_tsocket_address(mem_ctx, a);
+ talloc_free(a);
+ return r;
+}
+
+_PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ struct socket_address *a;
+ struct tsocket_address *r;
+
+ a = socket_get_my_addr(sock, mem_ctx);
+ if (a == NULL) {
+ return NULL;
+ }
+
+ r = socket_address_to_tsocket_address(mem_ctx, a);
+ talloc_free(a);
+ return r;
+}
+
_PUBLIC_ int socket_get_fd(struct socket_context *sock)
{
if (!sock->ops->fn_get_fd) {
diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h
index 02872457b5..8f8922bcea 100644
--- a/source4/lib/socket/socket.h
+++ b/source4/lib/socket/socket.h
@@ -127,6 +127,7 @@ struct socket_context {
};
struct resolve_context;
+struct tsocket_address;
/* prototypes */
NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
@@ -158,6 +159,12 @@ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, cons
char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx);
struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx);
struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
+ const struct socket_address *a);
+struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *a);
+struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx);
int socket_get_fd(struct socket_context *sock);
NTSTATUS socket_dup(struct socket_context *sock);
struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
diff --git a/source4/libcli/finddcs.c b/source4/libcli/finddcs.c
index 8330042ea1..04b25d37ef 100644
--- a/source4/libcli/finddcs.c
+++ b/source4/libcli/finddcs.c
@@ -158,6 +158,9 @@ static void finddcs_name_resolved(struct composite_context *ctx)
if (composite_nomem(state->r.in.my_accountname, state->ctx)) return;
state->r.in.account_control = ACB_WSTRUST;
state->r.in.domain_sid = state->domain_sid;
+ if (state->r.in.domain_sid == NULL) {
+ state->r.in.domain_sid = talloc_zero(state, struct dom_sid);
+ }
ireq = irpc_call_send(state->msg_ctx, nbt_servers[0],
&ndr_table_irpc, NDR_NBTD_GETDCNAME,
diff --git a/source4/libcli/security/sddl.c b/source4/libcli/security/sddl.c
index 2244a3d3ed..c4f8c5667b 100644
--- a/source4/libcli/security/sddl.c
+++ b/source4/libcli/security/sddl.c
@@ -304,7 +304,7 @@ static struct security_acl *sddl_decode_acl(struct security_descriptor *sd,
acl = talloc_zero(sd, struct security_acl);
if (acl == NULL) return NULL;
- acl->revision = SECURITY_ACL_REVISION_NT4;
+ acl->revision = SECURITY_ACL_REVISION_ADS;
if (isupper(sddl[0]) && sddl[1] == ':') {
/* its an empty ACL */
diff --git a/source4/libcli/security/tests/bindings.py b/source4/libcli/security/tests/bindings.py
index 00fa05d070..6fe3d5471d 100644
--- a/source4/libcli/security/tests/bindings.py
+++ b/source4/libcli/security/tests/bindings.py
@@ -2,17 +2,17 @@
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
+#
# 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/>.
#
@@ -46,6 +46,7 @@ class SecurityTokenTests(unittest.TestCase):
class SecurityDescriptorTests(unittest.TestCase):
+
def setUp(self):
self.descriptor = security.descriptor()
@@ -100,6 +101,10 @@ class SecurityDescriptorTests(unittest.TestCase):
desc1 = security.descriptor.from_sddl(text, dom)
self.assertNotEqual(desc1.as_sddl(), desc1.as_sddl(dom))
+ def test_split(self):
+ dom = security.dom_sid("S-2-0-7")
+ self.assertEquals((security.dom_sid("S-2-0"), 7), dom.split())
+
class DomSidTests(unittest.TestCase):
def test_parse_sid(self):
diff --git a/source4/libnet/libnet.c b/source4/libnet/libnet.c
index b10fb65df6..86cf80b4da 100644
--- a/source4/libnet/libnet.c
+++ b/source4/libnet/libnet.c
@@ -42,6 +42,9 @@ struct libnet_context *libnet_context_init(struct tevent_context *ev,
ctx->event_ctx = ev;
ctx->lp_ctx = lp_ctx;
+ /* make sure dcerpc is initialized */
+ dcerpc_init(lp_ctx);
+
/* name resolution methods */
ctx->resolve_ctx = lp_resolve_context(lp_ctx);
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c
index cb09e3041e..8195347b83 100644
--- a/source4/libnet/libnet_passwd.c
+++ b/source4/libnet/libnet_passwd.c
@@ -109,11 +109,11 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
nt_errstr(status));
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
- r->samr.in.domain_name, r->samr.in.account_name,
+ r->samr.in.domain_name, r->samr.in.account_name,
nt_errstr(status));
}
goto disconnect;
- }
+ }
/* prepare samr_ChangePasswordUser2 */
encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
@@ -216,7 +216,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
#endif
disconnect:
/* close connection */
- talloc_free(c.out.dcerpc_pipe);
+ talloc_unlink(ctx, c.out.dcerpc_pipe);
return status;
}
@@ -627,7 +627,7 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
disconnect:
/* close connection */
- talloc_free(c.out.dcerpc_pipe);
+ talloc_unlink(ctx, c.out.dcerpc_pipe);
return status;
}
diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c
index 4d3e81ce26..e5ca5e1c97 100644
--- a/source4/libnet/py_net.c
+++ b/source4/libnet/py_net.c
@@ -1,18 +1,19 @@
-/*
+/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
-
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+
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/>.
*/
@@ -65,10 +66,16 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs)
creds = cli_credentials_from_py_object(py_creds);
if (creds == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected credentials object");
+ talloc_free(mem_ctx);
return NULL;
}
libnet_ctx = py_net_ctx(cls, ev, creds);
+ if (libnet_ctx == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Unable to initialize libnet");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
status = libnet_Join(libnet_ctx, mem_ctx, &r);
if (NT_STATUS_IS_ERR(status)) {
@@ -77,7 +84,7 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs)
return NULL;
}
- result = Py_BuildValue("sss", r.out.join_password,
+ result = Py_BuildValue("sss", r.out.join_password,
dom_sid_string(mem_ctx, r.out.domain_sid),
r.out.domain_name);
@@ -89,15 +96,72 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs)
return result;
}
-static char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \
+static PyObject *py_net_set_password(PyObject *cls, PyObject *args, PyObject *kwargs)
+{
+ union libnet_SetPassword r;
+ NTSTATUS status;
+ PyObject *py_creds;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_context *ev;
+ struct libnet_context *libnet_ctx;
+ struct cli_credentials *creds;
+ const char *kwnames[] = { "account_name", "domain_name", "newpassword", "credentials", NULL };
+
+ r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssO:SetPassword", discard_const_p(char *, kwnames),
+ &r.generic.in.account_name, &r.generic.in.domain_name,
+ &r.generic.in.newpassword, &py_creds)) {
+ return NULL;
+ }
+
+ /* FIXME: we really need to get a context from the caller or we may end
+ * up with 2 event contexts */
+ ev = s4_event_context_init(NULL);
+ mem_ctx = talloc_new(ev);
+
+ creds = cli_credentials_from_py_object(py_creds);
+ if (creds == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected credentials object");
+ return NULL;
+ }
+
+ libnet_ctx = py_net_ctx(cls, ev, creds);
+
+ status = libnet_SetPassword(libnet_ctx, mem_ctx, &r);
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetString(PyExc_RuntimeError, r.generic.out.error_string);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static const char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \
"Join the domain with the specified name.";
+static const char py_net_set_password_doc[] = "SetPassword(account_name, domain_name, newpassword) -> True\n\n" \
+"Set password for a user. You must supply credential with enough rights to do this.\n\n" \
+"Sample usage is:\n" \
+"creds = samba.credentials.Credentials()\n" \
+"creds.set_username('admin_user')\n" \
+"creds.set_domain('domain_name')\n" \
+"creds.set_password('pass')\n\n" \
+"net.SetPassword(account_name=<account_name>,\n" \
+" domain_name=creds.get_domain(),\n" \
+" newpassword=new_pass,\n" \
+" credentials=creds)\n";
+
+
static struct PyMethodDef net_methods[] = {
{"Join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
+ {"SetPassword", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
{NULL }
};
void initnet(void)
{
- Py_InitModule("net", net_methods);
+ Py_InitModule3("net", net_methods, NULL);
}
+
diff --git a/source4/librpc/ndr/py_security.c b/source4/librpc/ndr/py_security.c
index 02dc059f05..d04e2579f5 100644
--- a/source4/librpc/ndr/py_security.c
+++ b/source4/librpc/ndr/py_security.c
@@ -41,6 +41,33 @@ static void PyType_AddMethods(PyTypeObject *type, PyMethodDef *methods)
}
}
+static PyObject *py_dom_sid_split(PyObject *py_self, PyObject *args)
+{
+ struct dom_sid *self = py_talloc_get_ptr(py_self);
+ struct dom_sid *domain_sid;
+ TALLOC_CTX *mem_ctx;
+ uint32_t rid;
+ NTSTATUS status;
+ PyObject *py_domain_sid;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ status = dom_sid_split_rid(mem_ctx, self, &domain_sid, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_domain_sid = py_talloc_steal(&dom_sid_Type, domain_sid);
+ talloc_free(mem_ctx);
+ return Py_BuildValue("(OI)", py_domain_sid, rid);
+}
+
static int py_dom_sid_cmp(PyObject *py_self, PyObject *py_other)
{
struct dom_sid *self = py_talloc_get_ptr(py_self), *other;
@@ -86,12 +113,21 @@ static int py_dom_sid_init(PyObject *self, PyObject *args, PyObject *kwargs)
return 0;
}
+static PyMethodDef py_dom_sid_extra_methods[] = {
+ { "split", (PyCFunction)py_dom_sid_split, METH_NOARGS,
+ "S.split() -> (domain_sid, rid)\n"
+ "Split a domain sid" },
+ { NULL }
+};
+
+
static void py_dom_sid_patch(PyTypeObject *type)
{
type->tp_init = py_dom_sid_init;
type->tp_str = py_dom_sid_str;
type->tp_repr = py_dom_sid_repr;
type->tp_compare = py_dom_sid_cmp;
+ PyType_AddMethods(type, py_dom_sid_extra_methods);
}
#define PY_DOM_SID_PATCH py_dom_sid_patch
diff --git a/source4/min_versions.m4 b/source4/min_versions.m4
index 5bb3b0b3a9..af8c4dd8fb 100644
--- a/source4/min_versions.m4
+++ b/source4/min_versions.m4
@@ -1,6 +1,6 @@
# Minimum and exact required versions for various libraries
# if we use the ones installed in the system.
define(TDB_MIN_VERSION,1.2.0)
-define(TALLOC_MIN_VERSION,2.0.0)
+define(TALLOC_MIN_VERSION,2.0.1)
define(LDB_REQUIRED_VERSION,0.9.10)
define(TEVENT_REQUIRED_VERSION,0.9.8)
diff --git a/source4/param/config.mk b/source4/param/config.mk
index 6e5290b64d..a5bcea691b 100644
--- a/source4/param/config.mk
+++ b/source4/param/config.mk
@@ -13,7 +13,7 @@ PUBLIC_HEADERS += param/param.h
PC_FILES += $(paramsrcdir)/samba-hostconfig.pc
[SUBSYSTEM::PROVISION]
-PRIVATE_DEPENDENCIES = LIBPYTHON pyldb pyparam_util
+PRIVATE_DEPENDENCIES = LIBPYTHON pyparam_util LIBLDB
PROVISION_OBJ_FILES = $(paramsrcdir)/provision.o $(param_OBJ_FILES)
diff --git a/source4/param/provision.c b/source4/param/provision.c
index 8c6e1c0f68..7bd10ca522 100644
--- a/source4/param/provision.c
+++ b/source4/param/provision.c
@@ -52,6 +52,34 @@ static PyObject *schema_module(void)
return PyImport_Import(name);
}
+static PyObject *ldb_module(void)
+{
+ PyObject *name = PyString_FromString("ldb");
+ if (name == NULL)
+ return NULL;
+ return PyImport_Import(name);
+}
+
+static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
+{
+ PyLdbObject *ret;
+ PyObject *ldb_mod = ldb_module();
+ PyTypeObject *ldb_ctx_type;
+ if (ldb_mod == NULL)
+ return NULL;
+
+ ldb_ctx_type = PyObject_GetAttrString(ldb_mod, "Ldb");
+
+ ret = (PyLdbObject *)ldb_ctx_type->tp_alloc(ldb_ctx_type, 0);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = talloc_new(NULL);
+ ret->ldb_ctx = talloc_reference(ret->mem_ctx, ldb_ctx);
+ return (PyObject *)ret;
+}
+
NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
struct provision_settings *settings,
struct provision_result *result)
@@ -167,8 +195,6 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
return NT_STATUS_OK;
}
-extern void initldb(void);
-
static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
{
PyObject *mod_security, *dom_sid_Type;
@@ -220,7 +246,6 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context
py_load_samba_modules();
Py_Initialize();
py_update_path("bin"); /* FIXME: Can't assume this is always the case */
- initldb();
provision_mod = provision_module();
if (provision_mod == NULL) {
diff --git a/source4/param/pyparam.c b/source4/param/pyparam.c
index eb2da11bb0..b4255002d2 100644
--- a/source4/param/pyparam.c
+++ b/source4/param/pyparam.c
@@ -374,6 +374,9 @@ void initparam(void)
if (PyType_Ready(&PyLoadparmContext) < 0)
return;
+ if (PyType_Ready(&PyLoadparmService) < 0)
+ return;
+
m = Py_InitModule3("param", pyparam_methods, "Parsing and writing Samba configuration files.");
if (m == NULL)
return;
diff --git a/source4/param/tests/bindings.py b/source4/param/tests/bindings.py
index 41a67f93fc..1915e79223 100644
--- a/source4/param/tests/bindings.py
+++ b/source4/param/tests/bindings.py
@@ -2,17 +2,17 @@
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
+#
# 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/>.
#
@@ -50,3 +50,7 @@ class LoadParmTestCase(unittest.TestCase):
file = param.LoadParm()
file.load_default()
+ def test_section_nonexistant(self):
+ samba_lp = param.LoadParm()
+ samba_lp.load_default()
+ self.assertRaises(KeyError, samba_lp.__getitem__, "nonexistant")
diff --git a/source4/rpc_server/drsuapi/addentry.c b/source4/rpc_server/drsuapi/addentry.c
index 89b664d691..ac94daa6a6 100644
--- a/source4/rpc_server/drsuapi/addentry.c
+++ b/source4/rpc_server/drsuapi/addentry.c
@@ -199,7 +199,8 @@ WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX
ret = ldb_transaction_commit(b_state->sam_ctx);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": DsAddEntry commit failed\n"));
+ DEBUG(0,(__location__ ": DsAddEntry commit failed: %s\n",
+ ldb_errstring(b_state->sam_ctx)));
return WERR_DS_DRA_INTERNAL_ERROR;
}
diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
index 3d92880162..6a6bc8be7e 100644
--- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
+++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
@@ -159,10 +159,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
- if (0 /*domain.behavior_version == 2*/) {
- /* TODO: find out how this is really triggered! */
- b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
- }
+ b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h
index e42d9569e7..3a64ef5c9c 100644
--- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h
+++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h
@@ -57,7 +57,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb,
struct ldb_dn *basedn,
enum ldb_scope scope,
const char * const *attrs,
- const char *sort_attrib,
const char *filter);
WERROR drs_security_level_check(struct dcesrv_call_state *dce_call,
diff --git a/source4/rpc_server/drsuapi/drsutil.c b/source4/rpc_server/drsuapi/drsutil.c
index a62f911537..0a8a576d60 100644
--- a/source4/rpc_server/drsuapi/drsutil.c
+++ b/source4/rpc_server/drsuapi/drsutil.c
@@ -47,7 +47,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb,
struct ldb_dn *basedn,
enum ldb_scope scope,
const char * const *attrs,
- const char *sort_attrib,
const char *filter)
{
int ret;
@@ -86,26 +85,11 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb,
return ret;
}
- if (sort_attrib) {
- struct ldb_server_sort_control **sort_control;
- sort_control = talloc_array(req, struct ldb_server_sort_control *, 2);
- if (sort_control == NULL) {
- talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- sort_control[0] = talloc(req, struct ldb_server_sort_control);
- sort_control[0]->attributeName = sort_attrib;
- sort_control[0]->orderingRule = NULL;
- sort_control[0]->reverse = 0;
- sort_control[1] = NULL;
-
- ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, sort_control);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
-
ret = ldb_request(ldb, req);
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 488ecd129e..437dc87ae8 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -25,11 +25,38 @@
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
#include "rpc_server/dcerpc_server_proto.h"
#include "../libcli/drsuapi/drsuapi.h"
#include "libcli/security/security.h"
+/*
+ build a DsReplicaObjectIdentifier from a ldb msg
+ */
+static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg)
+{
+ struct drsuapi_DsReplicaObjectIdentifier *identifier;
+ struct dom_sid *sid;
+
+ identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
+ if (identifier == NULL) {
+ return NULL;
+ }
+
+ identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn);
+ identifier->guid = samdb_result_guid(msg, "objectGUID");
+
+ sid = samdb_result_dom_sid(identifier, msg, "objectSid");
+ if (sid) {
+ identifier->sid = *sid;
+ } else {
+ ZERO_STRUCT(identifier->sid);
+ }
+ return identifier;
+}
+
/*
drsuapi_DsGetNCChanges for one object
*/
@@ -44,9 +71,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
{
const struct ldb_val *md_value;
int i, n;
- struct ldb_dn *obj_dn;
struct replPropertyMetaDataBlob md;
- struct dom_sid *sid;
uint32_t rid = 0;
enum ndr_err_code ndr_err;
uint32_t *attids;
@@ -104,20 +129,15 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr);
attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count);
- obj->object.identifier = talloc(obj, struct drsuapi_DsReplicaObjectIdentifier);
- obj_dn = ldb_msg_find_attr_as_dn(sam_ctx, obj, msg, "distinguishedName");
- obj->object.identifier->dn = ldb_dn_get_linearized(obj_dn);
- obj->object.identifier->guid = samdb_result_guid(msg, "objectGUID");
- sid = samdb_result_dom_sid(obj, msg, "objectSid");
- if (sid) {
- dom_sid_split_rid(NULL, sid, NULL, &rid);
- obj->object.identifier->sid = *sid;
- } else {
- ZERO_STRUCT(obj->object.identifier->sid);
+ obj->object.identifier = get_object_identifier(obj, msg);
+ if (obj->object.identifier == NULL) {
+ return WERR_NOMEM;
}
+ dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid);
obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
for (n=i=0; i<md.ctr.ctr1.count; i++) {
+ const struct dsdb_attribute *sa;
/* if the attribute has not changed, and it is not the
instanceType then don't include it */
if (md.ctr.ctr1.array[i].local_usn < highest_usn &&
@@ -126,6 +146,16 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
/* don't include the rDN */
if (md.ctr.ctr1.array[i].attid == rdn_sa->attributeID_id) continue;
+ sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid);
+ if (sa->linkID) {
+ struct ldb_message_element *el;
+ el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
+ if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) {
+ /* don't send upgraded links inline */
+ continue;
+ }
+ }
+
obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time;
obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version;
obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id;
@@ -199,6 +229,149 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
return WERR_OK;
}
+
+/*
+ add one linked attribute from an object to the list of linked
+ attributes in a getncchanges request
+ */
+static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx,
+ struct ldb_context *sam_ctx,
+ const struct dsdb_schema *schema,
+ const struct dsdb_attribute *sa,
+ struct ldb_message *msg,
+ struct dsdb_dn *dsdb_dn,
+ struct drsuapi_DsReplicaLinkedAttribute **la_list,
+ uint32_t *la_count)
+{
+ struct drsuapi_DsReplicaLinkedAttribute *la;
+ bool active;
+ NTSTATUS status;
+ WERROR werr;
+
+ (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1);
+ W_ERROR_HAVE_NO_MEMORY(*la_list);
+
+ la = &(*la_list)[*la_count];
+
+ la->identifier = get_object_identifier(*la_list, msg);
+ W_ERROR_HAVE_NO_MEMORY(la->identifier);
+
+ active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0;
+
+ la->attid = sa->attributeID_id;
+ la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0;
+
+ status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME");
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+ status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION");
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+ status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME");
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID");
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+ status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN");
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ (*la_count)++;
+ return WERR_OK;
+}
+
+
+/*
+ add linked attributes from an object to the list of linked
+ attributes in a getncchanges request
+ */
+static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *ncRoot_dn,
+ struct dsdb_schema *schema,
+ uint64_t highest_usn,
+ uint32_t replica_flags,
+ struct ldb_message *msg,
+ struct drsuapi_DsReplicaLinkedAttribute **la_list,
+ uint32_t *la_count)
+{
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ uint64_t uSNChanged = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1);
+
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct dsdb_attribute *sa;
+ int j;
+
+ sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+
+ if (!sa || sa->linkID == 0 || (sa->linkID & 1)) {
+ /* we only want forward links */
+ continue;
+ }
+
+ if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) {
+ /* its an old style link, it will have been
+ * sent in the main replication data */
+ continue;
+ }
+
+ for (j=0; j<el->num_values; j++) {
+ struct dsdb_dn *dsdb_dn;
+ uint64_t local_usn;
+ NTSTATUS status;
+ WERROR werr;
+
+ dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid);
+ if (dsdb_dn == NULL) {
+ DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n",
+ el->name, ldb_dn_get_linearized(msg->dn)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN");
+ if (!NT_STATUS_IS_OK(status)) {
+ /* this can happen for attributes
+ given to us with old style meta
+ data */
+ continue;
+ }
+
+ if (local_usn > uSNChanged) {
+ DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n",
+ el->name, ldb_dn_get_linearized(msg->dn)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ if (local_usn < highest_usn) {
+ continue;
+ }
+
+ werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema, sa, msg,
+ dsdb_dn, la_list, la_count);
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(tmp_ctx);
+ return werr;
+ }
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return WERR_OK;
+}
+
/*
load replUpToDateVector from a DN
*/
@@ -255,6 +428,7 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
NTTIME now;
time_t t = time(NULL);
struct replUpToDateVectorBlob ouv;
+ int i;
werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv);
if (!W_ERROR_IS_OK(werr)) {
@@ -267,13 +441,24 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
unix_to_nt_time(&now, t);
tmp_cursor->last_sync_success = now;
- udv->count = ouv.ctr.ctr2.count + 1;
+ udv->count = ouv.ctr.ctr2.count;
udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors);
- udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count);
- if (!udv->cursors) {
- return WERR_DS_DRA_INTERNAL_ERROR;
+
+ for (i=0; i<udv->count; i++) {
+ if (GUID_equal(&tmp_cursor->source_dsa_invocation_id,
+ &udv->cursors[i].source_dsa_invocation_id)) {
+ udv->cursors[i] = *tmp_cursor;
+ break;
+ }
+ }
+ if (i == udv->count) {
+ udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count+1);
+ if (!udv->cursors) {
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ udv->cursors[udv->count] = *tmp_cursor;
+ udv->count++;
}
- udv->cursors[udv->count - 1] = *tmp_cursor;
qsort(udv->cursors, udv->count,
sizeof(struct drsuapi_DsReplicaCursor2),
@@ -282,6 +467,103 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
return WERR_OK;
}
+
+/* comparison function for linked attributes - see CompareLinks() in
+ * MS-DRSR section 4.1.10.5.17 */
+static int linked_attribute_compare(const struct drsuapi_DsReplicaLinkedAttribute *la1,
+ const struct drsuapi_DsReplicaLinkedAttribute *la2,
+ struct ldb_context *sam_ctx)
+{
+ int c;
+ WERROR werr;
+ TALLOC_CTX *tmp_ctx;
+ const struct dsdb_schema *schema;
+ const struct dsdb_attribute *schema_attrib;
+ struct dsdb_dn *dn1, *dn2;
+ struct GUID guid1, guid2;
+ NTSTATUS status;
+
+ c = GUID_compare(&la1->identifier->guid,
+ &la2->identifier->guid);
+ if (c != 0) return c;
+
+ if (la1->attid != la2->attid) {
+ return la1->attid < la2->attid? -1:1;
+ }
+
+ if ((la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
+ (la2->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
+ return (la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
+ }
+
+ /* we need to get the target GUIDs to compare */
+ tmp_ctx = talloc_new(sam_ctx);
+
+ schema = dsdb_get_schema(sam_ctx);
+ schema_attrib = dsdb_attribute_by_attributeID_id(schema, la1->attid);
+
+ werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la1->value.blob, &dn1);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,(__location__ ": Bad la1 blob in sort\n"));
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+
+ werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la2->value.blob, &dn2);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,(__location__ ": Bad la2 blob in sort\n"));
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+
+ status = dsdb_get_extended_dn_guid(dn1->dn, &guid1, "GUID");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,(__location__ ": Bad la1 guid in sort\n"));
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+ status = dsdb_get_extended_dn_guid(dn2->dn, &guid2, "GUID");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,(__location__ ": Bad la2 guid in sort\n"));
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+
+ talloc_free(tmp_ctx);
+
+ return GUID_compare(&guid1, &guid2);
+}
+
+
+/*
+ sort the objects we send by tree order
+ */
+static int site_res_cmp_parent_order(const struct ldb_message **m1, const struct ldb_message **m2)
+{
+ return ldb_dn_compare((*m2)->dn, (*m1)->dn);
+}
+
+/*
+ sort the objects we send first by uSNChanged
+ */
+static int site_res_cmp_usn_order(const struct ldb_message **m1, const struct ldb_message **m2)
+{
+ unsigned usnchanged1, usnchanged2;
+ unsigned cn1, cn2;
+ cn1 = ldb_dn_get_comp_num((*m1)->dn);
+ cn2 = ldb_dn_get_comp_num((*m2)->dn);
+ if (cn1 != cn2) {
+ return cn1 > cn2 ? 1 : -1;
+ }
+ usnchanged1 = ldb_msg_find_attr_as_uint(*m1, "uSNChanged", 0);
+ usnchanged2 = ldb_msg_find_attr_as_uint(*m2, "uSNChanged", 0);
+ if (usnchanged1 == usnchanged2) {
+ return 0;
+ }
+ return usnchanged1 > usnchanged2 ? 1 : -1;
+}
+
+
/* state of a partially completed getncchanges call */
struct drsuapi_getncchanges_state {
struct ldb_result *site_res;
@@ -289,6 +571,9 @@ struct drsuapi_getncchanges_state {
struct ldb_dn *ncRoot_dn;
uint64_t min_usn;
uint64_t highest_usn;
+ struct ldb_dn *last_dn;
+ struct drsuapi_DsReplicaLinkedAttribute *la_list;
+ uint32_t la_count;
};
/*
@@ -323,6 +608,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
struct drsuapi_getncchanges_state *getnc_state;
struct drsuapi_DsGetNCChangesRequest8 *req8;
uint32_t options;
+ uint32_t max_objects;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
@@ -389,9 +675,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
if (getnc_state) {
struct ldb_dn *new_dn = ldb_dn_new(getnc_state, b_state->sam_ctx, ncRoot->dn);
if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
- DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s\n",
+ DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n",
ldb_dn_get_linearized(new_dn),
- ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
+ ldb_dn_get_linearized(getnc_state->ncRoot_dn),
+ ldb_dn_get_linearized(getnc_state->last_dn)));
talloc_free(getnc_state);
getnc_state = NULL;
}
@@ -433,6 +720,9 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
if (getnc_state->site_res == NULL) {
char* search_filter;
enum ldb_scope scope = LDB_SCOPE_SUBTREE;
+ const char *extra_filter;
+
+ extra_filter = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
getnc_state->min_usn = req8->highwatermark.highest_usn;
@@ -441,6 +731,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
"(uSNChanged>=%llu)",
(unsigned long long)(getnc_state->min_usn+1));
+ if (extra_filter) {
+ search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
+ }
+
if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_CRITICAL_ONLY) {
search_filter = talloc_asprintf(mem_ctx,
"(&%s(isCriticalSystemObject=TRUE))",
@@ -451,15 +745,27 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
scope = LDB_SCOPE_BASE;
}
- DEBUG(6,(__location__ ": getncchanges on %s using filter %s\n",
+ DEBUG(1,(__location__ ": getncchanges on %s using filter %s\n",
ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, &getnc_state->site_res,
getnc_state->ncRoot_dn, scope, attrs,
- "uSNChanged",
search_filter);
if (ret != LDB_SUCCESS) {
return WERR_DS_DRA_INTERNAL_ERROR;
}
+
+ if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS) {
+ qsort(getnc_state->site_res->msgs,
+ getnc_state->site_res->count,
+ sizeof(getnc_state->site_res->msgs[0]),
+ (comparison_fn_t)site_res_cmp_parent_order);
+ } else {
+ qsort(getnc_state->site_res->msgs,
+ getnc_state->site_res->count,
+ sizeof(getnc_state->site_res->msgs[0]),
+ (comparison_fn_t)site_res_cmp_usn_order);
+ }
+
}
/* Prefix mapping */
@@ -494,23 +800,25 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
r->out.ctr->ctr6.first_object = NULL;
currentObject = &r->out.ctr->ctr6.first_object;
+ /* use this to force single objects at a time, which is useful
+ * for working out what object is giving problems
+ */
+ max_objects = lp_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max object sync", 1000);
+ if (req8->max_object_count < max_objects) {
+ max_objects = req8->max_object_count;
+ }
+
for(i=getnc_state->num_sent;
i<getnc_state->site_res->count &&
- (r->out.ctr->ctr6.object_count < req8->max_object_count);
+ (r->out.ctr->ctr6.object_count < max_objects);
i++) {
int uSN;
struct drsuapi_DsReplicaObjectListItemEx *obj;
- obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
+ struct ldb_message *msg = getnc_state->site_res->msgs[i];
- uSN = ldb_msg_find_attr_as_int(getnc_state->site_res->msgs[i], "uSNChanged", -1);
- if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) {
- r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN;
- }
- if (uSN > getnc_state->highest_usn) {
- getnc_state->highest_usn = uSN;
- }
+ obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
- werr = get_nc_changes_build_object(obj, getnc_state->site_res->msgs[i],
+ werr = get_nc_changes_build_object(obj, msg,
b_state->sam_ctx, getnc_state->ncRoot_dn,
schema, &session_key, getnc_state->min_usn,
req8->replica_flags);
@@ -518,9 +826,28 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
return werr;
}
+ werr = get_nc_changes_add_links(b_state->sam_ctx, getnc_state,
+ getnc_state->ncRoot_dn,
+ schema, getnc_state->min_usn,
+ req8->replica_flags,
+ msg,
+ &getnc_state->la_list,
+ &getnc_state->la_count);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1);
+ if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) {
+ r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN;
+ }
+ if (uSN > getnc_state->highest_usn) {
+ getnc_state->highest_usn = uSN;
+ }
+
if (obj->meta_data_ctr == NULL) {
DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n",
- ldb_dn_get_linearized(getnc_state->site_res->msgs[i]->dn)));
+ ldb_dn_get_linearized(msg->dn)));
/* no attributes to send */
talloc_free(obj);
continue;
@@ -530,6 +857,11 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
*currentObject = obj;
currentObject = &obj->next_object;
+
+ talloc_free(getnc_state->last_dn);
+ getnc_state->last_dn = ldb_dn_copy(getnc_state, msg->dn);
+
+ DEBUG(8,(__location__ ": replicating object %s\n", ldb_dn_get_linearized(msg->dn)));
}
getnc_state->num_sent += r->out.ctr->ctr6.object_count;
@@ -562,6 +894,13 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
if (i < getnc_state->site_res->count) {
r->out.ctr->ctr6.more_data = true;
} else {
+ r->out.ctr->ctr6.linked_attributes_count = getnc_state->la_count;
+ r->out.ctr->ctr6.linked_attributes = talloc_steal(mem_ctx, getnc_state->la_list);
+
+ ldb_qsort(r->out.ctr->ctr6.linked_attributes, r->out.ctr->ctr6.linked_attributes_count,
+ sizeof(r->out.ctr->ctr6.linked_attributes[0]),
+ b_state->sam_ctx, (ldb_qsort_cmp_fn_t)linked_attribute_compare);
+
r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx);
r->out.ctr->ctr6.uptodateness_vector->version = 2;
r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0;
@@ -580,11 +919,19 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
b_state->getncchanges_state = NULL;
}
- DEBUG(2,("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d)\n",
- (unsigned long long)(req8->highwatermark.highest_usn+1),
- req8->replica_flags,
- ncRoot->dn, r->out.ctr->ctr6.object_count,
- i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i));
+ DEBUG(r->out.ctr->ctr6.more_data?2:1,
+ ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d la=%d)\n",
+ (unsigned long long)(req8->highwatermark.highest_usn+1),
+ req8->replica_flags,
+ ncRoot->dn, r->out.ctr->ctr6.object_count,
+ i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i,
+ r->out.ctr->ctr6.linked_attributes_count));
+
+#if 0
+ if (!r->out.ctr->ctr6.more_data) {
+ NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsGetNCChanges, NDR_BOTH, r);
+ }
+#endif
return WERR_OK;
}
diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c
index 6e2efed4f9..b1e3d6c352 100644
--- a/source4/rpc_server/drsuapi/updaterefs.c
+++ b/source4/rpc_server/drsuapi/updaterefs.c
@@ -105,7 +105,9 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
return werr;
}
- if (!found && !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK)) {
+ if (!found &&
+ !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK) &&
+ !(options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE)) {
return WERR_DS_DRA_REF_NOT_FOUND;
}
diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh
index cb618628b0..15fc64544c 100755
--- a/source4/script/installmisc.sh
+++ b/source4/script/installmisc.sh
@@ -1,28 +1,42 @@
#!/bin/sh
# install miscellaneous files
-[ $# -eq 5 ] || {
- echo "Usage: installmisc.sh SRCDIR SETUPDIR BINDDIR SBINDDIR PYTHONDIR"
+[ $# -eq 7 ] || {
+ echo "Usage: installmisc.sh DESTDIR SRCDIR SETUPDIR BINDDIR SBINDDIR PYTHONDIR PYTHON"
exit 1
}
-SRCDIR="$1"
-SETUPDIR="$2"
-BINDIR="$3"
-SBINDIR="$4"
-PYTHONDIR="$5"
+DESTDIR="$1"
+SRCDIR="$2"
+SETUPDIR="$3"
+BINDIR="$4"
+SBINDIR="$5"
+PYTHONDIR="$6"
+PYTHON="$7"
cd $SRCDIR || exit 1
+if $PYTHON -c "import sys; sys.exit('$PYTHONDIR' in sys.path)"; then
+ PYTHON_PATH_NEEDS_FIXING=yes
+ echo "sys.path in python scripts will be updated to include $PYTHONDIR"
+else
+ PYTHON_PATH_NEEDS_FIXING=no
+fi
+
# fixup a python script to use the right path
fix_python_path() {
f="$1"
- egrep 'sys.path.insert.*bin/python' $f > /dev/null && {
- # old systems don't have sed -i :-(
- sed "s|\(sys.path.insert.*\)bin/python\(.*\)$|\1$PYTHONDIR\2|g" < $f > $f.$$ || exit 1
- mv -f $f.$$ $f || exit 1
- chmod +x $f
- }
+ if egrep 'sys.path.insert.*bin/python' $f > /dev/null; then
+ if [ "$PYTHON_PATH_NEEDS_FIXING" = "yes" ]; then
+ # old systems don't have sed -i :-(
+ sed "s|\(sys.path.insert.*\)bin/python\(.*\)$|\1$PYTHONDIR\2|g" < $f > $f.$$ || exit 1
+ else
+ # old systems don't have sed -i :-(
+ sed "s|\(sys.path.insert.*\)bin/python\(.*\)$||g" < $f > $f.$$ || exit 1
+ fi
+ mv -f $f.$$ $f || exit 1
+ chmod +x $f
+ fi
}
echo "Installing setup templates"
@@ -35,7 +49,7 @@ cp setup/ad-schema/*.txt $SETUPDIR/ad-schema || exit 1
cp setup/display-specifiers/*.txt $SETUPDIR/display-specifiers || exit 1
echo "Installing sbin scripts from setup/*"
-for p in domainlevel enableaccount newuser provision setexpiry setpassword pwsettings
+for p in provision
do
cp setup/$p $SBINDIR || exit 1
chmod a+x $SBINDIR/$p
diff --git a/source4/scripting/python/modules.c b/source4/scripting/python/modules.c
index 5365c5007d..198b3ccf12 100644
--- a/source4/scripting/python/modules.c
+++ b/source4/scripting/python/modules.c
@@ -61,10 +61,47 @@ void py_load_samba_modules(void)
}
}
-void py_update_path(const char *bindir)
+static bool PySys_PathPrepend(PyObject *list, const char *path)
+{
+ PyObject *py_path = PyString_FromString(path);
+ if (py_path == NULL)
+ return false;
+
+ return (PyList_Insert(list, 0, py_path) == 0);
+}
+
+bool py_update_path(const char *bindir)
{
char *newpath;
- asprintf(&newpath, "%s/python:%s/../scripting/python:%s", bindir, bindir, Py_GetPath());
- PySys_SetPath(newpath);
+ PyObject *mod_sys, *py_path;
+
+ mod_sys = PyImport_ImportModule("sys");
+ if (mod_sys == NULL) {
+ return false;
+ }
+
+ py_path = PyObject_GetAttrString(mod_sys, "path");
+ if (py_path == NULL) {
+ return false;
+ }
+
+ if (!PyList_Check(py_path)) {
+ return false;
+ }
+
+ asprintf(&newpath, "%s/../scripting/python", bindir);
+ if (!PySys_PathPrepend(py_path, newpath)) {
+ free(newpath);
+ return false;
+ }
free(newpath);
+
+ asprintf(&newpath, "%s/python", bindir);
+ if (!PySys_PathPrepend(py_path, newpath)) {
+ free(newpath);
+ return false;
+ }
+ free(newpath);
+
+ return true;
}
diff --git a/source4/scripting/python/modules.h b/source4/scripting/python/modules.h
index 6b242ee257..4d1067cdd4 100644
--- a/source4/scripting/python/modules.h
+++ b/source4/scripting/python/modules.h
@@ -21,7 +21,7 @@
#define __SAMBA_PYTHON_MODULES_H__
void py_load_samba_modules(void);
-void py_update_path(const char *bindir);
+bool py_update_path(const char *bindir);
#define py_iconv_convenience(mem_ctx) smb_iconv_convenience_init(mem_ctx, "ASCII", PyUnicode_GetDefaultEncoding(), true)
diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c
index 9f01102316..3d33e605db 100644
--- a/source4/scripting/python/pyglue.c
+++ b/source4/scripting/python/pyglue.c
@@ -442,27 +442,6 @@ static PyObject *py_dsdb_make_schema_global(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *py_dom_sid_to_rid(PyLdbObject *self, PyObject *args)
-{
- PyObject *py_sid;
- struct dom_sid *sid;
- uint32_t rid;
- NTSTATUS status;
-
- if(!PyArg_ParseTuple(args, "O", &py_sid))
- return NULL;
-
- sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
-
- status = dom_sid_split_rid(NULL, sid, NULL, &rid);
- if (!NT_STATUS_IS_OK(status)) {
- PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed");
- return NULL;
- }
-
- return PyInt_FromLong(rid);
-}
-
static PyMethodDef py_misc_methods[] = {
{ "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
"random_password(len) -> string\n"
@@ -506,8 +485,6 @@ static PyMethodDef py_misc_methods[] = {
NULL },
{ "dsdb_make_schema_global", (PyCFunction)py_dsdb_make_schema_global, METH_VARARGS,
NULL },
- { "dom_sid_to_rid", (PyCFunction)py_dom_sid_to_rid, METH_VARARGS,
- NULL },
{ "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
"set debug level" },
{ NULL }
diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py
index f74304c01c..5d61c1bd8c 100644
--- a/source4/scripting/python/samba/__init__.py
+++ b/source4/scripting/python/samba/__init__.py
@@ -2,20 +2,20 @@
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-#
+#
# Based on the original in EJS:
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 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/>.
#
@@ -45,11 +45,11 @@ import ldb
import glue
class Ldb(ldb.Ldb):
- """Simple Samba-specific LDB subclass that takes care
+ """Simple Samba-specific LDB subclass that takes care
of setting up the modules dir, credentials pointers, etc.
-
- Please note that this is intended to be for all Samba LDB files,
- not necessarily the Sam database. For Sam-specific helper
+
+ Please note that this is intended to be for all Samba LDB files,
+ not necessarily the Sam database. For Sam-specific helper
functions see samdb.py.
"""
def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
@@ -65,7 +65,7 @@ class Ldb(ldb.Ldb):
:param options: Additional options (optional)
This is different from a regular Ldb file in that the Samba-specific
- modules-dir is used by default and that credentials and session_info
+ modules-dir is used by default and that credentials and session_info
can be passed through (required by some modules).
"""
@@ -122,10 +122,10 @@ class Ldb(ldb.Ldb):
# need one public, we will have to change this here
super(Ldb, self).set_create_perms(perms)
- def searchone(self, attribute, basedn=None, expression=None,
+ def searchone(self, attribute, basedn=None, expression=None,
scope=ldb.SCOPE_BASE):
"""Search for one attribute as a string.
-
+
:param basedn: BaseDN for the search.
:param attribute: Name of the attribute
:param expression: Optional search expression.
@@ -166,7 +166,7 @@ class Ldb(ldb.Ldb):
self.erase_users_computers(basedn)
# Delete the 'visible' records, and the invisble 'deleted' records (if this DB supports it)
- for msg in self.search(basedn, ldb.SCOPE_SUBTREE,
+ for msg in self.search(basedn, ldb.SCOPE_SUBTREE,
"(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))",
[], controls=["show_deleted:0"]):
try:
@@ -174,14 +174,14 @@ class Ldb(ldb.Ldb):
except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
# Ignore no such object errors
pass
-
- res = self.search(basedn, ldb.SCOPE_SUBTREE,
+
+ res = self.search(basedn, ldb.SCOPE_SUBTREE,
"(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))",
[], controls=["show_deleted:0"])
assert len(res) == 0
# delete the specials
- for attr in ["@SUBCLASSES", "@MODULES",
+ for attr in ["@SUBCLASSES", "@MODULES",
"@OPTIONS", "@PARTITION", "@KLUDGEACL"]:
try:
self.delete(attr)
@@ -191,7 +191,7 @@ class Ldb(ldb.Ldb):
def erase(self):
"""Erase this ldb, removing all records."""
-
+
self.erase_except_schema_controlled()
# delete the specials
@@ -207,13 +207,12 @@ class Ldb(ldb.Ldb):
def erase_recursive(self, dn):
try:
- res = self.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=[],
+ res = self.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=[],
controls=["show_deleted:0"])
except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
# Ignore no such object errors
return
- pass
-
+
for msg in res:
erase_recursive(self, msg.dn)
@@ -223,7 +222,7 @@ class Ldb(ldb.Ldb):
# Ignore no such object errors
pass
- res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)",
+ res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)",
["namingContexts"])
assert len(res) == 1
if not "namingContexts" in res[0]:
@@ -285,14 +284,14 @@ class Ldb(ldb.Ldb):
def set_invocation_id(self, invocation_id):
"""Set the invocation id for this SamDB handle.
-
+
:param invocation_id: GUID of the invocation id.
"""
glue.dsdb_set_ntds_invocation_id(self, invocation_id)
def set_opaque_integer(self, name, value):
"""Set an integer as an opaque (a flag or other value) value on the database
-
+
:param name: The name for the opaque value
:param value: The integer value
"""
@@ -302,7 +301,7 @@ class Ldb(ldb.Ldb):
def substitute_var(text, values):
"""substitute strings of the form ${NAME} in str, replacing
with substitutions from subobj.
-
+
:param text: Text in which to subsitute.
:param values: Dictionary with keys and values.
"""
@@ -318,21 +317,21 @@ def substitute_var(text, values):
def check_all_substituted(text):
"""Make sure that all substitution variables in a string have been replaced.
If not, raise an exception.
-
+
:param text: The text to search for substitution variables
"""
if not "${" in text:
return
-
+
var_start = text.find("${")
var_end = text.find("}", var_start)
-
+
raise Exception("Not all variables substituted: %s" % text[var_start:var_end+1])
def read_and_sub_file(file, subst_vars):
"""Read a file and sub in variables found in it
-
+
:param file: File to be read (typically from setup directory)
param subst_vars: Optional variables to subsitute in the file.
"""
@@ -370,15 +369,6 @@ def valid_netbios_name(name):
return True
-def dom_sid_to_rid(sid_str):
- """Converts a domain SID to the relative RID.
-
- :param sid_str: The domain SID formatted as string
- """
-
- return glue.dom_sid_to_rid(sid_str)
-
-
version = glue.version
# "userAccountControl" flags
diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py
index 8b756b2d6f..48d48dc260 100644
--- a/source4/scripting/python/samba/getopt.py
+++ b/source4/scripting/python/samba/getopt.py
@@ -2,17 +2,17 @@
# Samba-specific bits for optparse
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
+#
# 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/>.
#
@@ -30,7 +30,7 @@ class SambaOptions(optparse.OptionGroup):
def __init__(self, parser):
optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
self.add_option("-s", "--configfile", action="callback",
- type=str, metavar="FILE", help="Configuration file",
+ type=str, metavar="FILE", help="Configuration file",
callback=self._load_configfile)
self._configfile = None
@@ -73,15 +73,15 @@ class CredentialsOptions(optparse.OptionGroup):
help="DN to use for a simple bind")
self.add_option("--password", metavar="PASSWORD", action="callback",
help="Password", type=str, callback=self._set_password)
- self.add_option("-U", "--username", metavar="USERNAME",
+ self.add_option("-U", "--username", metavar="USERNAME",
action="callback", type=str,
help="Username", callback=self._parse_username)
- self.add_option("-W", "--workgroup", metavar="WORKGROUP",
+ self.add_option("-W", "--workgroup", metavar="WORKGROUP",
action="callback", type=str,
help="Workgroup", callback=self._parse_workgroup)
self.add_option("-N", "--no-pass", action="store_true",
help="Don't ask for a password")
- self.add_option("-k", "--kerberos", metavar="KERBEROS",
+ self.add_option("-k", "--kerberos", metavar="KERBEROS",
action="callback", type=str,
help="Use Kerberos", callback=self._set_kerberos)
self.creds = Credentials()
diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py
new file mode 100644
index 0000000000..a204ab897b
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/__init__.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
+#
+# 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 optparse
+from samba import getopt as options, Ldb
+import sys
+
+
+class Option(optparse.Option):
+ pass
+
+
+class Command(object):
+ """A net command."""
+
+ def _get_description(self):
+ return self.__doc__.splitlines()[0].rstrip("\n")
+
+ def _get_name(self):
+ name = self.__class__.__name__
+ if name.startswith("cmd_"):
+ return name[4:]
+ return name
+
+ name = property(_get_name)
+
+ def usage(self, *args):
+ parser, _ = self._create_parser()
+ parser.print_usage()
+
+ description = property(_get_description)
+
+ def _get_synopsis(self):
+ ret = self.name
+ if self.takes_args:
+ ret += " " + " ".join([x.upper() for x in self.takes_args])
+ return ret
+
+ synopsis = property(_get_synopsis)
+
+ takes_args = []
+ takes_options = []
+ takes_optiongroups = {}
+
+ def _create_parser(self):
+ parser = optparse.OptionParser(self.synopsis)
+ parser.prog = "net"
+ parser.add_options(self.takes_options)
+ optiongroups = {}
+ for name, optiongroup in self.takes_optiongroups.iteritems():
+ optiongroups[name] = optiongroup(parser)
+ parser.add_option_group(optiongroups[name])
+ return parser, optiongroups
+
+ def message(self, text):
+ print text
+
+ def _run(self, *argv):
+ parser, optiongroups = self._create_parser()
+ opts, args = parser.parse_args(list(argv))
+ # Filter out options from option groups
+ args = args[1:]
+ kwargs = dict(opts.__dict__)
+ for option_group in parser.option_groups:
+ for option in option_group.option_list:
+ del kwargs[option.dest]
+ kwargs.update(optiongroups)
+ min_args = 0
+ max_args = 0
+ for i, arg in enumerate(self.takes_args):
+ if arg[-1] not in ("?", "*"):
+ min_args += 1
+ max_args += 1
+ if arg[-1] == "*":
+ max_args = -1
+ if len(args) < min_args or (max_args != -1 and len(args) > max_args):
+ self.usage(*args)
+ return -1
+ try:
+ return self.run(*args, **kwargs)
+ except CommandError, e:
+ print >>sys.stderr, "ERROR: %s" % e
+ return -1
+
+ def run(self):
+ """Run the command. This should be overriden by all subclasses."""
+ raise NotImplementedError(self.run)
+
+
+class SuperCommand(Command):
+ """A command with subcommands."""
+
+ subcommands = {}
+
+ def _run(self, myname, subcommand=None, *args):
+ if subcommand is None:
+ print "Available subcommands:"
+ for subcommand in self.subcommands:
+ print "\t%s" % subcommand
+ return 0
+ if not subcommand in self.subcommands:
+ raise CommandError("No such subcommand '%s'" % subcommand)
+ return self.subcommands[subcommand]._run(subcommand, *args)
+
+ def usage(self, myname, subcommand=None, *args):
+ if subcommand is None or not subcommand in self.subcommands:
+ print "Usage: %s (%s) [options]" % (myname,
+ " | ".join(self.subcommands.keys()))
+ else:
+ return self.subcommands[subcommand].usage(*args)
+
+
+class CommandError(Exception):
+ pass
+
+
+commands = {}
+from samba.netcmd.pwsettings import cmd_pwsettings
+commands["pwsettings"] = cmd_pwsettings()
+from samba.netcmd.domainlevel import cmd_domainlevel
+commands["domainlevel"] = cmd_domainlevel()
+from samba.netcmd.setpassword import cmd_setpassword
+commands["setpassword"] = cmd_setpassword()
+from samba.netcmd.setexpiry import cmd_setexpiry
+commands["setexpiry"] = cmd_setexpiry()
+from samba.netcmd.enableaccount import cmd_enableaccount
+commands["enableaccount"] = cmd_enableaccount()
+from samba.netcmd.newuser import cmd_newuser
+commands["newuser"] = cmd_newuser()
diff --git a/source4/scripting/python/samba/netcmd/domainlevel.py b/source4/scripting/python/samba/netcmd/domainlevel.py
new file mode 100644
index 0000000000..1c12bde0c6
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/domainlevel.py
@@ -0,0 +1,229 @@
+#!/usr/bin/python
+#
+# Raises domain and forest function levels
+#
+# Copyright Matthias Dieter Wallnoefer 2009
+# Copyright Jelmer Vernooij 2009
+#
+# 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/>.
+#
+
+# Notice: At the moment we have some more checks to do here on the special
+# attributes (consider attribute "msDS-Behavior-Version). This is due to the
+# fact that we on s4 LDB don't implement their change policy (only certain
+# values, only increments possible...) yet.
+
+import samba.getopt as options
+import ldb
+
+from samba.auth import system_session
+from samba.netcmd import (
+ Command,
+ CommandError,
+ Option,
+ )
+from samba.samdb import SamDB
+from samba import (
+ DS_DOMAIN_FUNCTION_2000,
+ DS_DOMAIN_FUNCTION_2003,
+ DS_DOMAIN_FUNCTION_2003_MIXED,
+ DS_DOMAIN_FUNCTION_2008,
+ DS_DOMAIN_FUNCTION_2008_R2,
+ DS_DC_FUNCTION_2000,
+ DS_DC_FUNCTION_2003,
+ DS_DC_FUNCTION_2008,
+ DS_DC_FUNCTION_2008_R2,
+ )
+
+class cmd_domainlevel(Command):
+ """Raises domain and forest function levels."""
+
+ synopsis = "(show | raise <options>)"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "versionopts": options.VersionOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--quiet", help="Be quiet", action="store_true"),
+ Option("--forest", type="choice", choices=["2003", "2008", "2008_R2"],
+ help="The forest function level (2003 | 2008 | 2008_R2)"),
+ Option("--domain", type="choice", choices=["2003", "2008", "2008_R2"],
+ help="The domain function level (2003 | 2008 | 2008_R2)"),
+ ]
+
+ takes_args = ["subcommand"]
+
+ def run(self, subcommand, H=None, forest=None, domain=None, quiet=False,
+ credopts=None, sambaopts=None, versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ domain_dn = SamDB.domain_dn(samdb)
+
+ res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
+ scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
+ assert(len(res_forest) == 1)
+
+ res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
+ attrs=["msDS-Behavior-Version", "nTMixedDomain"])
+ assert(len(res_domain) == 1)
+
+ res_dc_s = samdb.search("CN=Sites,CN=Configuration," + domain_dn,
+ scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)",
+ attrs=["msDS-Behavior-Version"])
+ assert(len(res_dc_s) >= 1)
+
+ try:
+ level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
+ level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
+ level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
+
+ min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value
+ for msg in res_dc_s:
+ if int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
+ min_level_dc = int(msg["msDS-Behavior-Version"][0])
+
+ if level_forest < 0 or level_domain < 0:
+ raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!")
+ if min_level_dc < 0:
+ raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!")
+ if level_forest > level_domain:
+ raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!")
+ if level_domain > min_level_dc:
+ raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!")
+
+ except KeyError:
+ raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!")
+
+ if subcommand == "show":
+ self.message("Domain and forest function level for domain '" + domain_dn + "'")
+ if level_forest < DS_DOMAIN_FUNCTION_2003:
+ self.message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2003 (Native). This isn't supported! Please raise!")
+ if level_domain < DS_DOMAIN_FUNCTION_2003:
+ self.message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2003 (Native). This isn't supported! Please raise!")
+ if min_level_dc < DS_DC_FUNCTION_2003:
+ self.message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!")
+
+ self.message("")
+
+ if level_forest == DS_DOMAIN_FUNCTION_2000:
+ outstr = "2000"
+ elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
+ outstr = "2003 with mixed domains/interim (NT4 DC support)"
+ elif level_forest == DS_DOMAIN_FUNCTION_2003:
+ outstr = "2003"
+ elif level_forest == DS_DOMAIN_FUNCTION_2008:
+ outstr = "2008"
+ elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
+ outstr = "2008 R2"
+ else:
+ outstr = "higher than 2008 R2"
+ self.message("Forest function level: (Windows) " + outstr)
+
+ if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
+ outstr = "2000 mixed (NT4 DC support)"
+ elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0:
+ outstr = "2000"
+ elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
+ outstr = "2003 with mixed domains/interim (NT4 DC support)"
+ elif level_domain == DS_DOMAIN_FUNCTION_2003:
+ outstr = "2003"
+ elif level_domain == DS_DOMAIN_FUNCTION_2008:
+ outstr = "2008"
+ elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
+ outstr = "2008 R2"
+ else:
+ outstr = "higher than 2008 R2"
+ self.message("Domain function level: (Windows) " + outstr)
+
+ if min_level_dc == DS_DC_FUNCTION_2000:
+ outstr = "2000"
+ elif min_level_dc == DS_DC_FUNCTION_2003:
+ outstr = "2003"
+ elif min_level_dc == DS_DC_FUNCTION_2008:
+ outstr = "2008"
+ elif min_level_dc == DS_DC_FUNCTION_2008_R2:
+ outstr = "2008 R2"
+ else:
+ outstr = "higher than 2008 R2"
+ self.message("Lowest function level of a DC: (Windows) " + outstr)
+
+ elif subcommand == "raise":
+ msgs = []
+
+ if domain is not None:
+ if domain == "2003":
+ new_level_domain = DS_DOMAIN_FUNCTION_2003
+ elif domain == "2008":
+ new_level_domain = DS_DOMAIN_FUNCTION_2008
+ elif domain == "2008_R2":
+ new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
+
+ if new_level_domain <= level_domain and level_domain_mixed == 0:
+ raise CommandError("Domain function level can't be smaller equal to the actual one!")
+
+ if new_level_domain > min_level_dc:
+ raise CommandError("Domain function level can't be higher than the lowest function level of a DC!")
+
+ # Deactivate mixed/interim domain support
+ if level_domain_mixed != 0:
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, domain_dn)
+ m["nTMixedDomain"] = ldb.MessageElement("0",
+ ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
+ samdb.modify(m)
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, domain_dn)
+ m["msDS-Behavior-Version"]= ldb.MessageElement(
+ str(new_level_domain), ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version")
+ samdb.modify(m)
+ level_domain = new_level_domain
+ msgs.append("Domain function level changed!")
+
+ if forest is not None:
+ if forest == "2003":
+ new_level_forest = DS_DOMAIN_FUNCTION_2003
+ elif forest == "2008":
+ new_level_forest = DS_DOMAIN_FUNCTION_2008
+ elif forest == "2008_R2":
+ new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
+ if new_level_forest <= level_forest:
+ raise CommandError("Forest function level can't be smaller equal to the actual one!")
+ if new_level_forest > level_domain:
+ raise CommandError("Forest function level can't be higher than the domain function level(s). Please raise it/them first!")
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
+ + domain_dn)
+ m["msDS-Behavior-Version"]= ldb.MessageElement(
+ str(new_level_forest), ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version")
+ samdb.modify(m)
+ msgs.append("Forest function level changed!")
+ msgs.append("All changes applied successfully!")
+ self.message("\n".join(msgs))
+ else:
+ raise CommandError("Wrong argument '%s'!" % subcommand)
diff --git a/source4/scripting/python/samba/netcmd/enableaccount.py b/source4/scripting/python/samba/netcmd/enableaccount.py
new file mode 100755
index 0000000000..d4af0a84f1
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/enableaccount.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+#
+# Enables an user account on a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 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/>.
+#
+
+import samba.getopt as options
+
+from samba.auth import system_session
+from samba.netcmd import Command, CommandError, Option
+from samba.samdb import SamDB
+
+class cmd_enableaccount(Command):
+ """Enable an account."""
+
+ synopsis = "enableaccount [username] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--filter", help="LDAP Filter to set password on", type=str),
+ ]
+
+ takes_args = ["username?"]
+
+ def run(self, username=None, sambaopts=None, credopts=None,
+ versionopts=None, filter=None, H=None):
+ if username is None and filter is None:
+ raise CommandError("Either the username or '--filter' must be specified!")
+
+ if filter is None:
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(),
+ credentials=creds, lp=lp)
+ samdb.enable_account(filter)
diff --git a/source4/scripting/python/samba/netcmd/newuser.py b/source4/scripting/python/samba/netcmd/newuser.py
new file mode 100755
index 0000000000..651313a345
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/newuser.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+#
+# Adds a new user to a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 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/>.
+
+import samba.getopt as options
+from samba.netcmd import Command, CommandError, Option
+
+from getpass import getpass
+from samba.auth import system_session
+from samba.samdb import SamDB
+
+class cmd_newuser(Command):
+ """Create a new user."""
+
+ synopsis = "newuser [options] <username> [<password>]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--unixname", help="Unix Username", type=str),
+ Option("--must-change-at-next-login",
+ help="Force password to be changed on next login",
+ action="store_true"),
+ ]
+
+ takes_args = ["username", "password?"]
+
+ def run(self, username, password=None, credopts=None, sambaopts=None,
+ versionopts=None, H=None, unixname=None,
+ must_change_at_next_login=None):
+ if password is None:
+ password = getpass("New Password: ")
+
+ if unixname is None:
+ unixname = username
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(), credentials=creds,
+ lp=lp)
+ samdb.newuser(username, unixname, password,
+ force_password_change_at_next_login_req=must_change_at_next_login)
diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py
new file mode 100644
index 0000000000..30f6f20d68
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/pwsettings.py
@@ -0,0 +1,190 @@
+#!/usr/bin/python
+#
+# Sets password settings.
+# (Password complexity, history length, minimum password length, the minimum
+# and maximum password age) on a Samba4 server
+#
+# Copyright Matthias Dieter Wallnoefer 2009
+# Copyright Andrew Kroeger 2009
+# Copyright Jelmer Vernooij 2009
+#
+# 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 samba.getopt as options
+import optparse
+import ldb
+
+from samba.auth import system_session
+from samba.samdb import SamDB
+from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX
+from samba.netcmd import Command, CommandError, Option
+
+class cmd_pwsettings(Command):
+ """Sets password settings.
+
+ Password complexity, history length, minimum password length, the minimum
+ and maximum password age) on a Samba4 server.
+ """
+
+ synopsis = "(show | set <options>)"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--quiet", help="Be quiet", action="store_true"),
+ Option("--complexity", type="choice", choices=["on","off","default"],
+ help="The password complexity (on | off | default). Default is 'on'"),
+ Option("--history-length",
+ help="The password history length (<integer> | default). Default is 24.", type=str),
+ Option("--min-pwd-length",
+ help="The minimum password length (<integer> | default). Default is 7.", type=str),
+ Option("--min-pwd-age",
+ help="The minimum password age (<integer in days> | default). Default is 0.", type=str),
+ Option("--max-pwd-age",
+ help="The maximum password age (<integer in days> | default). Default is 43.", type=str),
+ ]
+
+ takes_args = ["subcommand"]
+
+ def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None,
+ quiet=False, complexity=None, history_length=None,
+ min_pwd_length=None, credopts=None, sambaopts=None,
+ versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ domain_dn = SamDB.domain_dn(samdb)
+ res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
+ attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
+ "minPwdAge", "maxPwdAge"])
+ assert(len(res) == 1)
+ try:
+ pwd_props = int(res[0]["pwdProperties"][0])
+ pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
+ cur_min_pwd_len = int(res[0]["minPwdLength"][0])
+ # ticks -> days
+ cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
+ cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
+ except KeyError:
+ raise CommandError("Could not retrieve password properties!")
+
+ if subcommand == "show":
+ self.message("Password informations for domain '%s'" % domain_dn)
+ self.message("")
+ if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
+ self.message("Password complexity: on")
+ else:
+ self.message("Password complexity: off")
+ self.message("Password history length: %d" % pwd_hist_len)
+ self.message("Minimum password length: %d" % cur_min_pwd_len)
+ self.message("Minimum password age (days): %d" % cur_min_pwd_age)
+ self.message("Maximum password age (days): %d" % cur_max_pwd_age)
+ elif subcommand == "set":
+ msgs = []
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, domain_dn)
+
+ if complexity is not None:
+ if complexity == "on" or complexity == "default":
+ pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
+ msgs.append("Password complexity activated!")
+ elif complexity == "off":
+ pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
+ msgs.append("Password complexity deactivated!")
+
+ m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
+ ldb.FLAG_MOD_REPLACE, "pwdProperties")
+
+ if history_length is not None:
+ if history_length == "default":
+ pwd_hist_len = 24
+ else:
+ pwd_hist_len = int(history_length)
+
+ if pwd_hist_len < 0 or pwd_hist_len > 24:
+ raise CommandError("Password history length must be in the range of 0 to 24!")
+
+ m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
+ ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
+ msgs.append("Password history length changed!")
+
+ if min_pwd_length is not None:
+ if min_pwd_length == "default":
+ min_pwd_len = 7
+ else:
+ min_pwd_len = int(min_pwd_length)
+
+ if min_pwd_len < 0 or min_pwd_len > 14:
+ raise CommandError("Minimum password length must be in the range of 0 to 14!")
+
+ m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
+ ldb.FLAG_MOD_REPLACE, "minPwdLength")
+ msgs.append("Minimum password length changed!")
+
+ if min_pwd_age is not None:
+ if min_pwd_age == "default":
+ min_pwd_age = 0
+ else:
+ min_pwd_age = int(min_pwd_age)
+
+ if min_pwd_age < 0 or min_pwd_age > 998:
+ raise CommandError("Minimum password age must be in the range of 0 to 998!")
+
+ # days -> ticks
+ min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
+
+ m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
+ ldb.FLAG_MOD_REPLACE, "minPwdAge")
+ msgs.append("Minimum password age changed!")
+
+ if max_pwd_age is not None:
+ if max_pwd_age == "default":
+ max_pwd_age = 43
+ else:
+ max_pwd_age = int(max_pwd_age)
+
+ if max_pwd_age < 0 or max_pwd_age > 999:
+ raise CommandError("Maximum password age must be in the range of 0 to 999!")
+
+ # days -> ticks
+ max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
+
+ m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
+ ldb.FLAG_MOD_REPLACE, "maxPwdAge")
+ msgs.append("Maximum password age changed!")
+
+ if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
+ raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
+
+ samdb.modify(m)
+ msgs.append("All changes applied successfully!")
+ self.message("\n".join(msgs))
+ else:
+ raise CommandError("Wrong argument '%s'!" % subcommand)
diff --git a/source4/scripting/python/samba/netcmd/setexpiry.py b/source4/scripting/python/samba/netcmd/setexpiry.py
new file mode 100644
index 0000000000..0c5dc5afff
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/setexpiry.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+#
+# Sets the user password expiry on a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 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/>.
+#
+
+from samba.netcmd import Command, CommandError, Option
+
+import samba.getopt as options
+
+from samba.auth import system_session
+from samba.samdb import SamDB
+
+class cmd_setexpiry(Command):
+ """Set the expiration of a user account."""
+
+ synopsis = "setexpiry [username] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--filter", help="LDAP Filter to set password on", type=str),
+ Option("--days", help="Days to expiry", type=int),
+ Option("--noexpiry", help="Password does never expire", action="store_true"),
+ ]
+
+ takes_args = ["username?"]
+
+ def run(self, username=None, sambaopts=None, credopts=None,
+ versionopts=None, H=None, filter=None, days=None, noexpiry=None):
+ if username is None and filter is None:
+ raise CommandError("Either the username or '--filter' must be specified!")
+
+ if filter is None:
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if days is None:
+ days = 0
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
diff --git a/source4/scripting/python/samba/netcmd/setpassword.py b/source4/scripting/python/samba/netcmd/setpassword.py
new file mode 100644
index 0000000000..6393e47414
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/setpassword.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+#
+# Sets a user password on a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 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/>.
+#
+
+import samba.getopt as options
+from samba.netcmd import Command, CommandError, Option
+
+from getpass import getpass
+from samba.auth import system_session
+from samba.samdb import SamDB
+
+class cmd_setpassword(Command):
+ """Change the password of a user."""
+
+ synopsis = "setpassword [username] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", help="LDB URL for database or target server", type=str),
+ Option("--filter", help="LDAP Filter to set password on", type=str),
+ Option("--newpassword", help="Set password", type=str),
+ Option("--must-change-at-next-login",
+ help="Force password to be changed on next login",
+ action="store_true"),
+ ]
+
+ takes_args = ["username?"]
+
+ def run(self, username=None, filter=None, credopts=None, sambaopts=None,
+ versionopts=None, H=None, newpassword=None,
+ must_change_at_next_login=None):
+ if filter is None and username is None:
+ raise CommandError("Either the username or '--filter' must be specified!")
+
+ password = newpassword
+ if password is None:
+ password = getpass("New Password: ")
+
+ if filter is None:
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if H is not None:
+ url = H
+ else:
+ url = lp.get("sam database")
+
+ samdb = SamDB(url=url, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ samdb.setpassword(filter, password,
+ force_password_change_at_next_login_req=must_change_at_next_login)
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
index 3e4e90a746..d7d0a790ca 100644
--- a/source4/scripting/python/samba/provision.py
+++ b/source4/scripting/python/samba/provision.py
@@ -894,6 +894,8 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp,
samdb.set_domain_sid(str(domainsid))
if serverrole == "domain controller":
samdb.set_invocation_id(invocationid)
+ # NOTE: the invocationid for standalone and member server
+ # cases is setup in the sambd_dsdb module init function
message("Adding DomainDN: %s" % names.domaindn)
diff --git a/source4/scripting/python/samba/tests/netcmd.py b/source4/scripting/python/samba/tests/netcmd.py
new file mode 100644
index 0000000000..ecd8dc439e
--- /dev/null
+++ b/source4/scripting/python/samba/tests/netcmd.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
+#
+# 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 unittest
+
+from samba.netcmd import Command
+
+class CommandTests(unittest.TestCase):
+
+ def test_name(self):
+ class cmd_foo(Command):
+ pass
+ self.assertEquals("foo", cmd_foo().name)
+
+ def test_description(self):
+ class cmd_foo(Command):
+ """Mydescription"""
+ self.assertEquals("Mydescription", cmd_foo().description)
diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh
index 73209efefe..cad97b7ad3 100755
--- a/source4/selftest/tests.sh
+++ b/source4/selftest/tests.sh
@@ -450,6 +450,7 @@ plantest "samba.python" none $SUBUNITRUN samba.tests
plantest "provision.python" none $SUBUNITRUN samba.tests.provision
plantest "samba3.python" none $SUBUNITRUN samba.tests.samba3
plantest "samr.python" dc:local $SUBUNITRUN samba.tests.dcerpc.sam
+plantest "netcmd.python" none $SUBUNITRUN samba.tests.netcmd
plantest "dcerpc.bare.python" dc:local $SUBUNITRUN samba.tests.dcerpc.bare
plantest "unixinfo.python" dc:local $SUBUNITRUN samba.tests.dcerpc.unix
plantest "samdb.python" none $SUBUNITRUN samba.tests.samdb
@@ -460,6 +461,7 @@ plantest "subunit.python" none $SUBUNITRUN subunit
plantest "rpcecho.python" dc:local $SUBUNITRUN samba.tests.dcerpc.rpcecho
plantest "winreg.python" dc:local $SUBUNITRUN -U\$USERNAME%\$PASSWORD samba.tests.dcerpc.registry
plantest "ldap.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/ldap.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN
+plantest "ldap_schema.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/ldap_schema.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN
plantest "ldap.possibleInferiors.python" dc $PYTHON $samba4srcdir/dsdb/samdb/ldb_modules/tests/possibleinferiors.py $CONFIGURATION ldap://\$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN
plantest "ldap.secdesc.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/sec_descriptor.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN
plantest "ldap.acl.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/acl.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN
diff --git a/source4/setup/domainlevel b/source4/setup/domainlevel
deleted file mode 100755
index c37d811dd8..0000000000
--- a/source4/setup/domainlevel
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/python
-#
-# Raises domain and forest function levels
-#
-# Copyright Matthias Dieter Wallnoefer 2009
-#
-# 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/>.
-#
-
-# Notice: At the moment we have some more checks to do here on the special
-# attributes (consider attribute "msDS-Behavior-Version). This is due to the
-# fact that we on s4 LDB don't implement their change policy (only certain
-# values, only increments possible...) yet.
-
-import sys
-
-# Find right directory when running from source tree
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-import ldb
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003
-from samba import DS_DOMAIN_FUNCTION_2003_MIXED, DS_DOMAIN_FUNCTION_2008
-from samba import DS_DOMAIN_FUNCTION_2008_R2
-from samba import DS_DC_FUNCTION_2000, DS_DC_FUNCTION_2003, DS_DC_FUNCTION_2008
-from samba import DS_DC_FUNCTION_2008_R2
-
-parser = optparse.OptionParser("domainlevel (show | raise <options>)")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--quiet", help="Be quiet", action="store_true")
-parser.add_option("--forest", type="choice",
- choices=["2003", "2008", "2008_R2"],
- help="The forest function level (2003 | 2008 | 2008_R2)")
-parser.add_option("--domain", type="choice",
- choices=["2003", "2008", "2008_R2"],
- help="The domain function level (2003 | 2008 | 2008_R2)")
-opts, args = parser.parse_args()
-
-#
-# print a message if quiet is not set
-#
-def message(text):
- if not opts.quiet:
- print text
-
-if len(args) == 0:
- parser.print_usage()
- sys.exit(1)
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-domain_dn = SamDB.domain_dn(samdb)
-
-res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
- scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
-assert(len(res_forest) == 1)
-
-res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
- attrs=["msDS-Behavior-Version", "nTMixedDomain"])
-assert(len(res_domain) == 1)
-
-res_dc_s = samdb.search("CN=Sites,CN=Configuration," + domain_dn,
- scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)",
- attrs=["msDS-Behavior-Version"])
-assert(len(res_dc_s) >= 1)
-
-try:
- level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
- level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
- level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
-
- min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value
- for msg in res_dc_s:
- if int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
- min_level_dc = int(msg["msDS-Behavior-Version"][0])
-
- if level_forest < 0 or level_domain < 0:
- print >>sys.stderr, "ERROR: Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!"
- sys.exit(1)
- if min_level_dc < 0:
- print >>sys.stderr, "ERROR: Lowest function level of a DC is invalid. Correct this or reprovision!"
- sys.exit(1)
- if level_forest > level_domain:
- print >>sys.stderr, "ERROR: Forest function level is higher than the domain level(s). Correct this or reprovision!"
- sys.exit(1)
- if level_domain > min_level_dc:
- print >>sys.stderr, "ERROR: Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!"
- sys.exit(1)
-
-except KeyError:
- print >>sys.stderr, "ERROR: Could not retrieve the actual domain, forest level and/or lowest DC function level!"
- if args[0] == "show":
- print >>sys.stderr, "So the levels can't be displayed!"
- sys.exit(1)
-
-if args[0] == "show":
- message("Domain and forest function level for domain '" + domain_dn + "'")
- if level_forest < DS_DOMAIN_FUNCTION_2003:
- message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2003 (Native). This isn't supported! Please raise!")
- if level_domain < DS_DOMAIN_FUNCTION_2003:
- message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2003 (Native). This isn't supported! Please raise!")
- if min_level_dc < DS_DC_FUNCTION_2003:
- message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!")
-
- message("")
-
- if level_forest == DS_DOMAIN_FUNCTION_2000:
- outstr = "2000"
- elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
- outstr = "2003 with mixed domains/interim (NT4 DC support)"
- elif level_forest == DS_DOMAIN_FUNCTION_2003:
- outstr = "2003"
- elif level_forest == DS_DOMAIN_FUNCTION_2008:
- outstr = "2008"
- elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- message("Forest function level: (Windows) " + outstr)
-
- if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
- outstr = "2000 mixed (NT4 DC support)"
- elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0:
- outstr = "2000"
- elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
- outstr = "2003 with mixed domains/interim (NT4 DC support)"
- elif level_domain == DS_DOMAIN_FUNCTION_2003:
- outstr = "2003"
- elif level_domain == DS_DOMAIN_FUNCTION_2008:
- outstr = "2008"
- elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- message("Domain function level: (Windows) " + outstr)
-
- if min_level_dc == DS_DC_FUNCTION_2000:
- outstr = "2000"
- elif min_level_dc == DS_DC_FUNCTION_2003:
- outstr = "2003"
- elif min_level_dc == DS_DC_FUNCTION_2008:
- outstr = "2008"
- elif min_level_dc == DS_DC_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- message("Lowest function level of a DC: (Windows) " + outstr)
-
-elif args[0] == "raise":
- msgs = []
-
- if opts.domain is not None:
- arg = opts.domain
-
- if arg == "2003":
- new_level_domain = DS_DOMAIN_FUNCTION_2003
- elif arg == "2008":
- new_level_domain = DS_DOMAIN_FUNCTION_2008
- elif arg == "2008_R2":
- new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
-
- if new_level_domain <= level_domain and level_domain_mixed == 0:
- print >>sys.stderr, "ERROR: Domain function level can't be smaller equal to the actual one!"
- sys.exit(1)
-
- if new_level_domain > min_level_dc:
- print >>sys.stderr, "ERROR: Domain function level can't be higher than the lowest function level of a DC!"
- sys.exit(1)
-
- # Deactivate mixed/interim domain support
- if level_domain_mixed != 0:
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
- m["nTMixedDomain"] = ldb.MessageElement("0",
- ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
- samdb.modify(m)
-
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
- m["msDS-Behavior-Version"]= ldb.MessageElement(
- str(new_level_domain), ldb.FLAG_MOD_REPLACE,
- "msDS-Behavior-Version")
- samdb.modify(m)
-
- level_domain = new_level_domain
-
- msgs.append("Domain function level changed!")
-
- if opts.forest is not None:
- arg = opts.forest
-
- if arg == "2003":
- new_level_forest = DS_DOMAIN_FUNCTION_2003
- elif arg == "2008":
- new_level_forest = DS_DOMAIN_FUNCTION_2008
- elif arg == "2008_R2":
- new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
-
- if new_level_forest <= level_forest:
- print >>sys.stderr, "ERROR: Forest function level can't be smaller equal to the actual one!"
- sys.exit(1)
-
- if new_level_forest > level_domain:
- print >>sys.stderr, "ERROR: Forest function level can't be higher than the domain function level(s). Please raise it/them first!"
- sys.exit(1)
-
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
- + domain_dn)
- m["msDS-Behavior-Version"]= ldb.MessageElement(
- str(new_level_forest), ldb.FLAG_MOD_REPLACE,
- "msDS-Behavior-Version")
- samdb.modify(m)
-
- msgs.append("Forest function level changed!")
-
- msgs.append("All changes applied successfully!")
-
- message("\n".join(msgs))
-else:
- print >>sys.stderr, "ERROR: Wrong argument '" + args[0] + "'!"
- sys.exit(1)
diff --git a/source4/setup/enableaccount b/source4/setup/enableaccount
deleted file mode 100755
index f8f727c1ee..0000000000
--- a/source4/setup/enableaccount
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/python
-#
-# Enables an user account on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 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/>.
-#
-
-import sys
-
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-parser = optparse.OptionParser("enableaccount [username] [options]")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--filter", help="LDAP Filter to set password on", type=str)
-
-opts, args = parser.parse_args()
-
-filter = opts.filter
-
-if (len(args) == 0) and (filter is None):
- print "Either the username or '--filter' must be specified!"
- parser.print_usage()
- sys.exit(1)
-
-if filter is None:
- username = args[0]
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-samdb.enable_account(filter)
diff --git a/source4/setup/newuser b/source4/setup/newuser
deleted file mode 100755
index ef65d36dfb..0000000000
--- a/source4/setup/newuser
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/python
-#
-# Adds a new user to a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 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/>.
-
-import sys
-
-# Find right directory when running from source tree
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-
-from getpass import getpass
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-parser = optparse.OptionParser("newuser [options] <username> [<password>]")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--unixname", help="Unix Username", type=str)
-parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true")
-
-opts, args = parser.parse_args()
-
-if len(args) == 0:
- parser.print_usage()
- sys.exit(1)
-
-username = args[0]
-if len(args) > 1:
- password = args[1]
-else:
- password = getpass("New Password: ")
-
-if opts.unixname is None:
- opts.unixname = username
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-samdb.newuser(username, opts.unixname, password, force_password_change_at_next_login_req=opts.must_change_at_next_login)
diff --git a/source4/setup/pwsettings b/source4/setup/pwsettings
deleted file mode 100755
index 59ed5d29bf..0000000000
--- a/source4/setup/pwsettings
+++ /dev/null
@@ -1,198 +0,0 @@
-#!/usr/bin/python
-#
-# Sets password settings (Password complexity, history length, minimum password
-# length, the minimum and maximum password age) on a Samba4 server
-#
-# Copyright Matthias Dieter Wallnoefer 2009
-# Copyright Andrew Kroeger 2009
-#
-# 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
-
-# Find right directory when running from source tree
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-import ldb
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX
-
-parser = optparse.OptionParser("pwsettings (show | set <options>)")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--quiet", help="Be quiet", action="store_true")
-parser.add_option("--complexity", type="choice", choices=["on","off","default"],
- help="The password complexity (on | off | default). Default is 'on'")
-parser.add_option("--history-length",
- help="The password history length (<integer> | default). Default is 24.", type=str)
-parser.add_option("--min-pwd-length",
- help="The minimum password length (<integer> | default). Default is 7.", type=str)
-parser.add_option("--min-pwd-age",
- help="The minimum password age (<integer in days> | default). Default is 0.", type=str)
-parser.add_option("--max-pwd-age",
- help="The maximum password age (<integer in days> | default). Default is 43.", type=str)
-
-opts, args = parser.parse_args()
-
-#
-# print a message if quiet is not set
-#
-def message(text):
- if not opts.quiet:
- print text
-
-if len(args) == 0:
- parser.print_usage()
- sys.exit(1)
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-domain_dn = SamDB.domain_dn(samdb)
-res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
- attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", "minPwdAge",
- "maxPwdAge"])
-assert(len(res) == 1)
-try:
- pwd_props = int(res[0]["pwdProperties"][0])
- pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
- min_pwd_len = int(res[0]["minPwdLength"][0])
- # ticks -> days
- min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
- max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
-except KeyError:
- print >>sys.stderr, "ERROR: Could not retrieve password properties!"
- if args[0] == "show":
- print >>sys.stderr, "So no settings can be displayed!"
- sys.exit(1)
-
-if args[0] == "show":
- message("Password informations for domain '" + domain_dn + "'")
- message("")
- if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
- message("Password complexity: on")
- else:
- message("Password complexity: off")
- message("Password history length: " + str(pwd_hist_len))
- message("Minimum password length: " + str(min_pwd_len))
- message("Minimum password age (days): " + str(min_pwd_age))
- message("Maximum password age (days): " + str(max_pwd_age))
-
-elif args[0] == "set":
-
- msgs = []
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
-
- if opts.complexity is not None:
- if opts.complexity == "on" or opts.complexity == "default":
- pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
- msgs.append("Password complexity activated!")
- elif opts.complexity == "off":
- pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
- msgs.append("Password complexity deactivated!")
-
- m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
- ldb.FLAG_MOD_REPLACE, "pwdProperties")
-
- if opts.history_length is not None:
- if opts.history_length == "default":
- pwd_hist_len = 24
- else:
- pwd_hist_len = int(opts.history_length)
-
- if pwd_hist_len < 0 or pwd_hist_len > 24:
- print >>sys.stderr, "ERROR: Password history length must be in the range of 0 to 24!"
- sys.exit(1)
-
- m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
- ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
- msgs.append("Password history length changed!")
-
- if opts.min_pwd_length is not None:
- if opts.min_pwd_length == "default":
- min_pwd_len = 7
- else:
- min_pwd_len = int(opts.min_pwd_length)
-
- if min_pwd_len < 0 or min_pwd_len > 14:
- print >>sys.stderr, "ERROR: Minimum password length must be in the range of 0 to 14!"
- sys.exit(1)
-
- m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
- ldb.FLAG_MOD_REPLACE, "minPwdLength")
- msgs.append("Minimum password length changed!")
-
- if opts.min_pwd_age is not None:
- if opts.min_pwd_age == "default":
- min_pwd_age = 0
- else:
- min_pwd_age = int(opts.min_pwd_age)
-
- if min_pwd_age < 0 or min_pwd_age > 998:
- print >>sys.stderr, "ERROR: Minimum password age must be in the range of 0 to 998!"
- sys.exit(1)
-
- # days -> ticks
- min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
-
- m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "minPwdAge")
- msgs.append("Minimum password age changed!")
-
- if opts.max_pwd_age is not None:
- if opts.max_pwd_age == "default":
- max_pwd_age = 43
- else:
- max_pwd_age = int(opts.max_pwd_age)
-
- if max_pwd_age < 0 or max_pwd_age > 999:
- print >>sys.stderr, "ERROR: Maximum password age must be in the range of 0 to 999!"
- sys.exit(1)
-
- # days -> ticks
- max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
-
- m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "maxPwdAge")
- msgs.append("Maximum password age changed!")
-
- if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
- print "ERROR: Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age)
- sys.exit(1)
-
- samdb.modify(m)
-
- msgs.append("All changes applied successfully!")
-
- message("\n".join(msgs))
-else:
- print >>sys.stderr, "ERROR: Wrong argument '" + args[0] + "'!"
- sys.exit(1)
diff --git a/source4/setup/setexpiry b/source4/setup/setexpiry
deleted file mode 100755
index 2740326f2b..0000000000
--- a/source4/setup/setexpiry
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/python
-#
-# Sets the user password expiry on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 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/>.
-#
-
-import sys
-
-# Find right directory when running from source tree
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-parser = optparse.OptionParser("setexpiry [username] [options]")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--filter", help="LDAP Filter to set password on", type=str)
-parser.add_option("--days", help="Days to expiry", type=int)
-parser.add_option("--noexpiry", help="Password does never expire", action="store_true")
-
-opts, args = parser.parse_args()
-
-filter = opts.filter
-
-if (len(args) == 0) and (filter is None):
- print "Either the username or '--filter' must be specified!"
- parser.print_usage()
- sys.exit(1)
-
-days = opts.days
-if days is None:
- days = 0
-
-if filter is None:
- username = args[0]
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-samdb.setexpiry(filter, days*24*3600, no_expiry_req=opts.noexpiry)
diff --git a/source4/setup/setpassword b/source4/setup/setpassword
deleted file mode 100755
index 57772be7a7..0000000000
--- a/source4/setup/setpassword
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/python
-#
-# Sets a user password on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 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/>.
-#
-
-import sys
-
-# Find right directory when running from source tree
-sys.path.insert(0, "bin/python")
-
-import samba.getopt as options
-import optparse
-
-from getpass import getpass
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-parser = optparse.OptionParser("setpassword [username] [options]")
-sambaopts = options.SambaOptions(parser)
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-credopts = options.CredentialsOptions(parser)
-parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--filter", help="LDAP Filter to set password on", type=str)
-parser.add_option("--newpassword", help="Set password", type=str)
-parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true")
-
-opts, args = parser.parse_args()
-
-filter = opts.filter
-
-if (len(args) == 0) and (filter is None):
- print "Either the username or '--filter' must be specified!"
- parser.print_usage()
- sys.exit(1)
-
-password = opts.newpassword;
-if password is None:
- password = getpass("New Password: ")
-
-if filter is None:
- username = args[0]
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
-lp = sambaopts.get_loadparm()
-creds = credopts.get_credentials(lp)
-
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp)
-
-samdb.setpassword(filter, password, force_password_change_at_next_login_req=opts.must_change_at_next_login)
-
diff --git a/source4/setup/tests/blackbox_newuser.sh b/source4/setup/tests/blackbox_newuser.sh
index d25c70669b..30e6830be5 100755
--- a/source4/setup/tests/blackbox_newuser.sh
+++ b/source4/setup/tests/blackbox_newuser.sh
@@ -14,19 +14,20 @@ shift 1
testit "simple-dc" $PYTHON ./setup/provision --server-role="dc" --domain=FOO --realm=foo.example.com --domain-sid=S-1-5-21-4177067393-1453636373-93818738 --targetdir=$PREFIX/simple-dc
+net="./bin/net"
CONFIG="--configfile=$PREFIX/simple-dc/etc/smb.conf"
-testit "newuser" $PYTHON ./setup/newuser $CONFIG testuser testpass
+testit "newuser" $net newuser $CONFIG testuser testpass
# check the enable account script
-testit "enableaccount" $PYTHON ./setup/enableaccount $CONFIG testuser
+testit "enableaccount" $net enableaccount $CONFIG testuser
# check the enable account script
-testit "setpassword" $PYTHON ./setup/setpassword $CONFIG testuser --newpassword=testpass2
+testit "setpassword" $net setpassword $CONFIG testuser --newpassword=testpass2
# check the setexpiry script
-testit "noexpiry" $PYTHON ./setup/setexpiry $CONFIG testuser --noexpiry
-testit "expiry" $PYTHON ./setup/setexpiry $CONFIG testuser --days=7
+testit "noexpiry" $net setexpiry $CONFIG testuser --noexpiry
+testit "expiry" $net setexpiry $CONFIG testuser --days=7
exit $failed
diff --git a/source4/setup/tests/blackbox_setpassword.sh b/source4/setup/tests/blackbox_setpassword.sh
index 77b41a2424..9f8fa6d2c1 100755
--- a/source4/setup/tests/blackbox_setpassword.sh
+++ b/source4/setup/tests/blackbox_setpassword.sh
@@ -12,14 +12,16 @@ shift 1
. `dirname $0`/../../../testprogs/blackbox/subunit.sh
+net="./bin/net"
+
testit "simple-dc" $PYTHON ./setup/provision --server-role="dc" --domain=FOO --realm=foo.example.com --domain-sid=S-1-5-21-4177067393-1453636373-93818738 --targetdir=$PREFIX/simple-dc
-testit "newuser" $PYTHON ./setup/newuser --configfile=$PREFIX/simple-dc/etc/smb.conf testuser testpass
+testit "newuser" $net newuser --configfile=$PREFIX/simple-dc/etc/smb.conf testuser testpass
-testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass
+testit "setpassword" $net setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass
-testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass --must-change-at-next-login
+testit "setpassword" $net setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass --must-change-at-next-login
-testit "pwsettings" $PYTHON ./setup/pwsettings --quiet set --configfile=$PREFIX/simple-dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default
+testit "pwsettings" $net pwsettings --quiet set --configfile=$PREFIX/simple-dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default
exit $failed
diff --git a/source4/smb_server/smb/negprot.c b/source4/smb_server/smb/negprot.c
index ab763e39c3..fe6cd68f6e 100644
--- a/source4/smb_server/smb/negprot.c
+++ b/source4/smb_server/smb/negprot.c
@@ -33,7 +33,6 @@
static NTSTATUS get_challenge(struct smbsrv_connection *smb_conn, uint8_t buff[8])
{
NTSTATUS nt_status;
- const uint8_t *challenge;
/* muliple negprots are not premitted */
if (smb_conn->negotiate.auth_context) {
@@ -53,14 +52,12 @@ static NTSTATUS get_challenge(struct smbsrv_connection *smb_conn, uint8_t buff[8
return nt_status;
}
- nt_status = auth_get_challenge(smb_conn->negotiate.auth_context, &challenge);
+ nt_status = auth_get_challenge(smb_conn->negotiate.auth_context, buff);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("auth_get_challenge() returned %s", nt_errstr(nt_status)));
return nt_status;
}
- memcpy(buff, challenge, 8);
-
return NT_STATUS_OK;
}
diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c
index 37f69abc12..aecd49fb0b 100644
--- a/source4/smb_server/smb/sesssetup.c
+++ b/source4/smb_server/smb/sesssetup.c
@@ -23,12 +23,14 @@
*/
#include "includes.h"
+#include <tevent.h>
#include "version.h"
#include "auth/gensec/gensec.h"
#include "auth/auth.h"
#include "smb_server/smb_server.h"
#include "smbd/service_stream.h"
#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
/*
setup the OS, Lanman and domain portions of a session setup reply
@@ -54,17 +56,18 @@ static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
smbsrv_reply_sesssetup_send(req, sess, status);
}
-static void sesssetup_old_send(struct auth_check_password_request *areq,
- void *private_data)
+static void sesssetup_old_send(struct tevent_req *subreq)
{
- struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
+ struct smbsrv_request *req =
+ tevent_req_callback_data(subreq, struct smbsrv_request);
union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info;
struct smbsrv_session *smb_sess;
NTSTATUS status;
- status = auth_check_password_recv(areq, req, &server_info);
+ status = auth_check_password_recv(subreq, req, &server_info);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) goto failed;
/* This references server_info into session_info */
@@ -100,8 +103,9 @@ failed:
static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
{
struct auth_usersupplied_info *user_info = NULL;
- struct socket_address *remote_address;
+ struct tsocket_address *remote_address;
const char *remote_machine = NULL;
+ struct tevent_req *subreq;
sess->old.out.vuid = 0;
sess->old.out.action = 0;
@@ -119,11 +123,12 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
remote_machine = req->smb_conn->negotiate.calling_name->name;
}
- remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
+ remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
if (!remote_address) goto nomem;
if (!remote_machine) {
- remote_machine = remote_address->addr;
+ remote_machine = tsocket_address_inet_addr_string(remote_address, req);
+ if (!remote_machine) goto nomem;
}
user_info = talloc(req, struct auth_usersupplied_info);
@@ -142,25 +147,30 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
user_info->password.response.nt = data_blob(NULL, 0);
- auth_check_password_send(req->smb_conn->negotiate.auth_context, user_info,
- sesssetup_old_send, req);
+ subreq = auth_check_password_send(req,
+ req->smb_conn->connection->event.ctx,
+ req->smb_conn->negotiate.auth_context,
+ user_info);
+ if (!subreq) goto nomem;
+ tevent_req_set_callback(subreq, sesssetup_old_send, req);
return;
nomem:
smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
}
-static void sesssetup_nt1_send(struct auth_check_password_request *areq,
- void *private_data)
+static void sesssetup_nt1_send(struct tevent_req *subreq)
{
- struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
+ struct smbsrv_request *req =
+ tevent_req_callback_data(subreq, struct smbsrv_request);
union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info;
struct smbsrv_session *smb_sess;
NTSTATUS status;
- status = auth_check_password_recv(areq, req, &server_info);
+ status = auth_check_password_recv(subreq, req, &server_info);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) goto failed;
/* This references server_info into session_info */
@@ -206,9 +216,10 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
NTSTATUS status;
struct auth_context *auth_context;
struct auth_usersupplied_info *user_info = NULL;
- struct socket_address *remote_address;
+ struct tsocket_address *remote_address;
const char *remote_machine = NULL;
-
+ struct tevent_req *subreq;
+
sess->nt1.out.vuid = 0;
sess->nt1.out.action = 0;
@@ -245,11 +256,12 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
remote_machine = req->smb_conn->negotiate.calling_name->name;
}
- remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
+ remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
if (!remote_address) goto nomem;
if (!remote_machine) {
- remote_machine = remote_address->addr;
+ remote_machine = tsocket_address_inet_addr_string(remote_address, req);
+ if (!remote_machine) goto nomem;
}
user_info = talloc(req, struct auth_usersupplied_info);
@@ -269,8 +281,13 @@ 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);
- auth_check_password_send(auth_context, user_info,
- sesssetup_nt1_send, req);
+ subreq = auth_check_password_send(req,
+ req->smb_conn->connection->event.ctx,
+ auth_context,
+ user_info);
+ if (!subreq) goto nomem;
+ tevent_req_set_callback(subreq, sesssetup_nt1_send, req);
+
return;
nomem:
@@ -286,9 +303,9 @@ struct sesssetup_spnego_state {
struct smbsrv_session *smb_sess;
};
-static void sesssetup_spnego_send(struct gensec_update_request *greq, void *private_data)
+static void sesssetup_spnego_send(struct tevent_req *subreq)
{
- struct sesssetup_spnego_state *s = talloc_get_type(private_data,
+ struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq,
struct sesssetup_spnego_state);
struct smbsrv_request *req = s->req;
union smb_sesssetup *sess = s->sess;
@@ -298,7 +315,8 @@ static void sesssetup_spnego_send(struct gensec_update_request *greq, void *priv
NTSTATUS skey_status;
DATA_BLOB session_key;
- status = gensec_update_recv(greq, req, &sess->spnego.out.secblob);
+ status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob);
+ TALLOC_FREE(subreq);
if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
goto done;
} else if (!NT_STATUS_IS_OK(status)) {
@@ -340,6 +358,7 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se
struct smbsrv_session *smb_sess = NULL;
struct sesssetup_spnego_state *s = NULL;
uint16_t vuid;
+ struct tevent_req *subreq;
sess->spnego.out.vuid = 0;
sess->spnego.out.action = 0;
@@ -407,8 +426,15 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se
s->sess = sess;
s->smb_sess = smb_sess;
- gensec_update_send(smb_sess->gensec_ctx, sess->spnego.in.secblob,
- sesssetup_spnego_send, s);
+ subreq = gensec_update_send(s,
+ req->smb_conn->connection->event.ctx,
+ smb_sess->gensec_ctx,
+ sess->spnego.in.secblob);
+ if (!subreq) {
+ goto nomem;
+ }
+ tevent_req_set_callback(subreq, sesssetup_spnego_send, s);
+
return;
nomem:
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index 58090305a0..9b601d17c0 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include <tevent.h>
#include "auth/gensec/gensec.h"
#include "auth/auth.h"
#include "libcli/smb2/smb2.h"
@@ -57,9 +58,9 @@ struct smb2srv_sesssetup_callback_ctx {
struct smbsrv_session *smb_sess;
};
-static void smb2srv_sesssetup_callback(struct gensec_update_request *greq, void *private_data)
+static void smb2srv_sesssetup_callback(struct tevent_req *subreq)
{
- struct smb2srv_sesssetup_callback_ctx *ctx = talloc_get_type(private_data,
+ struct smb2srv_sesssetup_callback_ctx *ctx = tevent_req_callback_data(subreq,
struct smb2srv_sesssetup_callback_ctx);
struct smb2srv_request *req = ctx->req;
union smb_sesssetup *io = ctx->io;
@@ -67,7 +68,8 @@ static void smb2srv_sesssetup_callback(struct gensec_update_request *greq, void
struct auth_session_info *session_info = NULL;
NTSTATUS status;
- status = gensec_update_recv(greq, req, &io->smb2.out.secblob);
+ status = gensec_update_recv(subreq, req, &io->smb2.out.secblob);
+ TALLOC_FREE(subreq);
if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
goto done;
} else if (!NT_STATUS_IS_OK(status)) {
@@ -108,6 +110,7 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
struct smb2srv_sesssetup_callback_ctx *callback_ctx;
struct smbsrv_session *smb_sess = NULL;
uint64_t vuid;
+ struct tevent_req *subreq;
io->smb2.out.session_flags = 0;
io->smb2.out.uid = 0;
@@ -174,8 +177,12 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
callback_ctx->io = io;
callback_ctx->smb_sess = smb_sess;
- gensec_update_send(smb_sess->gensec_ctx, io->smb2.in.secblob,
- smb2srv_sesssetup_callback, callback_ctx);
+ subreq = gensec_update_send(callback_ctx,
+ req->smb_conn->connection->event.ctx,
+ smb_sess->gensec_ctx,
+ io->smb2.in.secblob);
+ if (!subreq) goto nomem;
+ tevent_req_set_callback(subreq, smb2srv_sesssetup_callback, callback_ctx);
/* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
This is deliberate as windows does not set it even when it does
diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk
index b85beb0bc0..a77a18602f 100644
--- a/source4/smbd/config.mk
+++ b/source4/smbd/config.mk
@@ -4,7 +4,7 @@
PRIVATE_DEPENDENCIES = \
LIBTEVENT MESSAGING samba_socket \
NDR_NAMED_PIPE_AUTH NAMED_PIPE_AUTH_TSTREAM \
- HEIMDAL_GSSAPI CREDENTIALS
+ HEIMDAL_GSSAPI CREDENTIALS LIBTSOCKET
service_OBJ_FILES = $(addprefix $(smbdsrcdir)/, \
service.o \
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index ddfa220a72..e73cdfd659 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -326,7 +326,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
umask(0);
DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING));
- DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2009\n"));
+ DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2010\n"));
if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) {
DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c
index ab35eb04bf..2d8b9559f4 100644
--- a/source4/smbd/service_stream.c
+++ b/source4/smbd/service_stream.c
@@ -26,6 +26,7 @@
#include "lib/messaging/irpc.h"
#include "cluster/cluster.h"
#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
/* the range of ports to try for dcerpc over tcp endpoints */
#define SERVER_TCP_LOW_PORT 1024
@@ -164,7 +165,6 @@ static void stream_new_connection(struct tevent_context *ev,
{
struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
struct stream_connection *srv_conn;
- struct socket_address *c, *s;
srv_conn = talloc_zero(ev, struct stream_connection);
if (!srv_conn) {
@@ -205,20 +205,34 @@ static void stream_new_connection(struct tevent_context *ev,
return;
}
- c = socket_get_peer_addr(sock, ev);
- s = socket_get_my_addr(sock, ev);
- if (s && c) {
+ srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn);
+ if (!srv_conn->remote_address) {
+ stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed");
+ return;
+ }
+
+ srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn);
+ if (!srv_conn->local_address) {
+ stream_terminate_connection(srv_conn, "socket_get_local_addr() failed");
+ return;
+ }
+
+ {
+ TALLOC_CTX *tmp_ctx;
const char *title;
- title = talloc_asprintf(s, "conn[%s] c[%s:%u] s[%s:%u] server_id[%s]",
+
+ tmp_ctx = talloc_new(srv_conn);
+
+ title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]",
stream_socket->ops->name,
- c->addr, c->port, s->addr, s->port,
- cluster_id_string(s, server_id));
+ tsocket_address_string(srv_conn->remote_address, tmp_ctx),
+ tsocket_address_string(srv_conn->local_address, tmp_ctx),
+ cluster_id_string(tmp_ctx, server_id));
if (title) {
stream_connection_set_title(srv_conn, title);
}
+ talloc_free(tmp_ctx);
}
- talloc_free(c);
- talloc_free(s);
/* we're now ready to start receiving events on this stream */
TEVENT_FD_READABLE(srv_conn->event.fde);
diff --git a/source4/smbd/service_stream.h b/source4/smbd/service_stream.h
index 5d577d4dd8..685502a8ba 100644
--- a/source4/smbd/service_stream.h
+++ b/source4/smbd/service_stream.h
@@ -50,6 +50,9 @@ struct stream_connection {
struct messaging_context *msg_ctx;
struct loadparm_context *lp_ctx;
+ struct tsocket_address *local_address;
+ struct tsocket_address *remote_address;
+
/*
* this transport layer session info, normally NULL
* which means the same as an anonymous session info
diff --git a/source4/torture/drs/unit/prefixmap_tests.c b/source4/torture/drs/unit/prefixmap_tests.c
index 03f30de106..4bfdcc0d8b 100644
--- a/source4/torture/drs/unit/prefixmap_tests.c
+++ b/source4/torture/drs/unit/prefixmap_tests.c
@@ -383,6 +383,48 @@ static bool torture_drs_unit_pfm_oid_from_attid(struct torture_context *tctx, st
}
/**
+ * Tests dsdb_schema_pfm_oid_from_attid() for handling
+ * correctly different type of attid values.
+ * See: MS-ADTS, 3.1.1.2.6 ATTRTYP
+ */
+static bool torture_drs_unit_pfm_oid_from_attid_check_attid(struct torture_context *tctx,
+ struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ const char *oid;
+
+ /* Test with valid prefixMap attid */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x00000000, tctx, &oid);
+ torture_assert_werr_ok(tctx, werr, "Testing prefixMap type attid = 0x0000000");
+
+ /* Test with attid in msDS-IntId range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x80000000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing msDS-IntId type attid = 0x80000000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xBFFFFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing msDS-IntId type attid = 0xBFFFFFFF");
+
+ /* Test with attid in RESERVED range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xC0000000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing RESERVED type attid = 0xC0000000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFEFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing RESERVED type attid = 0xFFFEFFFF");
+
+ /* Test with attid in INTERNAL range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFF0000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing INTERNAL type attid = 0xFFFF0000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFFFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing INTERNAL type attid = 0xFFFFFFFF");
+
+ return true;
+}
+
+/**
* Test Schema prefixMap conversions to/from drsuapi prefixMap
* representation.
*/
@@ -663,7 +705,6 @@ static bool torture_drs_unit_ldb_setup(struct torture_context *tctx, struct drsu
}
DONE:
- unlink(ldb_url);
talloc_free(mem_ctx);
return bret;
}
@@ -722,6 +763,8 @@ struct torture_tcase * torture_drs_unit_prefixmap(struct torture_suite *suite)
torture_tcase_add_simple_test(tc, "make_attid_full_map", (pfn_run)torture_drs_unit_pfm_make_attid_full_map);
torture_tcase_add_simple_test(tc, "make_attid_small_map", (pfn_run)torture_drs_unit_pfm_make_attid_small_map);
torture_tcase_add_simple_test(tc, "oid_from_attid_full_map", (pfn_run)torture_drs_unit_pfm_oid_from_attid);
+ torture_tcase_add_simple_test(tc, "oid_from_attid_check_attid",
+ (pfn_run)torture_drs_unit_pfm_oid_from_attid_check_attid);
torture_tcase_add_simple_test(tc, "pfm_to_from_drsuapi", (pfn_run)torture_drs_unit_pfm_to_from_drsuapi);
diff --git a/source4/torture/libnet/python/samr-test.py b/source4/torture/libnet/python/samr-test.py
new file mode 100644
index 0000000000..d68456b79d
--- /dev/null
+++ b/source4/torture/libnet/python/samr-test.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+#
+# 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/>.
+#
+
+#
+# Usage:
+# export ACCOUNT_NAME=kamen
+# export NEW_PASS=test
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$samba4srcdir/torture/libnet/python" $SUBUNITRUN samr-test -Ukma-exch.devel/Administrator%333
+#
+
+import sys
+import os
+
+from samba import net
+import unittest
+import samba.tests
+
+if not "ACCOUNT_NAME" in os.environ.keys():
+ parser.error("Please supply ACCOUNT_NAME in environment")
+
+if not "NEW_PASS" in os.environ.keys():
+ parser.error("Please supply NEW_PASS in environment")
+
+account_name = os.environ["ACCOUNT_NAME"]
+new_pass = os.environ["NEW_PASS"]
+
+creds = samba.tests.cmdline_credentials
+
+#
+# Tests start here
+#
+
+class Libnet_SetPwdTest(unittest.TestCase):
+
+ ########################################################################################
+
+ def test_SetPassword(self):
+ net.SetPassword(account_name=account_name,
+ domain_name=creds.get_domain(),
+ newpassword=new_pass,
+ credentials=creds)
+
+ ########################################################################################
+
diff --git a/source4/torture/ndr/ndr.c b/source4/torture/ndr/ndr.c
index 8602003017..471c398b77 100644
--- a/source4/torture/ndr/ndr.c
+++ b/source4/torture/ndr/ndr.c
@@ -233,12 +233,21 @@ static bool test_compare_uuid(struct torture_context *tctx)
"GUID diff invalid");
g1.time_low = 10;
- torture_assert_int_equal(tctx, 10, GUID_compare(&g1, &g2),
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
"GUID diff invalid");
g1.time_low = 0;
g1.clock_seq[1] = 20;
- torture_assert_int_equal(tctx, 20, GUID_compare(&g1, &g2),
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = ~0;
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = 0;
+ g2.time_low = ~0;
+ torture_assert_int_equal(tctx, -1, GUID_compare(&g1, &g2),
"GUID diff invalid");
return true;
}
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
index 78987e3121..8bf3a2d97f 100644
--- a/source4/torture/raw/oplock.c
+++ b/source4/torture/raw/oplock.c
@@ -697,6 +697,176 @@ done:
return ret;
}
+/**
+ * Exclusive version of batch19
+ */
+static bool test_raw_oplock_exclusive7(struct torture_context *tctx,
+ struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_exclusiv6_1.dat";
+ const char *fname2 = BASEDIR "\\test_exclusiv6_2.dat";
+ const char *fname3 = BASEDIR "\\test_exclusiv6_3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+ uint16_t fnum2 = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+ smbcli_unlink(cli1->tree, fname3);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "open a file with an exclusive oplock (share "
+ "mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo rename info should trigger a break "
+ "to none\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ /* Exclusive oplocks should not be broken on rename. */
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+ /* Try breaking to level2 and then see if rename breaks the level2.*/
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP already broke to level2. */
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+ } else {
+ /* Break to level 2 expected. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ }
+
+ ZERO_STRUCT(break_info);
+ sfi.generic.in.file.path = fname2;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname1+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ /* Level2 oplocks are not broken on rename. */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+
+ /* Close and re-open file with oplock. */
+ smbcli_close(cli1->tree, fnum);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setfileinfo rename info on a client's own fid "
+ "should not trigger a break nor a violation\n");
+ ZERO_STRUCT(break_info);
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+done:
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
{
const char *fname = BASEDIR "\\test_batch1.dat";
@@ -2117,7 +2287,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
- io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
@@ -2134,7 +2305,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
- torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n");
+ torture_comment(tctx, "setpathinfo rename info should trigger a break "
+ "to none\n");
ZERO_STRUCT(sfi);
sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
sfi.generic.in.file.path = fname1;
@@ -2146,7 +2318,22 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 0);
+
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* Win XP breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3/2k8 incorrectly doesn't break at all. */
+ CHECK_VAL(break_info.count, 0);
+ } else {
+ /* win7/2k8r2 break to none. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ }
ZERO_STRUCT(qfi);
qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
@@ -2156,7 +2343,16 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
- torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n");
+ /* Close and re-open file with oplock. */
+ smbcli_close(cli1->tree, fnum);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setfileinfo rename info on a client's own fid "
+ "should not trigger a break nor a violation\n");
+ ZERO_STRUCT(break_info);
ZERO_STRUCT(sfi);
sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
sfi.generic.in.file.fnum = fnum;
@@ -2168,7 +2364,13 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 0);
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ CHECK_VAL(break_info.count, 0);
+ }
ZERO_STRUCT(qfi);
qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
@@ -2178,9 +2380,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
- smbcli_close(cli1->tree, fnum);
-
done:
+ smbcli_close(cli1->tree, fnum);
smb_raw_exit(cli1->session);
smb_raw_exit(cli2->session);
smbcli_deltree(cli1->tree, BASEDIR);
@@ -2223,7 +2424,8 @@ bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1,
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
- io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
@@ -2284,9 +2486,8 @@ bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1,
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
- smbcli_close(cli1->tree, fnum);
-
done:
+ smbcli_close(cli1->tree, fnum);
smb_raw_exit(cli1->session);
smb_raw_exit(cli2->session);
smbcli_deltree(cli1->tree, BASEDIR);
@@ -2469,7 +2670,6 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
- torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n");
ZERO_STRUCT(sfi);
sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
sfi.generic.in.file.path = fname1;
@@ -2481,7 +2681,21 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* Win XP breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3/2k8 incorrectly doesn't break at all. */
+ CHECK_VAL(break_info.count, 0);
+ } else {
+ /* win7/2k8r2 break to none. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ }
ZERO_STRUCT(qfi);
qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
@@ -2506,11 +2720,22 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_
CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 1);
- CHECK_VAL(break_info.failures, 0);
- CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
- torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n");
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP broke to level2, and doesn't break again. */
+ CHECK_VAL(break_info.count, 0);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3 incorrectly didn't break before so break now. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ /* win7/2k8r2 broke to none, and doesn't break again. */
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(break_info);
+
ZERO_STRUCT(sfi);
sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
sfi.generic.in.file.fnum = fnum;
@@ -2522,9 +2747,7 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 1);
- CHECK_VAL(break_info.failures, 0);
- CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.count, 0);
ZERO_STRUCT(qfi);
qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
@@ -2542,9 +2765,10 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
- smbcli_close(cli1->tree, fnum);
done:
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
smb_raw_exit(cli1->session);
smb_raw_exit(cli2->session);
smbcli_deltree(cli1->tree, BASEDIR);
@@ -3639,6 +3863,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
torture_suite_add_2smb_test(suite, "EXCLUSIVE4", test_raw_oplock_exclusive4);
torture_suite_add_2smb_test(suite, "EXCLUSIVE5", test_raw_oplock_exclusive5);
torture_suite_add_2smb_test(suite, "EXCLUSIVE6", test_raw_oplock_exclusive6);
+ torture_suite_add_2smb_test(suite, "EXCLUSIVE7", test_raw_oplock_exclusive7);
torture_suite_add_2smb_test(suite, "BATCH1", test_raw_oplock_batch1);
torture_suite_add_2smb_test(suite, "BATCH2", test_raw_oplock_batch2);
torture_suite_add_2smb_test(suite, "BATCH3", test_raw_oplock_batch3);
diff --git a/source4/torture/raw/qfileinfo.c b/source4/torture/raw/qfileinfo.c
index 85f9f1b093..032df87a4d 100644
--- a/source4/torture/raw/qfileinfo.c
+++ b/source4/torture/raw/qfileinfo.c
@@ -140,7 +140,7 @@ static int dos_nt_time_cmp(time_t t, NTTIME nt)
{
time_t t2 = nt_time_to_unix(nt);
if (abs(t2 - t) <= 2) return 0;
- return t2 - t;
+ return t2 > t ? 1 : -1;
}
diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c
index 42f4f320c2..1f8adfbe9a 100644
--- a/source4/torture/raw/setfileinfo.c
+++ b/source4/torture/raw/setfileinfo.c
@@ -970,6 +970,158 @@ done:
return ret;
}
+static bool
+torture_raw_sfileinfo_archive(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\test_archive.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo finfo;
+ uint16_t fnum=0;
+ uint32_t access_mask = 0;
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli->tree, fname);
+
+ /*
+ * create a normal file, verify archive bit
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "open failed");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_ARCHIVE,
+ "archive bit not set");
+
+ /*
+ * try to turn off archive bit
+ */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_NORMAL,
+ "archive bit set");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "close failed");
+
+ status = smbcli_unlink(cli->tree, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "unlink failed");
+
+ /*
+ * create a directory, verify no archive bit
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_DIR_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "directory open failed");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY,
+ "archive bit set");
+
+ /*
+ * verify you can turn on archive bit
+ */
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE,
+ "archive bit not set");
+
+ /*
+ * and try to turn it back off
+ */
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY,
+ "archive bit set");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "close failed");
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
struct torture_suite *torture_raw_sfileinfo(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx,
@@ -983,6 +1135,7 @@ struct torture_suite *torture_raw_sfileinfo(TALLOC_CTX *mem_ctx)
torture_raw_sfileinfo_eof);
torture_suite_add_2smb_test(suite, "END-OF-FILE-ACCESS",
torture_raw_sfileinfo_eof_access);
+ torture_suite_add_1smb_test(suite, "ARCHIVE", torture_raw_sfileinfo_archive);
return suite;
}
diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c
index 79cacffe10..a55575b6a3 100644
--- a/source4/torture/raw/streams.c
+++ b/source4/torture/raw/streams.c
@@ -609,7 +609,8 @@ static bool test_stream_delete(struct torture_context *tctx,
CHECK_STATUS(status, NT_STATUS_OK);
/* w2k and w2k3 return 0 and w2k8 returns 1 */
- if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx)) {
+ if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
+ TARGET_IS_SAMBA3(tctx)) {
CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
} else {
CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c
index 828e46889e..ba935b9986 100644
--- a/source4/utils/net/net.c
+++ b/source4/utils/net/net.c
@@ -6,6 +6,7 @@
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
Copyright (C) 2004 Stefan Metzmacher (metze@samba.org)
+ Copyright (C) 2009 Jelmer Vernooij (jelmer@samba.org)
Largely rewritten by metze in August 2004
@@ -48,6 +49,83 @@
#include "param/param.h"
#include "lib/events/events.h"
#include "auth/credentials/credentials.h"
+#include <Python.h>
+#include "scripting/python/modules.h"
+
+static PyObject *py_tuple_from_argv(int argc, const char *argv[])
+{
+ PyObject *l;
+ Py_ssize_t i;
+
+ l = PyTuple_New(argc);
+ if (l == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < argc; i++) {
+ PyTuple_SetItem(l, i, PyString_FromString(argv[i]));
+ }
+
+ return l;
+}
+
+static int py_call_with_string_args(PyObject *self, const char *method, int argc, const char *argv[])
+{
+ PyObject *ret, *args, *py_method;
+
+ args = py_tuple_from_argv(argc, argv);
+ if (args == NULL) {
+ PyErr_Print();
+ return 1;
+ }
+
+ py_method = PyObject_GetAttrString(self, method);
+ if (py_method == NULL) {
+ PyErr_Print();
+ return 1;
+ }
+
+ ret = PyObject_CallObject(py_method, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ PyErr_Print();
+ return 1;
+ }
+
+ if (ret == Py_None) {
+ return 0;
+ } else if (PyInt_Check(ret)) {
+ return PyInt_AsLong(ret);
+ } else {
+ fprintf(stderr, "Function return value type unexpected.\n");
+ return -1;
+ }
+}
+
+static PyObject *py_commands(void)
+{
+ PyObject *netcmd_module, *py_cmds;
+ netcmd_module = PyImport_ImportModule("samba.netcmd");
+ if (netcmd_module == NULL) {
+ PyErr_Print();
+ return NULL;
+ }
+
+ py_cmds = PyObject_GetAttrString(netcmd_module, "commands");
+ if (py_cmds == NULL) {
+ PyErr_Print();
+ return NULL;
+ }
+
+ if (!PyDict_Check(py_cmds)) {
+ d_printf("Python net commands is not a dictionary\n");
+ return NULL;
+ }
+
+ return py_cmds;
+}
/*
run a function from a function table. If not found then
@@ -84,6 +162,7 @@ int net_run_usage(struct net_context *ctx,
const struct net_functable *functable)
{
int i;
+ PyObject *py_cmds, *py_cmd;
for (i=0; functable[i].name; i++) {
if (strcasecmp_m(argv[0], functable[i].name) == 0)
@@ -92,6 +171,17 @@ int net_run_usage(struct net_context *ctx,
}
}
+ py_cmds = py_commands();
+ if (py_cmds == NULL) {
+ return 1;
+ }
+
+ py_cmd = PyDict_GetItemString(py_cmds, argv[0]);
+ if (py_cmd != NULL) {
+ return py_call_with_string_args(py_cmd, "usage", argc-1,
+ argv+1);
+ }
+
d_printf("No usage information for command: %s\n", argv[0]);
return 1;
@@ -112,13 +202,12 @@ static const struct net_functable net_functable[] = {
{NULL, NULL, NULL, NULL}
};
-int net_help(struct net_context *ctx, const struct net_functable *ftable)
+static int net_help_builtin(const struct net_functable *ftable)
{
int i = 0;
const char *name = ftable[i].name;
const char *desc = ftable[i].desc;
- d_printf("Available commands:\n");
while (name && desc) {
if (strlen(name) > 7) {
d_printf("\t%s\t%s", name, desc);
@@ -128,7 +217,53 @@ int net_help(struct net_context *ctx, const struct net_functable *ftable)
name = ftable[++i].name;
desc = ftable[i].desc;
}
+ return 0;
+}
+
+static int net_help_python(void)
+{
+ PyObject *py_cmds;
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ py_cmds = py_commands();
+ if (py_cmds == NULL) {
+ return 1;
+ }
+
+ while (PyDict_Next(py_cmds, &pos, &key, &value)) {
+ char *name, *desc;
+ PyObject *py_desc;
+ if (!PyString_Check(key)) {
+ d_printf("Command name not a string\n");
+ return 1;
+ }
+ name = PyString_AsString(key);
+ py_desc = PyObject_GetAttrString(value, "description");
+ if (py_desc == NULL) {
+ PyErr_Print();
+ return 1;
+ }
+ if (!PyString_Check(py_desc)) {
+ d_printf("Command description for %s not a string\n",
+ name);
+ return 1;
+ }
+ desc = PyString_AsString(py_desc);
+ if (strlen(name) > 7) {
+ d_printf("\t%s\t%s\n", name, desc);
+ } else {
+ d_printf("\t%s\t\t%s\n", name, desc);
+ }
+ }
+ return 0;
+}
+int net_help(struct net_context *ctx, const struct net_functable *ftable)
+{
+ d_printf("Available commands:\n");
+ net_help_builtin(ftable);
+ net_help_python();
return 0;
}
@@ -148,6 +283,7 @@ static int binary_net(int argc, const char **argv)
int opt,i;
int rc;
int argc_new;
+ PyObject *py_cmds, *py_cmd;
const char **argv_new;
struct tevent_context *ev;
struct net_context *ctx = NULL;
@@ -163,6 +299,33 @@ static int binary_net(int argc, const char **argv)
setlinebuf(stdout);
+ dcerpc_init(cmdline_lp_ctx);
+
+ ev = s4_event_context_init(NULL);
+ if (!ev) {
+ d_printf("Failed to create an event context\n");
+ exit(1);
+ }
+ py_load_samba_modules();
+ Py_Initialize();
+ PySys_SetArgv(argc, argv);
+ py_update_path("bin"); /* FIXME: Can't assume this is always the case */
+
+ py_cmds = py_commands();
+ if (py_cmds == NULL) {
+ return 1;
+ }
+
+ if (argc > 1) {
+ py_cmd = PyDict_GetItemString(py_cmds, argv[1]);
+ if (py_cmd != NULL) {
+ rc = py_call_with_string_args(py_cmd, "_run",
+ argc-1, argv+1);
+ talloc_free(ev);
+ return rc;
+ }
+ }
+
pc = poptGetContext("net", argc, (const char **) argv, long_options,
POPT_CONTEXT_KEEP_FIRST);
@@ -190,13 +353,7 @@ static int binary_net(int argc, const char **argv)
return net_usage(ctx, argc, argv);
}
- dcerpc_init(cmdline_lp_ctx);
- ev = s4_event_context_init(NULL);
- if (!ev) {
- d_printf("Failed to create an event context\n");
- exit(1);
- }
ctx = talloc(ev, struct net_context);
if (!ctx) {
d_printf("Failed to talloc a net_context\n");
@@ -208,7 +365,10 @@ static int binary_net(int argc, const char **argv)
ctx->credentials = cmdline_credentials;
ctx->event_ctx = ev;
- rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, net_usage);
+
+
+ rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable,
+ net_usage);
if (rc != 0) {
DEBUG(0,("return code = %d\n", rc));
diff --git a/testprogs/blackbox/test_export_keytab.sh b/testprogs/blackbox/test_export_keytab.sh
index 80235d3255..c5e85e35c8 100755
--- a/testprogs/blackbox/test_export_keytab.sh
+++ b/testprogs/blackbox/test_export_keytab.sh
@@ -22,7 +22,7 @@ samba4bindir="$BUILDDIR/bin"
smbclient="$samba4bindir/smbclient$EXEEXT"
samba4kinit="$samba4bindir/samba4kinit$EXEEXT"
net="$samba4bindir/net$EXEEXT"
-newuser="$PYTHON `dirname $0`/../../source4/setup/newuser"
+newuser="$net newuser"
. `dirname $0`/subunit.sh
diff --git a/testprogs/blackbox/test_kinit.sh b/testprogs/blackbox/test_kinit.sh
index 91f21f473b..0f835ef635 100755
--- a/testprogs/blackbox/test_kinit.sh
+++ b/testprogs/blackbox/test_kinit.sh
@@ -25,7 +25,7 @@ samba4kinit="$samba4bindir/samba4kinit$EXEEXT"
net="$samba4bindir/net$EXEEXT"
rkpty="$samba4bindir/rkpty$EXEEXT"
samba4kpasswd="$samba4bindir/samba4kpasswd$EXEEXT"
-enableaccount="$PYTHON `dirname $0`/../../source4/setup/enableaccount"
+enableaccount="$samba4bindir/net enableaccount"
. `dirname $0`/subunit.sh
diff --git a/testprogs/blackbox/test_passwords.sh b/testprogs/blackbox/test_passwords.sh
index 09799f6efa..9a4c1915f6 100755
--- a/testprogs/blackbox/test_passwords.sh
+++ b/testprogs/blackbox/test_passwords.sh
@@ -5,7 +5,7 @@
if [ $# -lt 5 ]; then
cat <<EOF
-Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX
+Usage: test_passwords.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX
EOF
exit 1;
fi
@@ -25,9 +25,7 @@ samba4kinit="$samba4bindir/samba4kinit$EXEEXT"
net="$samba4bindir/net$EXEEXT"
rkpty="$samba4bindir/rkpty$EXEEXT"
samba4kpasswd="$samba4bindir/samba4kpasswd$EXEEXT"
-enableaccount="$PYTHON `dirname $0`/../../source4/setup/enableaccount"
-setpassword="$PYTHON `dirname $0`/../../source4/setup/setpassword"
-newuser="$PYTHON `dirname $0`/../../source4/setup/newuser"
+newuser="$net newuser"
. `dirname $0`/subunit.sh
@@ -47,9 +45,12 @@ test_smbclient() {
return $status
}
+CONFIG="--configfile=$PREFIX/dc/etc/smb.conf"
+export CONFIG
+
USERPASS=testPaSS@01%
-testit "create user locally" $VALGRIND $newuser nettestuser $USERPASS $@ || failed=`expr $failed + 1`
+testit "create user locally" $VALGRIND $newuser $CONFIG nettestuser $USERPASS $@ || failed=`expr $failed + 1`
KRB5CCNAME="$PREFIX/tmpuserccache"
export KRB5CCNAME
@@ -61,7 +62,7 @@ testit "kinit with user password" $samba4kinit --password-file=$PREFIX/tmpuserpa
test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
NEWUSERPASS=testPaSS@02%
-testit "change user password with 'net password change' (unforced)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
+testit "change user password with 'net password change' (unforced)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN/nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
echo $NEWUSERPASS > ./tmpuserpassfile
testit "kinit with user password" $samba4kinit --password-file=./tmpuserpassfile --request-pac nettestuser@$REALM || failed=`expr $failed + 1`
@@ -88,15 +89,15 @@ test_smbclient "Test login with user kerberos (unforced)" 'ls' -k yes -Unettestu
NEWUSERPASS=testPaSS@04%
-testit "set password on user locally" $VALGRIND $setpassword nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
+testit "set password on user locally" $VALGRIND $net setpassword $CONFIG nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
USERPASS=$NEWUSERPASS
NEWUSERPASS=testPaSS@05%
-testit "change user password with 'net password change' (after must change flag set)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
+testit "change user password with 'net password change' (after must change flag set)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN/nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
USERPASS=$NEWUSERPASS
NEWUSERPASS=testPaSS@06%
-testit "set password on user locally" $VALGRIND $setpassword nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
+testit "set password on user locally" $VALGRIND $net setpassword $CONFIG nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
USERPASS=$NEWUSERPASS
NEWUSERPASS=testPaSS@07%
@@ -116,32 +117,34 @@ USERPASS=$NEWUSERPASS
test_smbclient "Test login with user kerberos" 'ls' -k yes -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
-testit "reset password policies" $VALGRIND $PYTHON ./setup/pwsettings set --configfile=$PREFIX/dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
+testit "reset password policies" $VALGRIND $net pwsettings set $CONFIG --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
NEWUSERPASS=abcdefg
-testit_expect_failure "try to set a non-complex password (command should not succeed)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ && failed=`expr $failed + 1`
+testit_expect_failure "try to set a non-complex password (command should not succeed)" $VALGRIND $net password change -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no "$NEWUSERPASS" $@ && failed=`expr $failed + 1`
-testit "allow non-complex passwords" $VALGRIND $PYTHON ./setup/pwsettings set --configfile=$PREFIX/dc/etc/smb.conf --complexity=off || failed=`expr $failed + 1`
+testit "allow non-complex passwords" $VALGRIND $net pwsettings set $CONFIG --complexity=off || failed=`expr $failed + 1`
-testit "try to set a non-complex password (command should succeed)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
+testit "try to set a non-complex password (command should succeed)" $VALGRIND $net password change -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no "$NEWUSERPASS" $@ || failed=`expr $failed + 1`
USERPASS=$NEWUSERPASS
test_smbclient "test login with non-complex password" 'ls' -k no -Unettestuser@$REALM%$USERPASS || failed=`expr $failed + 1`
NEWUSERPASS=abc
-testit_expect_failure "try to set a short password (command should not succeed)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ && failed=`expr $failed + 1`
+testit_expect_failure "try to set a short password (command should not succeed)" $VALGRIND $net password change -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no "$NEWUSERPASS" $@ && failed=`expr $failed + 1`
-testit "allow short passwords (length 1)" $VALGRIND $PYTHON ./setup/pwsettings set --configfile=$PREFIX/dc/etc/smb.conf --min-pwd-length=1 || failed=`expr $failed + 1`
+testit "allow short passwords (length 1)" $VALGRIND $net pwsettings $CONFIG set --min-pwd-length=1 || failed=`expr $failed + 1`
-testit "try to set a short password (command should succeed)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ || failed=`expr $failed + 1`
-USERPASS=$NEWUSERPASS
+testit "try to set a short password (command should succeed)" $VALGRIND $net password change -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no "$NEWUSERPASS" $@ || failed=`expr $failed + 1`
+USERPASS="$NEWUSERPASS"
+
+testit "require minimum password age of 1 day" $VALGRIND $net pwsettings $CONFIG set --min-pwd-age=1 || failed=`expr $failed + 1`
-testit "require minimum password age of 1 day" $VALGRIND $PYTHON ./setup/pwsettings set --configfile=$PREFIX/dc/etc/smb.conf --min-pwd-age=1 || failed=`expr $failed + 1`
+testit "show password settings" $VALGRIND $net pwsettings $CONFIG show || failed=`expr $failed + 1`
-NEWUSERPASS=testPaSS@08%
-testit_expect_failure "try to change password too quickly (command should not succeed)" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS -k no $NEWUSERPASS $@ && failed=`expr $failed + 1`
+NEWUSERPASS="testPaSS@08%"
+testit_expect_failure "try to change password too quickly (command should not succeed)" $VALGRIND $net password change -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no "$NEWUSERPASS" $@ && failed=`expr $failed + 1`
-testit "reset password policies" $VALGRIND $PYTHON ./setup/pwsettings set --configfile=$PREFIX/dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
+testit "reset password policies" $VALGRIND $net pwsettings $CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
testit "del user" $VALGRIND $net user delete nettestuser -U"$USERNAME%$PASSWORD" -k no $@ || failed=`expr $failed + 1`