summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW.txt137
-rw-r--r--docs-xml/manpages/net.8.xml15
-rw-r--r--docs-xml/smbdotconf/security/inheritowner.xml6
-rw-r--r--docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml16
-rw-r--r--lib/param/param_functions.c1
-rw-r--r--lib/param/param_table.c9
-rw-r--r--lib/replace/replace.h5
-rw-r--r--lib/replace/wscript25
-rw-r--r--lib/tevent/tevent_signal.c6
-rw-r--r--lib/util/charset/tests/charset.c12
-rw-r--r--lib/util/charset/util_str.c37
-rw-r--r--lib/util/memcache.c (renamed from source3/lib/memcache.c)22
-rw-r--r--lib/util/memcache.h (renamed from source3/include/memcache.h)2
-rw-r--r--lib/util/select.c14
-rw-r--r--lib/util/string_wrappers.h5
-rwxr-xr-xlib/util/wscript_build2
-rw-r--r--libcli/auth/credentials.c2
-rw-r--r--libcli/auth/proto.h1
-rw-r--r--libcli/dns/dns_hosts_file.c35
-rw-r--r--libcli/security/secdesc.c36
-rw-r--r--librpc/idl/security.idl18
-rw-r--r--python/samba/join.py4
-rw-r--r--python/samba/provision/sambadns.py1
-rw-r--r--python/samba/tests/dcerpc/dnsserver.py41
-rw-r--r--python/samba/tests/dns.py1
-rw-r--r--selftest/README1
-rw-r--r--selftest/knownfail1
-rwxr-xr-xselftest/selftest.pl6
-rwxr-xr-xselftest/target/Samba3.pm15
-rw-r--r--selftest/target/Samba4.pm19
-rw-r--r--source3/auth/token_util.c2
-rw-r--r--source3/include/includes.h8
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/access.c2
-rw-r--r--source3/lib/id_cache.c2
-rw-r--r--source3/lib/username.c2
-rw-r--r--source3/lib/util_sock.c2
-rw-r--r--source3/librpc/idl/open_files.idl1
-rw-r--r--source3/libsmb/clidfs.c6
-rw-r--r--source3/libsmb/libsmb_server.c5
-rw-r--r--source3/modules/vfs_default.c12
-rw-r--r--source3/modules/vfs_dirsort.c2
-rw-r--r--source3/modules/vfs_gpfs.c63
-rw-r--r--source3/param/loadparm.c1
-rw-r--r--source3/passdb/lookup_sid.c2
-rw-r--r--source3/passdb/pdb_interface.c2
-rw-r--r--source3/passdb/pdb_samba_dsdb.c6
-rw-r--r--source3/printing/load.c4
-rw-r--r--source3/printing/pcap.c54
-rw-r--r--source3/printing/pcap.h13
-rw-r--r--source3/printing/print_aix.c17
-rw-r--r--source3/printing/print_iprint.c16
-rw-r--r--source3/printing/print_standard.c8
-rw-r--r--source3/printing/print_svid.c11
-rw-r--r--source3/printing/printer_list.c17
-rw-r--r--source3/printing/printer_list.h4
-rw-r--r--source3/printing/queue_process.c102
-rw-r--r--source3/printing/spoolssd.c38
-rw-r--r--source3/rpc_client/cli_netlogon.c1
-rw-r--r--source3/rpc_server/spoolss/srv_spoolss_nt.c30
-rw-r--r--source3/rpc_server/srvsvc/srv_srvsvc_nt.c1
-rw-r--r--source3/smbd/dir.c2
-rw-r--r--source3/smbd/dosmode.c13
-rw-r--r--source3/smbd/durable.c14
-rw-r--r--source3/smbd/globals.c2
-rw-r--r--source3/smbd/lanman.c1
-rw-r--r--source3/smbd/mangle_hash.c4
-rw-r--r--source3/smbd/mangle_hash2.c2
-rw-r--r--source3/smbd/negprot.c3
-rw-r--r--source3/smbd/nttrans.c7
-rw-r--r--source3/smbd/posix_acls.c2
-rw-r--r--source3/smbd/proto.h1
-rw-r--r--source3/smbd/server.c22
-rw-r--r--source3/smbd/server_reload.c74
-rw-r--r--source3/smbd/smb2_find.c41
-rw-r--r--source3/smbd/smb2_getinfo.c3
-rw-r--r--source3/smbd/smb2_setinfo.c3
-rw-r--r--source3/smbd/statcache.c2
-rw-r--r--source3/smbd/vfs.c2
-rw-r--r--source3/torture/torture.c2
-rw-r--r--source3/utils/net_time.c30
-rw-r--r--source3/winbindd/idmap.c4
-rw-r--r--source3/winbindd/winbindd.c36
-rw-r--r--source3/wscript72
-rwxr-xr-xsource3/wscript_build2
-rw-r--r--source4/dns_server/dlz_bind9.c377
-rw-r--r--source4/dns_server/dlz_minimal.h2
-rw-r--r--source4/dns_server/dns_server.h6
-rw-r--r--source4/dns_server/dns_update.c78
-rw-r--r--source4/dns_server/dns_utils.c150
-rw-r--r--source4/dns_server/dnsserver_common.c342
-rw-r--r--source4/dns_server/dnsserver_common.h50
-rw-r--r--source4/dns_server/wscript_build14
-rw-r--r--source4/dsdb/dns/dns_update.c13
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c1
-rw-r--r--source4/rpc_server/dnsserver/dcerpc_dnsserver.c22
-rw-r--r--source4/rpc_server/dnsserver/dnsdata.c11
-rw-r--r--source4/rpc_server/dnsserver/dnsdb.c26
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c91
-rwxr-xr-xsource4/scripting/bin/samba_dnsupdate213
-rw-r--r--source4/setup/dns_update_list82
-rw-r--r--source4/torture/dns/dlz_bind9.c868
-rw-r--r--source4/torture/ntp/ntp_signd.c1
-rw-r--r--source4/torture/rpc/lsa.c1
-rw-r--r--source4/torture/rpc/netlogon.c164
-rw-r--r--source4/torture/rpc/samba3rpc.c2
107 files changed, 2867 insertions, 923 deletions
diff --git a/VERSION b/VERSION
index 72f82cc6366..cb14e70ddef 100644
--- a/VERSION
+++ b/VERSION
@@ -25,7 +25,7 @@
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=1
-SAMBA_VERSION_RELEASE=11
+SAMBA_VERSION_RELEASE=12
########################################################
# If a official release has a serious bug #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 521ea1fd0b8..25059275056 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,137 @@
==============================
+ Release Notes for Samba 4.1.12
+ September 8, 2014
+ ==============================
+
+
+This is the latest stable release of Samba 4.1.
+
+Major enhancements in Samba 4.1.12 include:
+
+o New parameter "winbind request timeout" has been added (bug #3204). Please
+ see smb.conf man page for details.
+o Fix smbd crashes when filename contains non-ascii character (bug #10716).
+o dnsserver: Handle updates of tombstoned dnsNode objects (bug #10749).
+
+
+Changes since 4.1.11:
+---------------------
+
+o Michael Adam <obnox@samba.org>
+ * BUG 10369: build: Fix configure to honour '--without-dmapi'.
+ * BUG 10737: s3:idmap: Don't log missing range config if range checking not
+ requested.
+ * BUG 10741: Fix flapping VFS gpfs offline bit.
+
+
+o Jeremy Allison <jra@samba.org>
+ * BUG 3204: s3: winbindd: On new client connect, prune idle or hung
+ connections older than "winbind request timeout". Add new parameter
+ "winbind request timeout".
+ * BUG 10640: lib: tevent: make TEVENT_SIG_INCREMENT atomic.
+ * BUG 10650: Make "case sensitive = True" option working with
+ "max protocol = SMB2" or higher in large directories.
+ * BUG 10716: Fix smbd crashes when filename contains non-ascii
+ character.
+ * BUG 10728: 'net time': Fix usage and core dump.
+ * BUG 10773: s3: smbd: POSIX ACLs. Remove incorrect check for
+ SECINFO_PROTECTED_DACL in incoming security_information flags in
+ posix_get_nt_acl_common().
+ * BUG 10794: vfs_dirsort: Fix an off-by-one error that can cause
+ uninitialized memory read.
+
+
+o Björn Baumbach <bb@sernet.de>
+ * BUG 10543: s3: Enforce a positive allocation_file_size for non-empty
+ files.
+
+
+o Kai Blin <kai@samba.org>
+ * BUG 10466: provision: Correctly provision the SOA record minimum TTL.
+
+
+o David Disseldorp <ddiss@samba.org>
+ * BUG 10652: Samba 4 consuming a lot of CPU when re-reading printcap info.
+ * BUG 10787: dosmode: Fix FSCTL_SET_SPARSE request validation.
+
+
+o Amitay Isaacs <amitay@gmail.com>
+ * BUG 10742: s4-rpc: dnsserver: Allow . to be specified for @ record.
+
+
+o Daniel Kobras <d.kobras@science-computing.de>
+ * BUG 10731: sys_poll_intr: Fix timeout arithmetic.
+
+
+o Ross Lagerwall <rosslagerwall@gmail.com>
+ * BUG 10778: s3:libsmb: Set a max charge for SMB2 connections.
+
+
+o Volker Lendecke <vl@samba.org>
+ * BUG 10716: lib: strings: Simplify strcasecmp.
+ * BUG 10758: lib: Remove unused nstrcpy.
+ * BUG 10782: smbd: Properly initialize mangle_hash.
+
+
+o Stefan Metzmacher <metze@samba.org>
+ * BUG 9831: s4:setup/dns_update_list: make use of the new substitution
+ variables.
+ * BUG 10723: Allow netr_ServerReqChallenge() and netr_ServerAuthenticate3()
+ on different connections.
+ * BUG 10749: s4-rpc: dnsserver: Handle updates of tombstoned dnsNode
+ objects.
+ * BUG 10751: s4-rpc: dnsserver: return DNS_RANK_NS_GLUE recors when
+ explicitly asked for.
+ * BUG 10773: libcli/security: Add better detection of
+ SECINFO_[UN]PROTECTED_[D|S]ACL in get_sec_info().
+
+
+o Marc Muehlfeld <mmuehlfeld@samba.org>
+ * BUG 10761: docs: Fix typos in smb.conf (inherit acls).
+
+
+o Shirish Pargaonkar <spargaonkar@suse.com>
+ * BUG 10755: samba: Retain case sensitivity of cifs client.
+
+
+o Arvid Requate <requate@univention.de>
+ * BUG 9570: passdb: Fix NT_STATUS_NO_SUCH_GROUP.
+
+
+o Har Gagan Sahai <SHarGagan@novell.com>
+ * BUG 10759: Fix a memory leak in cli_set_mntpoint().
+
+
+o Roel van Meer <roel@1afa.com>
+ * BUG 10777: Don't discard result of checking grouptype.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.freenode.net.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the Samba 4.1 product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+
+======================================================================
+
+ ==============================
Release Notes for Samba 4.1.11
August 1, 2014
==============================
@@ -44,10 +177,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
-======================================================================
==============================
Release Notes for Samba 4.1.10
diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
index e2e1b8ff566..4c88008ea8a 100644
--- a/docs-xml/manpages/net.8.xml
+++ b/docs-xml/manpages/net.8.xml
@@ -404,7 +404,8 @@ YOU HAVE BEEN WARNED.
<title>TIME</title>
<para>Without any options, the <command>NET TIME</command> command
-displays the time on the remote server.
+displays the time on the remote server. The remote server must be
+specified with the -S option.
</para>
</refsect3>
@@ -412,21 +413,27 @@ displays the time on the remote server.
<refsect3>
<title>TIME SYSTEM</title>
-<para>Displays the time on the remote server in a format ready for <command>/bin/date</command>.</para>
+<para>Displays the time on the remote server in a format ready for <command>/bin/date</command>.
+The remote server must be specified with the -S option.
+</para>
</refsect3>
<refsect3>
<title>TIME SET</title>
<para>Tries to set the date and time of the local server to that on
-the remote server using <command>/bin/date</command>. </para>
+the remote server using <command>/bin/date</command>.
+The remote server must be specified with the -S option.
+</para>
</refsect3>
<refsect3>
<title>TIME ZONE</title>
-<para>Displays the timezone in hours from GMT on the remote computer.</para>
+<para>Displays the timezone in hours from GMT on the remote server.
+The remote server must be specified with the -S option.
+</para>
</refsect3>
</refsect2>
diff --git a/docs-xml/smbdotconf/security/inheritowner.xml b/docs-xml/smbdotconf/security/inheritowner.xml
index ba4fc617cb5..0ed8285b065 100644
--- a/docs-xml/smbdotconf/security/inheritowner.xml
+++ b/docs-xml/smbdotconf/security/inheritowner.xml
@@ -10,9 +10,9 @@
by the ownership of the parent directory.</para>
<para>Common scenarios where this behavior is useful is in
- implementing drop-boxes where users can create and edit files but not
- delete them and to ensure that newly create files in a user's
- roaming profile directory are actually owner by the user.</para>
+ implementing drop-boxes, where users can create and edit files but
+ not delete them and ensuring that newly created files in a user's
+ roaming profile directory are actually owned by the user.</para>
</description>
<related>inherit permissions</related>
diff --git a/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml b/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml
new file mode 100644
index 00000000000..322087161d2
--- /dev/null
+++ b/docs-xml/smbdotconf/winbind/winbindrequesttimeout.xml
@@ -0,0 +1,16 @@
+<samba:parameter name="winbind request timeout"
+ context="G"
+ type="integer"
+ advanced="1" developer="1"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This parameter specifies the number of
+ seconds the <citerefentry><refentrytitle>winbindd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> daemon will wait before
+ disconnecting either a client connection with no outstanding
+ requests (idle) or a client connection with a request that has
+ remained outstanding (hung) for longer than this number of seconds.</para>
+</description>
+
+<value type="default">60</value>
+</samba:parameter>
diff --git a/lib/param/param_functions.c b/lib/param/param_functions.c
index 61f00448ca3..d9d5df62726 100644
--- a/lib/param/param_functions.c
+++ b/lib/param/param_functions.c
@@ -341,6 +341,7 @@ FN_GLOBAL_INTEGER(winbind_cache_time, winbind_cache_time)
FN_GLOBAL_INTEGER(winbind_expand_groups, winbind_expand_groups)
FN_GLOBAL_INTEGER(winbind_max_clients, winbind_max_clients)
FN_GLOBAL_INTEGER(winbind_reconnect_delay, winbind_reconnect_delay)
+FN_GLOBAL_INTEGER(winbind_request_timeout, winbind_request_timeout)
FN_GLOBAL_LIST(auth_methods, AuthMethods)
FN_GLOBAL_LIST(cluster_addresses, szClusterAddresses)
FN_GLOBAL_LIST(dcerpc_endpoint_servers, dcerpc_ep_servers)
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index 7b32998084c..8e3f952b6ec 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -4018,6 +4018,15 @@ static struct parm_struct parm_table[] = {
.flags = FLAG_ADVANCED,
},
{
+ .label = "winbind request timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .offset = GLOBAL_VAR(winbind_request_timeout),
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
.label = "winbind max clients",
.type = P_INTEGER,
.p_class = P_GLOBAL,
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index c0b799763a8..cd0c25e2af7 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -899,4 +899,9 @@ int usleep(useconds_t);
void rep_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
#endif
+/* Needed for Solaris atomic_add_XX functions. */
+#if defined(HAVE_SYS_ATOMIC_H)
+#include <sys/atomic.h>
+#endif
+
#endif /* _LIBREPLACE_REPLACE_H */
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 84516898003..f0040b18e02 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -106,6 +106,7 @@ struct foo bar = { .y = 'X', .x = 1 };
conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h')
conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h malloc.h')
conf.CHECK_HEADERS('syscall.h sys/syscall.h inttypes.h')
+ conf.CHECK_HEADERS('sys/atomic.h')
# Check for process set name support
conf.CHECK_CODE('''
@@ -225,6 +226,30 @@ struct foo bar = { .y = 'X', .x = 1 };
msg="Checking whether we have ucontext_t",
headers='signal.h sys/ucontext.h')
+ # Check for atomic builtins. */
+ conf.CHECK_CODE('''
+ int main(void) {
+ int i;
+ (void)__sync_fetch_and_add(&i, 1);
+ return 0;
+ }
+ ''',
+ 'HAVE___SYNC_FETCH_AND_ADD',
+ msg='Checking for __sync_fetch_and_add compiler builtin')
+
+ conf.CHECK_CODE('''
+ #include <stdint.h>
+ #include <sys/atomic.h>
+ int main(void) {
+ int32_t i;
+ atomic_add_32(&i, 1);
+ return 0;
+ }
+ ''',
+ 'HAVE_ATOMIC_ADD_32',
+ headers='stdint.h sys/atomic.h',
+ msg='Checking for atomic_add_32 compiler builtin')
+
# these may be builtins, so we need the link=False strategy
conf.CHECK_FUNCS('strdup memmem printf memset memcpy memmove strcpy strncpy bzero', link=False)
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 0fdf646c8de..95a099d6ab5 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -42,7 +42,13 @@ struct tevent_sigcounter {
uint32_t seen;
};
+#if defined(HAVE___SYNC_FETCH_AND_ADD)
+#define TEVENT_SIG_INCREMENT(s) __sync_fetch_and_add(&((s).count), 1)
+#elif defined(HAVE_ATOMIC_ADD_32)
+#define TEVENT_SIG_INCREMENT(s) atomic_add_32(&((s).count), 1)
+#else
#define TEVENT_SIG_INCREMENT(s) (s).count++
+#endif
#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
diff --git a/lib/util/charset/tests/charset.c b/lib/util/charset/tests/charset.c
index 70b67418763..a47670e6665 100644
--- a/lib/util/charset/tests/charset.c
+++ b/lib/util/charset/tests/charset.c
@@ -50,12 +50,18 @@ static bool test_codepoint_cmpi(struct torture_context *tctx)
static bool test_strcasecmp_m(struct torture_context *tctx)
{
+ /* file.{accented e} in iso8859-1 */
+ const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
+ /* file.{accented e} in utf8 */
+ const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
torture_assert(tctx, strcasecmp_m("foo", "bar") != 0, "different strings");
torture_assert(tctx, strcasecmp_m("foo", "foo") == 0, "same case strings");
torture_assert(tctx, strcasecmp_m("foo", "Foo") == 0, "different case strings");
torture_assert(tctx, strcasecmp_m(NULL, "Foo") != 0, "one NULL");
torture_assert(tctx, strcasecmp_m("foo", NULL) != 0, "other NULL");
torture_assert(tctx, strcasecmp_m(NULL, NULL) == 0, "both NULL");
+ torture_assert(tctx, strcasecmp_m(file_iso8859_1, file_utf8) != 0,
+ "file.{accented e} should differ");
return true;
}
@@ -102,6 +108,10 @@ static bool test_string_replace_m(struct torture_context *tctx)
static bool test_strncasecmp_m(struct torture_context *tctx)
{
+ /* file.{accented e} in iso8859-1 */
+ const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
+ /* file.{accented e} in utf8 */
+ const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
torture_assert(tctx, strncasecmp_m("foo", "bar", 3) != 0, "different strings");
torture_assert(tctx, strncasecmp_m("foo", "foo", 3) == 0, "same case strings");
torture_assert(tctx, strncasecmp_m("foo", "Foo", 3) == 0, "different case strings");
@@ -111,6 +121,8 @@ static bool test_strncasecmp_m(struct torture_context *tctx)
torture_assert(tctx, strncasecmp_m(NULL, "Foo", 3) != 0, "one NULL");
torture_assert(tctx, strncasecmp_m("foo", NULL, 3) != 0, "other NULL");
torture_assert(tctx, strncasecmp_m(NULL, NULL, 3) == 0, "both NULL");
+ torture_assert(tctx, strncasecmp_m(file_iso8859_1, file_utf8, 6) != 0,
+ "file.{accented e} should differ");
return true;
}
diff --git a/lib/util/charset/util_str.c b/lib/util/charset/util_str.c
index 688ab5a0a1c..d2e6cbbc620 100644
--- a/lib/util/charset/util_str.c
+++ b/lib/util/charset/util_str.c
@@ -47,6 +47,11 @@ _PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
c1 = next_codepoint_handle(iconv_handle, s1, &size1);
c2 = next_codepoint_handle(iconv_handle, s2, &size2);
+ if (c1 == INVALID_CODEPOINT ||
+ c2 == INVALID_CODEPOINT) {
+ return strcasecmp(s1, s2);
+ }
+
s1 += size1;
s2 += size2;
@@ -54,12 +59,6 @@ _PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- if (c1 == INVALID_CODEPOINT ||
- c2 == INVALID_CODEPOINT) {
- /* what else can we do?? */
- return strcasecmp(s1, s2);
- }
-
if (toupper_m(c1) != toupper_m(c2)) {
return c1 - c2;
}
@@ -97,6 +96,26 @@ _PUBLIC_ int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
c1 = next_codepoint_handle(iconv_handle, s1, &size1);
c2 = next_codepoint_handle(iconv_handle, s2, &size2);
+ if (c1 == INVALID_CODEPOINT ||
+ c2 == INVALID_CODEPOINT) {
+ /*
+ * n was specified in characters,
+ * now we must convert it to bytes.
+ * As bytes are the smallest
+ * character unit, the following
+ * increment and strncasecmp is always
+ * safe.
+ *
+ * The source string was already known
+ * to be n characters long, so we are
+ * guaranteed to be able to look at the
+ * (n remaining + size1) bytes from the
+ * s1 position).
+ */
+ n += size1;
+ return strncasecmp(s1, s2, n);
+ }
+
s1 += size1;
s2 += size2;
@@ -104,12 +123,6 @@ _PUBLIC_ int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- if (c1 == INVALID_CODEPOINT ||
- c2 == INVALID_CODEPOINT) {
- /* what else can we do?? */
- return strcasecmp(s1, s2);
- }
-
if (toupper_m(c1) != toupper_m(c2)) {
return c1 - c2;
}
diff --git a/source3/lib/memcache.c b/lib/util/memcache.c
index 88453f32dd8..50e59fc7040 100644
--- a/source3/lib/memcache.c
+++ b/lib/util/memcache.c
@@ -17,8 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "memcache.h"
+#include "replace.h"
+#include <talloc.h>
+#include "../lib/util/samba_util.h"
+#include "../lib/util/debug.h"
+#include "../lib/util/dlinklist.h"
#include "../lib/util/rbtree.h"
+#include "memcache.h"
static struct memcache *global_cache;
@@ -26,7 +31,7 @@ struct memcache_element {
struct rb_node rb_node;
struct memcache_element *prev, *next;
size_t keylength, valuelength;
- uint8 n; /* This is really an enum, but save memory */
+ uint8_t n; /* This is really an enum, but save memory */
char data[1]; /* placeholder for offsetof */
};
@@ -63,7 +68,7 @@ static int memcache_destructor(struct memcache *cache) {
for (e = cache->mru; e != NULL; e = next) {
next = e->next;
- SAFE_FREE(e);
+ TALLOC_FREE(e);
}
return 0;
}
@@ -96,7 +101,7 @@ static struct memcache_element *memcache_node2elem(struct rb_node *node)
static void memcache_element_parse(struct memcache_element *e,
DATA_BLOB *key, DATA_BLOB *value)
{
- key->data = ((uint8 *)e) + offsetof(struct memcache_element, data);
+ key->data = ((uint8_t *)e) + offsetof(struct memcache_element, data);
key->length = e->keylength;
value->data = key->data + e->keylength;
value->length = e->valuelength;
@@ -206,7 +211,7 @@ static void memcache_delete_element(struct memcache *cache,
cache->size -= memcache_element_size(e->keylength, e->valuelength);
- SAFE_FREE(e);
+ TALLOC_FREE(e);
}
static void memcache_trim(struct memcache *cache)
@@ -285,13 +290,12 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
element_size = memcache_element_size(key.length, value.length);
-
- e = (struct memcache_element *)SMB_MALLOC(element_size);
-
+ e = talloc_size(cache, element_size);
if (e == NULL) {
- DEBUG(0, ("malloc failed\n"));
+ DEBUG(0, ("talloc failed\n"));
return;
}
+ talloc_set_type(e, struct memcache_element);
e->n = n;
e->keylength = key.length;
diff --git a/source3/include/memcache.h b/lib/util/memcache.h
index 9362483cea4..11e59718c9f 100644
--- a/source3/include/memcache.h
+++ b/lib/util/memcache.h
@@ -20,8 +20,6 @@
#ifndef __MEMCACHE_H__
#define __MEMCACHE_H__
-#include "includes.h"
-
struct memcache;
/*
diff --git a/lib/util/select.c b/lib/util/select.c
index 5e66344c9da..99cd772bae8 100644
--- a/lib/util/select.c
+++ b/lib/util/select.c
@@ -42,9 +42,19 @@ int sys_poll_intr(struct pollfd *fds, int num_fds, int timeout)
if (errno != EINTR) {
break;
}
+ /* Infinite timeout, no need to adjust. */
+ if (timeout < 0) {
+ continue;
+ }
clock_gettime_mono(&now);
- elapsed = nsec_time_diff(&now, &start);
- timeout = (orig_timeout - elapsed) / 1000000;
+ elapsed = nsec_time_diff(&now, &start) / 1000000;
+ timeout = orig_timeout - elapsed;
+ /* Unlikely, but might happen eg. when getting traced.
+ * Make sure we're not hanging in this case.
+ */
+ if (timeout < 0) {
+ timeout = 0;
+ }
};
return ret;
}
diff --git a/lib/util/string_wrappers.h b/lib/util/string_wrappers.h
index 243fafc27ef..fcc088ca040 100644
--- a/lib/util/string_wrappers.h
+++ b/lib/util/string_wrappers.h
@@ -43,11 +43,6 @@ do { \
const char *_fstrcat_src = (const char *)(s); \
strlcat((d),_fstrcat_src ? _fstrcat_src : "",sizeof(fstring)); \
} while (0)
-#define nstrcpy(d,s) \
-do { \
- const char *_nstrcpy_src = (const char *)(s); \
- strlcpy((d),_nstrcpy_src ? _nstrcpy_src : "",sizeof(fstring)); \
-} while (0)
#define unstrcpy(d,s) \
do { \
const char *_unstrcpy_src = (const char *)(s); \
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 5087116174a..f161f963512 100755
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -8,7 +8,7 @@ bld.SAMBA_LIBRARY('samba-util',
util_strlist.c util_paths.c idtree.c debug.c fault.c base64.c
util_str.c util_str_common.c substitute.c ms_fnmatch.c
server_id.c dprintf.c parmlist.c bitmap.c pidfile.c
- tevent_debug.c util_process.c''',
+ tevent_debug.c util_process.c memcache.c''',
deps='DYNCONFIG',
public_deps='talloc tevent execinfo uid_wrapper pthread LIBCRYPTO charset util_setid systemd-daemon',
public_headers='debug.h attr.h byteorder.h data_blob.h memory.h safe_string.h time.h talloc_stack.h xfile.h dlinklist.h samba_util.h string_wrappers.h',
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
index 7c8d53cf8d4..fb77ede197a 100644
--- a/libcli/auth/credentials.c
+++ b/libcli/auth/credentials.c
@@ -263,6 +263,7 @@ next comes the client specific functions
struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
const char *client_account,
const char *client_computer_name,
+ uint16_t secure_channel_type,
const struct netr_Credential *client_challenge,
const struct netr_Credential *server_challenge,
const struct samr_Password *machine_password,
@@ -277,6 +278,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me
creds->sequence = time(NULL);
creds->negotiate_flags = negotiate_flags;
+ creds->secure_channel_type = secure_channel_type;
creds->computer_name = talloc_strdup(creds, client_computer_name);
if (!creds->computer_name) {
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index 89a732e0525..6bc18d78205 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -26,6 +26,7 @@ next comes the client specific functions
struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
const char *client_account,
const char *client_computer_name,
+ uint16_t secure_channel_type,
const struct netr_Credential *client_challenge,
const struct netr_Credential *server_challenge,
const struct samr_Password *machine_password,
diff --git a/libcli/dns/dns_hosts_file.c b/libcli/dns/dns_hosts_file.c
index 94d1d9704a3..4b1bc531675 100644
--- a/libcli/dns/dns_hosts_file.c
+++ b/libcli/dns/dns_hosts_file.c
@@ -88,9 +88,14 @@ static bool getdns_hosts_fileent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, cha
if (next_token_talloc(ctx, &ptr, &name_type, NULL))
++count;
+ if (count == 0) {
+ continue;
+ }
if (next_token_talloc(ctx, &ptr, &name, NULL))
++count;
- if (name_type && strcasecmp(name_type, "A") == 0) {
+ if ((strcasecmp(name_type, "A") == 0) ||
+ (strcasecmp(name_type, "AAAA") == 0))
+ {
if (next_token_talloc(ctx, &ptr, &ip, NULL))
++count;
} else if (name_type && strcasecmp(name_type, "SRV") == 0) {
@@ -101,13 +106,18 @@ static bool getdns_hosts_fileent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, cha
} else if (name_type && strcasecmp(name_type, "CNAME") == 0) {
if (next_token_talloc(ctx, &ptr, &next_name, NULL))
++count;
+ } else if (name_type && strcasecmp(name_type, "NS") == 0) {
+ if (next_token_talloc(ctx, &ptr, &next_name, NULL))
+ ++count;
}
if (count <= 0)
continue;
- if (strcasecmp(name_type, "A") == 0) {
+ if ((strcasecmp(name_type, "A") == 0) ||
+ (strcasecmp(name_type, "AAAA") == 0))
+ {
if (count != 3) {
- DEBUG(0,("getdns_hosts_fileent: Ill formed hosts A record [%s]\n",
+ DEBUG(0,("getdns_hosts_fileent: Ill formed hosts A[AAA] record [%s]\n",
line));
continue;
}
@@ -148,6 +158,15 @@ static bool getdns_hosts_fileent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, cha
if (!*pp_next_name) {
return false;
}
+ } else if (strcasecmp(name_type, "NS") == 0) {
+ if (count != 3) {
+ DEBUG(0,("getdns_hosts_fileent: Ill formed hosts NS record [%s]\n",
+ line));
+ continue;
+ }
+ DEBUG(4, ("getdns_hosts_fileent: NS entry: %s %s %s\n",
+ name_type, name, next_name));
+ continue;
} else {
DEBUG(0,("getdns_hosts_fileent: unknown type %s\n", name_type));
continue;
@@ -215,7 +234,7 @@ static NTSTATUS resolve_dns_hosts_file_as_dns_rr_recurse(const char *dns_hosts_f
DEBUG(3,("resolve_dns_hosts: (%d) "
"Attempting %s dns_hosts lookup for name %s\n",
- level, srv_lookup ? "SRV" : "A", name));
+ level, srv_lookup ? "SRV" : "A[AAA]", name));
fp = startdns_hosts_file(dns_hosts_file);
@@ -278,7 +297,9 @@ static NTSTATUS resolve_dns_hosts_file_as_dns_rr_recurse(const char *dns_hosts_f
mem_ctx, return_rr, return_count);
talloc_free(ip_list_ctx);
return status;
- } else if (strcasecmp(name_type, "A") == 0) {
+ } else if ((strcasecmp(name_type, "A") == 0) ||
+ (strcasecmp(name_type, "AAAA") == 0))
+ {
if (*return_count == 0) {
/* We are happy to keep looking for other possible A record matches */
rr = talloc_zero(ip_list_ctx,
@@ -405,11 +426,11 @@ NTSTATUS resolve_dns_hosts_file_as_dns_rr(const char *dns_hosts_file,
if (NT_STATUS_IS_OK(status)) {
DEBUG(3,("resolve_dns_hosts (dns_rr): "
"Found %d %s result records for for name %s\n",
- *return_count, srv_lookup ? "SRV" : "A", name));
+ *return_count, srv_lookup ? "SRV" : "A[AAA]", name));
} else {
DEBUG(3,("resolve_dns_hosts (dns_rr): "
"failed to obtain %s result records for for name %s: %s\n",
- srv_lookup ? "SRV" : "A", name, nt_errstr(status)));
+ srv_lookup ? "SRV" : "A[AAA]", name, nt_errstr(status)));
}
return status;
}
diff --git a/libcli/security/secdesc.c b/libcli/security/secdesc.c
index 8570334f36c..62207a00845 100644
--- a/libcli/security/secdesc.c
+++ b/libcli/security/secdesc.c
@@ -24,13 +24,6 @@
#include "librpc/gen_ndr/ndr_security.h"
#include "libcli/security/security.h"
-#define ALL_SECURITY_INFORMATION (SECINFO_OWNER|SECINFO_GROUP|\
- SECINFO_DACL|SECINFO_SACL|\
- SECINFO_UNPROTECTED_SACL|\
- SECINFO_UNPROTECTED_DACL|\
- SECINFO_PROTECTED_SACL|\
- SECINFO_PROTECTED_DACL)
-
/* Map generic permissions to file object specific permissions */
const struct generic_mapping file_generic_mapping = {
@@ -46,21 +39,32 @@ const struct generic_mapping file_generic_mapping = {
uint32_t get_sec_info(const struct security_descriptor *sd)
{
- uint32_t sec_info = ALL_SECURITY_INFORMATION;
+ uint32_t sec_info = 0;
SMB_ASSERT(sd);
- if (sd->owner_sid == NULL) {
- sec_info &= ~SECINFO_OWNER;
+ if (sd->owner_sid != NULL) {
+ sec_info |= SECINFO_OWNER;
+ }
+ if (sd->group_sid != NULL) {
+ sec_info |= SECINFO_GROUP;
}
- if (sd->group_sid == NULL) {
- sec_info &= ~SECINFO_GROUP;
+ if (sd->sacl != NULL) {
+ sec_info |= SECINFO_SACL;
}
- if (sd->sacl == NULL) {
- sec_info &= ~SECINFO_SACL;
+ if (sd->dacl != NULL) {
+ sec_info |= SECINFO_DACL;
+ }
+
+ if (sd->type & SEC_DESC_SACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_SACL;
+ } else if (sd->type & SEC_DESC_SACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_SACL;
}
- if (sd->dacl == NULL) {
- sec_info &= ~SECINFO_DACL;
+ if (sd->type & SEC_DESC_DACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_DACL;
+ } else if (sd->type & SEC_DESC_DACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_DACL;
}
return sec_info;
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl
index 381d6e5632e..eb80a869b0d 100644
--- a/librpc/idl/security.idl
+++ b/librpc/idl/security.idl
@@ -630,6 +630,24 @@ interface security
SECINFO_PROTECTED_DACL = 0x80000000
} security_secinfo;
+ /*
+ * a SMB server should only support the following flags
+ * and ignore all others.
+ *
+ * See AdditionalInformation in [MS-SMB2] 2.2.37 SMB2 QUERY_INFO Request
+ * and 2.2.39 SMB2 SET_INFO Request.
+ */
+ const int SMB_SUPPORTED_SECINFO_FLAGS = (
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL |
+ SECINFO_SACL |
+ SECINFO_LABEL |
+ SECINFO_ATTRIBUTE |
+ SECINFO_SCOPE |
+ SECINFO_BACKUP |
+ 0);
+
typedef [public,bitmap32bit] bitmap {
KERB_ENCTYPE_DES_CBC_CRC = 0x00000001,
KERB_ENCTYPE_DES_CBC_MD5 = 0x00000002,
diff --git a/python/samba/join.py b/python/samba/join.py
index 7d2f913b571..ee973a1bd8c 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -133,7 +133,7 @@ class dc_join(object):
else:
ctx.dns_backend = dns_backend
- ctx.dnshostname = "%s.%s" % (ctx.myname, ctx.dnsdomain)
+ ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
ctx.realm = ctx.dnsdomain
@@ -1198,7 +1198,7 @@ def join_subdomain(server=None, creds=None, lp=None, site=None,
ctx.base_dn = samba.dn_from_dns_name(dnsdomain)
ctx.domsid = str(security.random_sid())
ctx.acct_dn = None
- ctx.dnshostname = "%s.%s" % (ctx.myname, ctx.dnsdomain)
+ ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
ctx.trustdom_pass = samba.generate_random_password(128, 128)
ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py
index 53f10826080..ce4a46a8ecc 100644
--- a/python/samba/provision/sambadns.py
+++ b/python/samba/provision/sambadns.py
@@ -125,6 +125,7 @@ class SOARecord(dnsp.DnssrvRpcRecord):
soa.expire = expire
soa.mname = mname
soa.rname = rname
+ soa.minimum = minimum
self.data = soa
diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py
index 59d6eee7618..e2c666727d0 100644
--- a/python/samba/tests/dcerpc/dnsserver.py
+++ b/python/samba/tests/dcerpc/dnsserver.py
@@ -19,7 +19,7 @@
from samba.dcerpc import dnsp, dnsserver
from samba.tests import RpcInterfaceTestCase, env_get_var_value
-from samba.netcmd.dns import ARecord
+from samba.netcmd.dns import ARecord, NSRecord
class DnsserverTests(RpcInterfaceTestCase):
@@ -239,3 +239,42 @@ class DnsserverTests(RpcInterfaceTestCase):
select_flags,
None,
None)
+
+ def test_updaterecords2_soa(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ record_type = dnsp.DNS_TYPE_NS
+ select_flags = (dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA |
+ dnsserver.DNS_RPC_VIEW_NO_CHILDREN)
+
+ nameserver = 'ns.example.local'
+ rec = NSRecord(nameserver)
+
+ # Add record
+ add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ add_rec_buf.rec = rec
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ '.',
+ add_rec_buf,
+ None)
+
+ buflen, result = self.conn.DnssrvEnumRecords2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ '@',
+ None,
+ record_type,
+ select_flags,
+ None,
+ None)
+ self.assertEquals(1, result.count)
+ self.assertEquals(2, result.rec[0].wRecordCount)
+ match = False
+ for i in range(2):
+ self.assertEquals(dnsp.DNS_TYPE_NS, result.rec[0].records[i].wType)
+ if result.rec[0].records[i].data.str.rstrip('.') == nameserver:
+ match = True
+ self.assertEquals(match, True)
diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
index 79e4158b67b..2983de34ac5 100644
--- a/python/samba/tests/dns.py
+++ b/python/samba/tests/dns.py
@@ -289,6 +289,7 @@ class TestSimpleQueries(DNSTest):
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
self.assertEquals(response.ancount, 1)
+ self.assertEquals(response.answers[0].rdata.minimum, 3600)
class TestDNSUpdates(DNSTest):
diff --git a/selftest/README b/selftest/README
index c23d730d640..d9ad0202683 100644
--- a/selftest/README
+++ b/selftest/README
@@ -89,6 +89,7 @@ The environments are currently available include
* REALM: Realm name
* SERVER: DC host name
* SERVER_IP: DC IPv4 address
+ * SERVER_IPV6: DC IPv6 address
* NETBIOSNAME: DC NetBIOS name
* NETIOSALIAS: DC NetBIOS alias
diff --git a/selftest/knownfail b/selftest/knownfail
index 3768f8233fc..c493dbac4ed 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -106,6 +106,7 @@
^samba4.rpc.netlogon.*.GetTrustPasswords
^samba4.rpc.netlogon.*.DatabaseRedo
^samba4.rpc.netlogon.*.ServerGetTrustInfo
+^samba4.rpc.netlogon.*.invalidAuthenticate2
^samba4.rpc.samr.passwords.badpwdcount # Not provided by Samba 4 yet
^samba4.rpc.samr.passwords.lockout
^samba4.base.charset.*.Testing partial surrogate
diff --git a/selftest/selftest.pl b/selftest/selftest.pl
index 2b1e3ce4b08..25e0f936e04 100755
--- a/selftest/selftest.pl
+++ b/selftest/selftest.pl
@@ -663,35 +663,41 @@ my @exported_envvars = (
# domain controller stuff
"DC_SERVER",
"DC_SERVER_IP",
+ "DC_SERVER_IPV6",
"DC_NETBIOSNAME",
"DC_NETBIOSALIAS",
# domain member
"MEMBER_SERVER",
"MEMBER_SERVER_IP",
+ "MEMBER_SERVER_IPV6",
"MEMBER_NETBIOSNAME",
"MEMBER_NETBIOSALIAS",
# rpc proxy controller stuff
"RPC_PROXY_SERVER",
"RPC_PROXY_SERVER_IP",
+ "RPC_PROXY_SERVER_IPV6",
"RPC_PROXY_NETBIOSNAME",
"RPC_PROXY_NETBIOSALIAS",
# domain controller stuff for Vampired DC
"VAMPIRE_DC_SERVER",
"VAMPIRE_DC_SERVER_IP",
+ "VAMPIRE_DC_SERVER_IPV6",
"VAMPIRE_DC_NETBIOSNAME",
"VAMPIRE_DC_NETBIOSALIAS",
"PROMOTED_DC_SERVER",
"PROMOTED_DC_SERVER_IP",
+ "PROMOTED_DC_SERVER_IPV6",
"PROMOTED_DC_NETBIOSNAME",
"PROMOTED_DC_NETBIOSALIAS",
# server stuff
"SERVER",
"SERVER_IP",
+ "SERVER_IPV6",
"NETBIOSNAME",
"NETBIOSALIAS",
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index bc07403dcc4..ba01154e524 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -207,6 +207,7 @@ sub setup_s3dc($$)
$vars->{DC_SERVER} = $vars->{SERVER};
$vars->{DC_SERVER_IP} = $vars->{SERVER_IP};
+ $vars->{DC_SERVER_IPV6} = $vars->{SERVER_IPV6};
$vars->{DC_NETBIOSNAME} = $vars->{NETBIOSNAME};
$vars->{DC_USERNAME} = $vars->{USERNAME};
$vars->{DC_PASSWORD} = $vars->{PASSWORD};
@@ -250,6 +251,7 @@ sub setup_member($$$)
$ret->{DC_SERVER} = $s3dcvars->{SERVER};
$ret->{DC_SERVER_IP} = $s3dcvars->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $s3dcvars->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $s3dcvars->{NETBIOSNAME};
$ret->{DC_USERNAME} = $s3dcvars->{USERNAME};
$ret->{DC_PASSWORD} = $s3dcvars->{PASSWORD};
@@ -321,6 +323,7 @@ sub setup_admember($$$$)
$ret->{DC_SERVER} = $dcvars->{SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{PASSWORD};
@@ -400,6 +403,7 @@ sub setup_admember_rfc2307($$$$)
$ret->{DC_SERVER} = $dcvars->{SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{PASSWORD};
@@ -770,6 +774,7 @@ sub provision($$$$$$)
my $swiface = Samba::get_interface($server);
my %ret = ();
my $server_ip = "127.0.0.$swiface";
+ my $server_ipv6 = sprintf("fd00:0000:0000:0000:0000:0000:5357:5f%02x", $swiface);
my $domain = "SAMBA-TEST";
my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
@@ -872,7 +877,7 @@ sub provision($$$$$$)
close(MSDFS_TARGET);
chmod 0666, $msdfs_target;
symlink "msdfs:$server_ip\\ro-tmp", "$msdfs_shrdir/msdfs-src1";
- symlink "msdfs:$server_ip\\ro-tmp", "$msdfs_shrdir/deeppath/msdfs-src2";
+ symlink "msdfs:$server_ipv6\\ro-tmp", "$msdfs_shrdir/deeppath/msdfs-src2";
my $conffile="$libdir/server.conf";
@@ -925,7 +930,7 @@ sub provision($$$$$$)
print CONF "
[global]
netbios name = $server
- interfaces = $server_ip/8
+ interfaces = $server_ip/8 $server_ipv6/64
bind interfaces only = yes
panic action = $self->{srcdir}/selftest/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
smbd:suicide mode = yes
@@ -1176,14 +1181,16 @@ domadmins:X:$gid_domadmins:
print "DONE\n";
open(DNS_UPDATE_LIST, ">$prefix/dns_update_list") or die("Unable to open $$prefix/dns_update_list");
- print DNS_UPDATE_LIST "A $server. $server_ip";
+ print DNS_UPDATE_LIST "A $server. $server_ip\n";
+ print DNS_UPDATE_LIST "AAAA $server. $server_ipv6\n";
close(DNS_UPDATE_LIST);
- if (system("$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate --all-interfaces --use-file=$dns_host_file -s $conffile --update-list=$prefix/dns_update_list --no-substiutions --no-credentials") != 0) {
+ if (system("$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate --all-interfaces --use-file=$dns_host_file -s $conffile --update-list=$prefix/dns_update_list --update-cache=$prefix/dns_update_cache --no-substiutions --no-credentials") != 0) {
die "Unable to update hostname into $dns_host_file";
}
$ret{SERVER_IP} = $server_ip;
+ $ret{SERVER_IPV6} = $server_ipv6;
$ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
$ret{NMBD_TEST_LOG_POS} = 0;
$ret{WINBINDD_TEST_LOG} = "$prefix/winbindd_test.log";
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 8a3f51d3614..ac2fdd97c5e 100644
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -516,7 +516,8 @@ sub provision_raw_prepare($$$$$$$$$$)
$ctx->{tlsdir} = "$ctx->{privatedir}/tls";
$ctx->{ipv4} = "127.0.0.$swiface";
- $ctx->{interfaces} = "$ctx->{ipv4}/8";
+ $ctx->{ipv6} = sprintf("fd00:0000:0000:0000:0000:0000:5357:5f%02x", $swiface);
+ $ctx->{interfaces} = "$ctx->{ipv4}/8 $ctx->{ipv6}/64";
push(@{$ctx->{directories}}, $ctx->{privatedir});
push(@{$ctx->{directories}}, $ctx->{etcdir});
@@ -691,6 +692,7 @@ nogroup:x:65534:nobody
PIDDIR => $ctx->{piddir},
SERVER => $ctx->{hostname},
SERVER_IP => $ctx->{ipv4},
+ SERVER_IPV6 => $ctx->{ipv6},
NETBIOSNAME => $ctx->{netbiosname},
DOMAIN => $ctx->{domain},
USERNAME => $ctx->{username},
@@ -914,12 +916,14 @@ sub provision_member($$$)
$ret->{MEMBER_SERVER} = $ret->{SERVER};
$ret->{MEMBER_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{MEMBER_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{MEMBER_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{MEMBER_USERNAME} = $ret->{USERNAME};
$ret->{MEMBER_PASSWORD} = $ret->{PASSWORD};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1006,12 +1010,14 @@ sub provision_rpc_proxy($$$)
$ret->{RPC_PROXY_SERVER} = $ret->{SERVER};
$ret->{RPC_PROXY_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{RPC_PROXY_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{RPC_PROXY_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{RPC_PROXY_USERNAME} = $ret->{USERNAME};
$ret->{RPC_PROXY_PASSWORD} = $ret->{PASSWORD};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1082,10 +1088,12 @@ sub provision_promoted_dc($$$)
$ret->{PROMOTED_DC_SERVER} = $ret->{SERVER};
$ret->{PROMOTED_DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{PROMOTED_DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{PROMOTED_DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1143,10 +1151,12 @@ sub provision_vampire_dc($$$)
$ret->{VAMPIRE_DC_SERVER} = $ret->{SERVER};
$ret->{VAMPIRE_DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{VAMPIRE_DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{VAMPIRE_DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1208,10 +1218,12 @@ sub provision_subdom_dc($$$)
$ret->{SUBDOM_DC_SERVER} = $ret->{SERVER};
$ret->{SUBDOM_DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{SUBDOM_DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{SUBDOM_DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1242,6 +1254,7 @@ sub provision_dc($$)
$ret->{NETBIOSALIAS} = "localdc1-a";
$ret->{DC_SERVER} = $ret->{SERVER};
$ret->{DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_USERNAME} = $ret->{USERNAME};
$ret->{DC_PASSWORD} = $ret->{PASSWORD};
@@ -1385,10 +1398,12 @@ sub provision_rodc($$$)
$ret->{RODC_DC_SERVER} = $ret->{SERVER};
$ret->{RODC_DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{RODC_DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{RODC_DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
@@ -1503,6 +1518,7 @@ sub provision_plugin_s4_dc($$)
$ret->{DC_SERVER} = $ret->{SERVER};
$ret->{DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_USERNAME} = $ret->{USERNAME};
$ret->{DC_PASSWORD} = $ret->{PASSWORD};
@@ -1542,6 +1558,7 @@ sub provision_chgdcpass($$)
$ret->{DC_SERVER} = $ret->{SERVER};
$ret->{DC_SERVER_IP} = $ret->{SERVER_IP};
+ $ret->{DC_SERVER_IPV6} = $ret->{SERVER_IPV6};
$ret->{DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
$ret->{DC_USERNAME} = $ret->{USERNAME};
$ret->{DC_PASSWORD} = $ret->{PASSWORD};
diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
index be44ce949d9..039387f4232 100644
--- a/source3/auth/token_util.c
+++ b/source3/auth/token_util.c
@@ -28,7 +28,7 @@
#include "system/passwd.h"
#include "auth.h"
#include "secrets.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "../librpc/gen_ndr/netlogon.h"
#include "../libcli/security/security.h"
#include "../lib/util/util_pw.h"
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 1b22a5770cc..e8434f2b2ef 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -322,14 +322,6 @@ struct stat_ex {
uint32_t st_ex_flags;
uint32_t st_ex_mask;
-
- /*
- * Add space for VFS internal extensions. The initial user of this
- * would be the onefs modules, passing the snapid from the stat calls
- * to the file_id_create call. Maybe we'll have to expand this later,
- * but the core of Samba should never look at this field.
- */
- uint64_t vfs_private;
};
typedef struct stat_ex SMB_STRUCT_STAT;
diff --git a/source3/include/proto.h b/source3/include/proto.h
index a42faf8148b..cbad7ac36a2 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1357,6 +1357,7 @@ int lp_smb_encrypt(int );
char lp_magicchar(const struct share_params *p );
int lp_winbind_cache_time(void);
int lp_winbind_reconnect_delay(void);
+int lp_winbind_request_timeout(void);
int lp_winbind_max_clients(void);
const char **lp_winbind_nss_info(void);
int lp_algorithmic_rid_base(void);
diff --git a/source3/lib/access.c b/source3/lib/access.c
index 044c079cc5e..b664dc83c56 100644
--- a/source3/lib/access.c
+++ b/source3/lib/access.c
@@ -11,7 +11,7 @@
*/
#include "includes.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "lib/socket/interfaces.h"
#define NAME_INDEX 0
diff --git a/source3/lib/id_cache.c b/source3/lib/id_cache.c
index e6e345741c1..3a703ae4af3 100644
--- a/source3/lib/id_cache.c
+++ b/source3/lib/id_cache.c
@@ -28,7 +28,7 @@
#include "includes.h"
#include "messages.h"
#include "lib/id_cache.h"
-#include "include/memcache.h"
+#include "../lib/util/memcache.h"
#include "idmap_cache.h"
#include "../librpc/gen_ndr/ndr_security.h"
#include "../libcli/security/dom_sid.h"
diff --git a/source3/lib/username.c b/source3/lib/username.c
index 665fbb42536..d44db7518df 100644
--- a/source3/lib/username.c
+++ b/source3/lib/username.c
@@ -21,7 +21,7 @@
#include "includes.h"
#include "system/passwd.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "../lib/util/util_pw.h"
/* internal functions */
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index 54286b3f311..22ba764d13c 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -21,7 +21,7 @@
#include "includes.h"
#include "system/filesys.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "../lib/async_req/async_sock.h"
#include "../lib/util/select.h"
#include "lib/socket/interfaces.h"
diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl
index 686bc02548a..42ecb02210b 100644
--- a/source3/librpc/idl/open_files.idl
+++ b/source3/librpc/idl/open_files.idl
@@ -77,7 +77,6 @@ interface open_files
hyper st_ex_blocks;
uint32 st_ex_flags;
uint32 st_ex_mask;
- hyper vfs_private;
} vfs_default_durable_stat;
typedef [public] struct {
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index ff48719c76b..840084f8b6d 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -280,13 +280,15 @@ static NTSTATUS do_connect(TALLOC_CTX *ctx,
static void cli_set_mntpoint(struct cli_state *cli, const char *mnt)
{
- char *name = clean_name(NULL, mnt);
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *name = clean_name(frame, mnt);
if (!name) {
+ TALLOC_FREE(frame);
return;
}
TALLOC_FREE(cli->dfs_mountpoint);
cli->dfs_mountpoint = talloc_strdup(cli, name);
- TALLOC_FREE(name);
+ TALLOC_FREE(frame);
}
/********************************************************************
diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
index 517753d5314..d4254dadac8 100644
--- a/source3/libsmb/libsmb_server.c
+++ b/source3/libsmb/libsmb_server.c
@@ -459,6 +459,11 @@ SMBC_server_internal(TALLOC_CTX *ctx,
return NULL;
}
+ if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
+ /* Ensure we ask for some initial credits. */
+ smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS);
+ }
+
username_used = *pp_username;
if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 7fda4b82271..ed14c673b51 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1530,6 +1530,18 @@ static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
#else
#error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
#endif
+ if (result == 0) {
+ /*
+ * Some file systems do not allocate a block for very
+ * small files. But for non-empty file should report a
+ * positive size.
+ */
+
+ uint64_t filesize = get_file_size_stat(sbuf);
+ if (filesize > 0) {
+ result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
+ }
+ }
#else
result = get_file_size_stat(sbuf);
#endif
diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c
index 98109c280bf..d6b33941fad 100644
--- a/source3/modules/vfs_dirsort.c
+++ b/source3/modules/vfs_dirsort.c
@@ -256,7 +256,7 @@ static void dirsort_seekdir(vfs_handle_struct *handle, DIR *dirp,
if (data == NULL) {
return;
}
- if (offset > data->number_of_entries) {
+ if (offset >= data->number_of_entries) {
return;
}
data->pos = offset;
diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
index 4a53bf84e55..f9eb7e86b12 100644
--- a/source3/modules/vfs_gpfs.c
+++ b/source3/modules/vfs_gpfs.c
@@ -1444,7 +1444,6 @@ static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
smb_fname->st.st_ex_calculated_birthtime = false;
smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
- smb_fname->st.vfs_private = attrs.winAttrs;
}
return 0;
}
@@ -1512,7 +1511,6 @@ static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
smb_fname->st.st_ex_calculated_birthtime = false;
smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
- smb_fname->st.vfs_private = attrs.winAttrs;
}
return 0;
}
@@ -1636,6 +1634,7 @@ static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
char *path = NULL;
NTSTATUS status;
struct gpfs_config_data *config;
+ int ret;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct gpfs_config_data,
@@ -1651,17 +1650,12 @@ static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
return -1;
}
- if (VALID_STAT(*sbuf)) {
- attrs.winAttrs = sbuf->vfs_private;
- } else {
- int ret;
- ret = get_gpfs_winattrs(path, &attrs);
-
- if (ret == -1) {
- TALLOC_FREE(path);
- return false;
- }
+ ret = get_gpfs_winattrs(path, &attrs);
+ if (ret == -1) {
+ TALLOC_FREE(path);
+ return false;
}
+
if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
DEBUG(10, ("%s is offline\n", path));
TALLOC_FREE(path);
@@ -1682,7 +1676,8 @@ static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
files_struct *fsp, const DATA_BLOB *hdr,
off_t offset, size_t n)
{
- if ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0) {
+ if (SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name, &fsp->fsp_name->st))
+ {
errno = ENOSYS;
return -1;
}
@@ -1953,15 +1948,14 @@ static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
void *data, size_t n, off_t offset)
{
ssize_t ret;
+ bool was_offline;
- ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
+ &fsp->fsp_name->st);
- DEBUG(10, ("vfs_private = %x\n",
- (unsigned int)fsp->fsp_name->st.vfs_private));
+ ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
- if ((ret != -1) &&
- ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0)) {
- fsp->fsp_name->st.vfs_private &= ~GPFS_WINATTR_OFFLINE;
+ if ((ret != -1) && was_offline) {
notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
fsp->fsp_name->base_name);
@@ -1974,6 +1968,7 @@ struct vfs_gpfs_pread_state {
struct files_struct *fsp;
ssize_t ret;
int err;
+ bool was_offline;
};
static void vfs_gpfs_pread_done(struct tevent_req *subreq);
@@ -1992,6 +1987,8 @@ static struct tevent_req *vfs_gpfs_pread_send(struct vfs_handle_struct *handle,
if (req == NULL) {
return NULL;
}
+ state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
+ &fsp->fsp_name->st);
state->fsp = fsp;
subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
n, offset);
@@ -2025,12 +2022,7 @@ static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req, int *err)
}
*err = state->err;
- DEBUG(10, ("vfs_private = %x\n",
- (unsigned int)fsp->fsp_name->st.vfs_private));
-
- if ((state->ret != -1) &&
- ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0)) {
- fsp->fsp_name->st.vfs_private &= ~GPFS_WINATTR_OFFLINE;
+ if ((state->ret != -1) && state->was_offline) {
DEBUG(10, ("sending notify\n"));
notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
@@ -2044,15 +2036,14 @@ static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
const void *data, size_t n, off_t offset)
{
ssize_t ret;
+ bool was_offline;
- ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
+ &fsp->fsp_name->st);
- DEBUG(10, ("vfs_private = %x\n",
- (unsigned int)fsp->fsp_name->st.vfs_private));
+ ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
- if ((ret != -1) &&
- ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0)) {
- fsp->fsp_name->st.vfs_private &= ~GPFS_WINATTR_OFFLINE;
+ if ((ret != -1) && was_offline) {
notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
fsp->fsp_name->base_name);
@@ -2065,6 +2056,7 @@ struct vfs_gpfs_pwrite_state {
struct files_struct *fsp;
ssize_t ret;
int err;
+ bool was_offline;
};
static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
@@ -2084,6 +2076,8 @@ static struct tevent_req *vfs_gpfs_pwrite_send(
if (req == NULL) {
return NULL;
}
+ state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
+ &fsp->fsp_name->st);
state->fsp = fsp;
subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
n, offset);
@@ -2117,12 +2111,7 @@ static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
}
*err = state->err;
- DEBUG(10, ("vfs_private = %x\n",
- (unsigned int)fsp->fsp_name->st.vfs_private));
-
- if ((state->ret != -1) &&
- ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0)) {
- fsp->fsp_name->st.vfs_private &= ~GPFS_WINATTR_OFFLINE;
+ if ((state->ret != -1) && state->was_offline) {
DEBUG(10, ("sending notify\n"));
notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index a339a1db52e..4b31023cd7c 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -978,6 +978,7 @@ static void init_globals(bool reinit_globals)
Globals.winbind_cache_time = 300; /* 5 minutes */
Globals.winbind_reconnect_delay = 30; /* 30 seconds */
+ Globals.winbind_request_timeout = 60; /* 60 seconds */
Globals.winbind_max_clients = 200;
Globals.bWinbindEnumUsers = false;
Globals.bWinbindEnumGroups = false;
diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
index 6ec6ce8e47e..e4d41c44dcb 100644
--- a/source3/passdb/lookup_sid.c
+++ b/source3/passdb/lookup_sid.c
@@ -23,7 +23,7 @@
#include "passdb.h"
#include "../librpc/gen_ndr/ndr_security.h"
#include "secrets.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "idmap_cache.h"
#include "../libcli/security/security.h"
#include "lib/winbind_util.h"
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
index ea67e2faf51..d9e7bb531df 100644
--- a/source3/passdb/pdb_interface.c
+++ b/source3/passdb/pdb_interface.c
@@ -29,7 +29,7 @@
#include "../librpc/gen_ndr/drsblobs.h"
#include "../librpc/gen_ndr/ndr_drsblobs.h"
#include "../librpc/gen_ndr/idmap.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "nsswitch/winbind_client.h"
#include "../libcli/security/security.h"
#include "../lib/util/util_pw.h"
diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
index 4cd7a4b6cdc..49b7cf0a63e 100644
--- a/source3/passdb/pdb_samba_dsdb.c
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -882,7 +882,7 @@ static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m, GROUP_MAP *map
{
struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
m->private_data, struct pdb_samba_dsdb_state);
- const char *attrs[] = { "objectSid", "description", "samAccountName", "groupType",
+ const char *attrs[] = { "objectClass", "objectSid", "description", "samAccountName", "groupType",
NULL };
struct ldb_message *msg;
va_list ap;
@@ -941,15 +941,13 @@ static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m, GROUP_MAP *map
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- map->sid_name_use = SID_NAME_DOM_GRP;
-
ZERO_STRUCT(id_map);
id_map.sid = sid;
id_maps[0] = &id_map;
id_maps[1] = NULL;
status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
- talloc_free(tmp_ctx);
+
if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
return status;
diff --git a/source3/printing/load.c b/source3/printing/load.c
index 136d055088f..238998d920d 100644
--- a/source3/printing/load.c
+++ b/source3/printing/load.c
@@ -65,11 +65,11 @@ load automatic printer services from pre-populated pcap cache
void load_printers(struct tevent_context *ev,
struct messaging_context *msg_ctx)
{
- SMB_ASSERT(pcap_cache_loaded());
+ SMB_ASSERT(pcap_cache_loaded(NULL));
add_auto_printers();
/* load all printcap printers */
if (lp_load_printers() && lp_servicenumber(PRINTERS_NAME) >= 0)
- pcap_printer_fn(lp_add_one_printer, NULL);
+ pcap_printer_read_fn(lp_add_one_printer, NULL);
}
diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c
index dd7ba624590..c5524ad53db 100644
--- a/source3/printing/pcap.c
+++ b/source3/printing/pcap.c
@@ -83,28 +83,26 @@ void pcap_cache_destroy_specific(struct pcap_cache **pp_cache)
*pp_cache = NULL;
}
-bool pcap_cache_add(const char *name, const char *comment, const char *location)
-{
- NTSTATUS status;
- time_t t = time_mono(NULL);
-
- status = printer_list_set_printer(talloc_tos(), name, comment, location, t);
- return NT_STATUS_IS_OK(status);
-}
-
-bool pcap_cache_loaded(void)
+bool pcap_cache_loaded(time_t *_last_change)
{
NTSTATUS status;
time_t last;
status = printer_list_get_last_refresh(&last);
- return NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ if (_last_change != NULL) {
+ *_last_change = last;
+ }
+ return true;
}
bool pcap_cache_replace(const struct pcap_cache *pcache)
{
const struct pcap_cache *p;
NTSTATUS status;
+ time_t t = time_mono(NULL);
status = printer_list_mark_reload();
if (!NT_STATUS_IS_OK(status)) {
@@ -113,7 +111,11 @@ bool pcap_cache_replace(const struct pcap_cache *pcache)
}
for (p = pcache; p; p = p->next) {
- pcap_cache_add(p->name, p->comment, p->location);
+ status = printer_list_set_printer(talloc_tos(), p->name,
+ p->comment, p->location, t);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
}
status = printer_list_clean_old();
@@ -132,8 +134,8 @@ void pcap_cache_reload(struct tevent_context *ev,
{
const char *pcap_name = lp_printcapname();
bool pcap_reloaded = False;
- NTSTATUS status;
bool post_cache_fill_fn_handled = false;
+ struct pcap_cache *pcache = NULL;
DEBUG(3, ("reloading printcap cache\n"));
@@ -143,12 +145,6 @@ void pcap_cache_reload(struct tevent_context *ev,
return;
}
- status = printer_list_mark_reload();
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to mark printer list for reload!\n"));
- return;
- }
-
#ifdef HAVE_CUPS
if (strequal(pcap_name, "cups")) {
pcap_reloaded = cups_cache_reload(ev, msg_ctx,
@@ -164,26 +160,26 @@ void pcap_cache_reload(struct tevent_context *ev,
#ifdef HAVE_IPRINT
if (strequal(pcap_name, "iprint")) {
- pcap_reloaded = iprint_cache_reload();
+ pcap_reloaded = iprint_cache_reload(&pcache);
goto done;
}
#endif
#if defined(SYSV) || defined(HPUX)
if (strequal(pcap_name, "lpstat")) {
- pcap_reloaded = sysv_cache_reload();
+ pcap_reloaded = sysv_cache_reload(&pcache);
goto done;
}
#endif
#ifdef AIX
if (strstr_m(pcap_name, "/qconfig") != NULL) {
- pcap_reloaded = aix_cache_reload();
+ pcap_reloaded = aix_cache_reload(&pcache);
goto done;
}
#endif
- pcap_reloaded = std_pcap_cache_reload(pcap_name);
+ pcap_reloaded = std_pcap_cache_reload(pcap_name, &pcache);
done:
DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error"));
@@ -192,14 +188,16 @@ done:
/* cleanup old entries only if the operation was successful,
* otherwise keep around the old entries until we can
* successfully reload */
- status = printer_list_clean_old();
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to cleanup printer list!\n"));
+
+ if (!pcap_cache_replace(pcache)) {
+ DEBUG(0, ("Failed to replace printer list!\n"));
}
+
if (post_cache_fill_fn != NULL) {
post_cache_fill_fn(ev, msg_ctx);
}
}
+ pcap_cache_destroy_specific(&pcache);
return;
}
@@ -229,11 +227,11 @@ void pcap_printer_fn_specific(const struct pcap_cache *pc,
return;
}
-void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *pdata)
+void pcap_printer_read_fn(void (*fn)(const char *, const char *, const char *, void *), void *pdata)
{
NTSTATUS status;
- status = printer_list_run_fn(fn, pdata);
+ status = printer_list_read_run_fn(fn, pdata);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Failed to run fn for all printers!\n"));
}
diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h
index 70562137ac8..8fc9e9de31c 100644
--- a/source3/printing/pcap.h
+++ b/source3/printing/pcap.h
@@ -35,11 +35,10 @@ struct pcap_cache;
bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location);
void pcap_cache_destroy_specific(struct pcap_cache **ppcache);
-bool pcap_cache_add(const char *name, const char *comment, const char *location);
-bool pcap_cache_loaded(void);
+bool pcap_cache_loaded(time_t *_last_change);
bool pcap_cache_replace(const struct pcap_cache *cache);
void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, void *), void *);
-void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *);
+void pcap_printer_read_fn(void (*fn)(const char *, const char *, const char *, void *), void *);
void pcap_cache_reload(struct tevent_context *ev,
struct messaging_context *msg_ctx,
@@ -49,7 +48,7 @@ bool pcap_printername_ok(const char *printername);
/* The following definitions come from printing/print_aix.c */
-bool aix_cache_reload(void);
+bool aix_cache_reload(struct pcap_cache **_pcache);
/* The following definitions come from printing/print_cups.c */
@@ -60,13 +59,13 @@ bool cups_cache_reload(struct tevent_context *ev,
/* The following definitions come from printing/print_iprint.c */
-bool iprint_cache_reload(void);
+bool iprint_cache_reload(struct pcap_cache **_pcache);
/* The following definitions come from printing/print_svid.c */
-bool sysv_cache_reload(void);
+bool sysv_cache_reload(struct pcap_cache **_pcache);
/* The following definitions come from printing/print_standard.c */
-bool std_pcap_cache_reload(const char *pcap_name);
+bool std_pcap_cache_reload(const char *pcap_name, struct pcap_cache **_pcache);
#endif /* _PRINTING_PCAP_H_ */
diff --git a/source3/printing/print_aix.c b/source3/printing/print_aix.c
index 23d9a86fe37..927a71b2948 100644
--- a/source3/printing/print_aix.c
+++ b/source3/printing/print_aix.c
@@ -29,12 +29,13 @@
#include "printing/pcap.h"
#ifdef AIX
-bool aix_cache_reload(void)
+bool aix_cache_reload(struct pcap_cache **_pcache)
{
int iEtat;
XFILE *pfile;
char *line = NULL, *p;
char *name = NULL;
+ struct pcap_cache *pcache = NULL;
TALLOC_CTX *ctx = talloc_init("aix_cache_reload");
if (!ctx) {
@@ -52,6 +53,8 @@ bool aix_cache_reload(void)
iEtat = 0;
/* scan qconfig file for searching <printername>: */
for (;(line = fgets_slash(NULL, 1024, pfile)); free(line)) {
+ bool ok;
+
if (*line == '*' || *line == 0)
continue;
@@ -67,6 +70,7 @@ bool aix_cache_reload(void)
if (strcmp(p, "bsh") != 0) {
name = talloc_strdup(ctx, p);
if (!name) {
+ pcap_cache_destroy_specific(&pcache);
SAFE_FREE(line);
x_fclose(pfile);
TALLOC_FREE(ctx);
@@ -86,7 +90,10 @@ bool aix_cache_reload(void)
/* name is found without stanza device */
/* probably a good printer ??? */
iEtat = 0;
- if (!pcap_cache_add(name, NULL, NULL)) {
+ ok = pcap_cache_add_specific(&pcache,
+ name, NULL, NULL);
+ if (!ok) {
+ pcap_cache_destroy_specific(&pcache);
SAFE_FREE(line);
x_fclose(pfile);
TALLOC_FREE(ctx);
@@ -101,7 +108,10 @@ bool aix_cache_reload(void)
} else if (strstr_m(line, "device")) {
/* it's a good virtual printer */
iEtat = 0;
- if (!pcap_cache_add(name, NULL, NULL)) {
+ ok = pcap_cache_add_specific(&pcache,
+ name, NULL, NULL);
+ if (!ok) {
+ pcap_cache_destroy_specific(&pcache);
SAFE_FREE(line);
x_fclose(pfile);
TALLOC_FREE(ctx);
@@ -113,6 +123,7 @@ bool aix_cache_reload(void)
}
}
+ *_pcache = pcache;
x_fclose(pfile);
TALLOC_FREE(ctx);
return true;
diff --git a/source3/printing/print_iprint.c b/source3/printing/print_iprint.c
index ad61a0a3380..eeb193c6230 100644
--- a/source3/printing/print_iprint.c
+++ b/source3/printing/print_iprint.c
@@ -206,7 +206,8 @@ static int iprint_get_server_version(http_t *http, char* serviceUri)
static int iprint_cache_add_printer(http_t *http,
int reqId,
- char* url)
+ char *url,
+ struct pcap_cache **pcache)
{
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
@@ -342,7 +343,7 @@ static int iprint_cache_add_printer(http_t *http,
*/
if (name != NULL && !secure && smb_enabled)
- pcap_cache_add(name, info, NULL);
+ pcap_cache_add_specific(pcache, name, info, NULL);
}
out:
@@ -351,7 +352,7 @@ static int iprint_cache_add_printer(http_t *http,
return(0);
}
-bool iprint_cache_reload(void)
+bool iprint_cache_reload(struct pcap_cache **_pcache)
{
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
@@ -359,7 +360,8 @@ bool iprint_cache_reload(void)
ipp_attribute_t *attr; /* Current attribute */
cups_lang_t *language = NULL; /* Default language */
int i;
- bool ret = False;
+ bool ret = false;
+ struct pcap_cache *pcache = NULL;
DEBUG(5, ("reloading iprint printcap cache\n"));
@@ -441,14 +443,16 @@ bool iprint_cache_reload(void)
char *url = ippGetString(attr, i, NULL);
if (!url || !strlen(url))
continue;
- iprint_cache_add_printer(http, i+2, url);
+ iprint_cache_add_printer(http, i+2, url,
+ &pcache);
}
}
attr = ippNextAttribute(response);
}
}
- ret = True;
+ ret = true;
+ *_pcache = pcache;
out:
if (response)
diff --git a/source3/printing/print_standard.c b/source3/printing/print_standard.c
index c4f9c5b7ae3..b5f1056b2e6 100644
--- a/source3/printing/print_standard.c
+++ b/source3/printing/print_standard.c
@@ -59,10 +59,11 @@
#include "printing/pcap.h"
/* handle standard printcap - moved from pcap_printer_fn() */
-bool std_pcap_cache_reload(const char *pcap_name)
+bool std_pcap_cache_reload(const char *pcap_name, struct pcap_cache **_pcache)
{
XFILE *pcap_file;
char *pcap_line;
+ struct pcap_cache *pcache = NULL;
if ((pcap_file = x_fopen(pcap_name, O_RDONLY, 0)) == NULL) {
DEBUG(0, ("Unable to open printcap file %s for read!\n", pcap_name));
@@ -117,12 +118,15 @@ bool std_pcap_cache_reload(const char *pcap_name)
}
}
- if (*name && !pcap_cache_add(name, comment, NULL)) {
+ if ((*name != '\0')
+ && !pcap_cache_add_specific(&pcache, name, comment, NULL)) {
x_fclose(pcap_file);
+ pcap_cache_destroy_specific(&pcache);
return false;
}
}
x_fclose(pcap_file);
+ *_pcache = pcache;
return true;
}
diff --git a/source3/printing/print_svid.c b/source3/printing/print_svid.c
index 222649308ca..879661bf5f3 100644
--- a/source3/printing/print_svid.c
+++ b/source3/printing/print_svid.c
@@ -35,10 +35,11 @@
#include "printing/pcap.h"
#if defined(SYSV) || defined(HPUX)
-bool sysv_cache_reload(void)
+bool sysv_cache_reload(struct pcap_cache **_pcache)
{
char **lines;
int i;
+ struct pcap_cache *pcache = NULL;
#if defined(HPUX)
DEBUG(5, ("reloading hpux printcap cache\n"));
@@ -111,14 +112,16 @@ bool sysv_cache_reload(void)
*tmp = '\0';
/* add it to the cache */
- if (!pcap_cache_add(name, NULL, NULL)) {
+ if (!pcap_cache_add_specific(&pcache, name, NULL, NULL)) {
TALLOC_FREE(lines);
- return False;
+ pcap_cache_destroy_specific(&pcache);
+ return false;
}
}
TALLOC_FREE(lines);
- return True;
+ *_pcache = pcache;
+ return true;
}
#else
diff --git a/source3/printing/printer_list.c b/source3/printing/printer_list.c
index 7e89ec4cd7a..815f89fbca3 100644
--- a/source3/printing/printer_list.c
+++ b/source3/printing/printer_list.c
@@ -283,7 +283,8 @@ done:
typedef int (printer_list_trv_fn_t)(struct db_record *, void *);
static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn,
- void *private_data)
+ void *private_data,
+ bool read_only)
{
struct db_context *db;
NTSTATUS status;
@@ -293,7 +294,11 @@ static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn,
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- status = dbwrap_traverse(db, fn, private_data, NULL);
+ if (read_only) {
+ status = dbwrap_traverse_read(db, fn, private_data, NULL);
+ } else {
+ status = dbwrap_traverse(db, fn, private_data, NULL);
+ }
return status;
}
@@ -363,7 +368,7 @@ NTSTATUS printer_list_clean_old(void)
state.status = NT_STATUS_OK;
- status = printer_list_traverse(printer_list_clean_fn, &state);
+ status = printer_list_traverse(printer_list_clean_fn, &state, false);
if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
!NT_STATUS_IS_OK(state.status)) {
status = state.status;
@@ -416,8 +421,8 @@ static int printer_list_exec_fn(struct db_record *rec, void *private_data)
return 0;
}
-NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *),
- void *private_data)
+NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *),
+ void *private_data)
{
struct printer_list_exec_state state;
NTSTATUS status;
@@ -426,7 +431,7 @@ NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *
state.private_data = private_data;
state.status = NT_STATUS_OK;
- status = printer_list_traverse(printer_list_exec_fn, &state);
+ status = printer_list_traverse(printer_list_exec_fn, &state, true);
if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
!NT_STATUS_IS_OK(state.status)) {
status = state.status;
diff --git a/source3/printing/printer_list.h b/source3/printing/printer_list.h
index fb2e007ae6c..b12c1923e72 100644
--- a/source3/printing/printer_list.h
+++ b/source3/printing/printer_list.h
@@ -100,6 +100,6 @@ NTSTATUS printer_list_mark_reload(void);
*/
NTSTATUS printer_list_clean_old(void);
-NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *),
- void *private_data);
+NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *),
+ void *private_data);
#endif /* _PRINTER_LIST_H_ */
diff --git a/source3/printing/queue_process.c b/source3/printing/queue_process.c
index aa0d0fb6a89..88196b4216f 100644
--- a/source3/printing/queue_process.c
+++ b/source3/printing/queue_process.c
@@ -33,10 +33,102 @@
#include "rpc_server/rpc_config.h"
#include "printing/load.h"
#include "rpc_server/spoolss/srv_spoolss_nt.h"
+#include "auth.h"
+#include "nt_printing.h"
extern pid_t start_spoolssd(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx);
+/**
+ * @brief Purge stale printers and reload from pre-populated pcap cache.
+ *
+ * This function should normally only be called as a callback on a successful
+ * pcap_cache_reload().
+ *
+ * This function can cause DELETION of printers and drivers from our registry,
+ * so calling it on a failed pcap reload may REMOVE permanently all printers
+ * and drivers.
+ *
+ * @param[in] ev The event context.
+ *
+ * @param[in] msg_ctx The messaging context.
+ */
+static void delete_and_reload_printers_full(struct tevent_context *ev,
+ struct messaging_context *msg_ctx)
+{
+ struct auth_session_info *session_info = NULL;
+ struct spoolss_PrinterInfo2 *pinfo2 = NULL;
+ int n_services;
+ int pnum;
+ int snum;
+ const char *pname;
+ const char *sname;
+ NTSTATUS status;
+
+ n_services = lp_numservices();
+ pnum = lp_servicenumber(PRINTERS_NAME);
+
+ status = make_session_info_system(talloc_tos(), &session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("reload_printers: "
+ "Could not create system session_info\n"));
+ /* can't remove stale printers before we
+ * are fully initilized */
+ return;
+ }
+
+ /*
+ * Add default config for printers added to smb.conf file and remove
+ * stale printers
+ */
+ for (snum = 0; snum < n_services; snum++) {
+ /* avoid removing PRINTERS_NAME */
+ if (snum == pnum) {
+ continue;
+ }
+
+ /* skip no-printer services */
+ if (!snum_is_shared_printer(snum)) {
+ continue;
+ }
+
+ sname = lp_const_servicename(snum);
+ pname = lp_printername(session_info, snum);
+
+ /* check printer, but avoid removing non-autoloaded printers */
+ if (lp_autoloaded(snum) && !pcap_printername_ok(pname)) {
+ DEBUG(3, ("removing stale printer %s\n", pname));
+
+ if (is_printer_published(session_info, session_info,
+ msg_ctx,
+ NULL,
+ lp_servicename(session_info,
+ snum),
+ &pinfo2)) {
+ nt_printer_publish(session_info,
+ session_info,
+ msg_ctx,
+ pinfo2,
+ DSPRINT_UNPUBLISH);
+ TALLOC_FREE(pinfo2);
+ }
+ nt_printer_remove(session_info, session_info, msg_ctx,
+ pname);
+ } else {
+ DEBUG(8, ("Adding default registry entry for printer "
+ "[%s], if it doesn't exist.\n", sname));
+ nt_printer_add(session_info, session_info, msg_ctx,
+ sname);
+ }
+ }
+
+ /* finally, purge old snums */
+ delete_and_reload_printers(ev, msg_ctx);
+
+ TALLOC_FREE(session_info);
+}
+
+
/****************************************************************************
Notify smbds of new printcap data
**************************************************************************/
@@ -50,7 +142,7 @@ static void reload_pcap_change_notify(struct tevent_context *ev,
* This will block the process for some time (~1 sec per printer), but
* it doesn't block smbd's servering clients.
*/
- delete_and_reload_printers(ev, msg_ctx);
+ delete_and_reload_printers_full(ev, msg_ctx);
message_send_all(msg_ctx, MSG_PRINTER_PCAP, NULL, 0, NULL);
}
@@ -372,7 +464,8 @@ bool printing_subsystem_init(struct tevent_context *ev_ctx,
ret = printing_subsystem_queue_tasks(ev_ctx, msg_ctx);
/* Publish nt printers, this requires a working winreg pipe */
- pcap_cache_reload(ev_ctx, msg_ctx, &delete_and_reload_printers);
+ pcap_cache_reload(ev_ctx, msg_ctx,
+ &delete_and_reload_printers_full);
return ret;
}
@@ -390,7 +483,7 @@ void printing_subsystem_update(struct tevent_context *ev_ctx,
bool force)
{
if (background_lpq_updater_pid != -1) {
- if (pcap_cache_loaded()) {
+ if (pcap_cache_loaded(NULL)) {
load_printers(ev_ctx, msg_ctx);
}
if (force) {
@@ -401,5 +494,6 @@ void printing_subsystem_update(struct tevent_context *ev_ctx,
return;
}
- pcap_cache_reload(ev_ctx, msg_ctx, &delete_and_reload_printers);
+ pcap_cache_reload(ev_ctx, msg_ctx,
+ &delete_and_reload_printers_full);
}
diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c
index 7525fd1c2b6..59f560cd3ba 100644
--- a/source3/printing/spoolssd.c
+++ b/source3/printing/spoolssd.c
@@ -132,27 +132,6 @@ static void smb_conf_updated(struct messaging_context *msg,
update_conf(ev_ctx, msg);
}
-static void update_pcap(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- change_to_root_user();
- delete_and_reload_printers(ev_ctx, msg_ctx);
-}
-
-static void pcap_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- DEBUG(10, ("Got message that pcap updated. Reloading.\n"));
- update_pcap(ev_ctx, msg);
-}
-
static void spoolss_sig_term_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
@@ -318,8 +297,6 @@ static bool spoolss_child_init(struct tevent_context *ev_ctx,
messaging_register(msg_ctx, ev_ctx,
MSG_SMB_CONF_UPDATED, smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx, MSG_PRINTER_PCAP,
- pcap_updated);
messaging_register(msg_ctx, ev_ctx,
MSG_PREFORK_PARENT_EVENT, parent_ping);
@@ -327,7 +304,7 @@ static bool spoolss_child_init(struct tevent_context *ev_ctx,
* If so then we probably missed a message and should load_printers()
* ourselves. If pcap has not been loaded yet, then ignore, we will get
* a message as soon as the bq process completes the reload. */
- if (pcap_cache_loaded()) {
+ if (pcap_cache_loaded(NULL)) {
load_printers(ev_ctx, msg_ctx);
}
@@ -739,16 +716,15 @@ pid_t start_spoolssd(struct tevent_context *ev_ctx,
MSG_SMB_CONF_UPDATED, smb_conf_updated);
messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
print_queue_forward);
- messaging_register(msg_ctx, ev_ctx, MSG_PRINTER_PCAP,
- pcap_updated);
messaging_register(msg_ctx, ev_ctx,
MSG_PREFORK_CHILD_EVENT, child_ping);
- /* As soon as messaging is up check if pcap has been loaded already.
- * If so then we probably missed a message and should load_printers()
- * ourselves. If pcap has not been loaded yet, then ignore, we will get
- * a message as soon as the bq process completes the reload. */
- if (pcap_cache_loaded()) {
+ /*
+ * As soon as messaging is up check if pcap has been loaded already.
+ * If pcap has not been loaded yet, then ignore, as we will reload on
+ * client enumeration anyway.
+ */
+ if (pcap_cache_loaded(NULL)) {
load_printers(ev_ctx, msg_ctx);
}
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 66a50a8f2d9..3d6a3e1a0a8 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -89,6 +89,7 @@ NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
cli->dc = netlogon_creds_client_init(cli,
mach_acct,
clnt_name,
+ sec_chan_type,
&clnt_chal_send,
&srv_chal_recv,
&password,
diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c
index 64f5cbed2ff..335647bf16f 100644
--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
+++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
@@ -1726,6 +1726,16 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
return WERR_INVALID_PARAM;
}
+ /*
+ * The printcap printer share inventory is updated on client
+ * enumeration. For clients that do not perform enumeration prior to
+ * access, such as cupssmbadd, we reinitialise the printer share
+ * inventory on open as well.
+ */
+ become_root();
+ delete_and_reload_printers(server_event_context(), p->msg_ctx);
+ unbecome_root();
+
/* some sanity check because you can open a printer or a print server */
/* aka: \\server\printer or \\server */
@@ -4284,15 +4294,6 @@ static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx,
return WERR_OK;
}
-
-/********************************************************************
-********************************************************************/
-
-static bool snum_is_shared_printer(int snum)
-{
- return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
-}
-
/********************************************************************
Spoolss_enumprinters.
********************************************************************/
@@ -4307,7 +4308,7 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx,
uint32_t *count_p)
{
int snum;
- int n_services = lp_numservices();
+ int n_services;
union spoolss_PrinterInfo *info = NULL;
uint32_t count = 0;
WERROR result = WERR_OK;
@@ -4319,6 +4320,15 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx,
return WERR_NOMEM;
}
+ /*
+ * printer shares are updated on client enumeration. The background
+ * printer process updates printer_list.tdb at regular intervals.
+ */
+ become_root();
+ delete_and_reload_printers(server_event_context(), msg_ctx);
+ unbecome_root();
+
+ n_services = lp_numservices();
*count_p = 0;
*info_p = NULL;
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index 011d41fa522..7b9ec5c87da 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -484,6 +484,7 @@ static WERROR init_srv_share_info_ctr(struct pipes_struct *p,
/* Ensure all the usershares are loaded. */
become_root();
+ delete_and_reload_printers(server_event_context(), p->msg_ctx);
load_usershare_shares(NULL, connections_snum_used);
load_registry_shares();
num_services = lp_numservices();
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 1be5daa385e..3c3f662001f 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -24,7 +24,7 @@
#include "smbd/globals.h"
#include "libcli/security/security.h"
#include "lib/util/bitmap.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
/*
This module implements directory related functions for Samba.
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index b99e18033cc..baf40d7750b 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -951,6 +951,19 @@ NTSTATUS file_set_sparse(connection_struct *conn,
return NT_STATUS_ACCESS_DENIED;
}
+ if (fsp->is_directory) {
+ DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
+ (sparse ? "set" : "clear"),
+ smb_fname_str_dbg(fsp->fsp_name)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (IS_IPC(conn) || IS_PRINT(conn)) {
+ DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
+ (sparse ? "set" : "clear")));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
sparse, smb_fname_str_dbg(fsp->fsp_name)));
diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c
index 9b05d48680e..c3d0a6fd58b 100644
--- a/source3/smbd/durable.c
+++ b/source3/smbd/durable.c
@@ -121,7 +121,6 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
- cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -275,7 +274,6 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
- cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -536,18 +534,6 @@ static bool vfs_default_durable_reconnect_check_stat(
return false;
}
- if (cookie_st->vfs_private != fsp_st->vfs_private) {
- DEBUG(1, ("vfs_default_durable_reconnect (%s): "
- "stat_ex.%s differs: "
- "cookie:%llu != stat:%llu, "
- "denying durable reconnect\n",
- name,
- "vfs_private",
- (unsigned long long)cookie_st->vfs_private,
- (unsigned long long)fsp_st->vfs_private));
- return false;
- }
-
return true;
}
diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c
index 3eb65a13200..e03c7c4180b 100644
--- a/source3/smbd/globals.c
+++ b/source3/smbd/globals.c
@@ -20,7 +20,7 @@
#include "includes.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "messages.h"
#include "tdb_compat.h"
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index 0a0ab6b9754..d0dae36db2e 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -2091,6 +2091,7 @@ static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
/* Ensure all the usershares are loaded. */
become_root();
+ delete_and_reload_printers(sconn->ev_ctx, sconn->msg_ctx);
load_registry_shares();
count = load_usershare_shares(NULL, connections_snum_used);
unbecome_root();
diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c
index 8a44ea2d6a2..f3d85223330 100644
--- a/source3/smbd/mangle_hash.c
+++ b/source3/smbd/mangle_hash.c
@@ -767,6 +767,10 @@ const struct mangle_fns *mangle_hash_init(void)
{
mangle_reset();
+ if (chartest == NULL) {
+ init_chartest();
+ }
+
/* Create the in-memory tdb using our custom hash function. */
tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL,
(O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c
index c2910f82c85..ac1f4b0f4fb 100644
--- a/source3/smbd/mangle_hash2.c
+++ b/source3/smbd/mangle_hash2.c
@@ -66,7 +66,7 @@
#include "includes.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "mangle.h"
#if 1
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 315bd890376..b1d93cd8a3e 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -252,7 +252,8 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) &&
((req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) == 0) )
{
- if (get_remote_arch() != RA_SAMBA) {
+ if ((get_remote_arch() != RA_SAMBA) &&
+ (get_remote_arch() != RA_CIFSFS)) {
set_remote_arch( RA_VISTA );
}
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 5a0ac39e91e..131009b14c3 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -2046,7 +2046,8 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
status = smbd_do_query_security_desc(conn,
talloc_tos(),
fsp,
- security_info_wanted,
+ security_info_wanted &
+ SMB_SUPPORTED_SECINFO_FLAGS,
max_data_count,
&marshalled_sd,
&sd_size);
@@ -2139,8 +2140,8 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
return;
}
- status = set_sd_blob(fsp, (uint8 *)data, data_count, security_info_sent);
-
+ status = set_sd_blob(fsp, (uint8 *)data, data_count,
+ security_info_sent & SMB_SUPPORTED_SECINFO_FLAGS);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
return;
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 621457e0510..d187787e098 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -3288,7 +3288,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
num_profile_acls = 3;
}
- if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
+ if (security_info & SECINFO_DACL) {
/*
* In the optimum case Creator Owner and Creator Group would be used for
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 6153a4965a8..327b25d370e 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -958,6 +958,7 @@ const struct security_token *sec_ctx_active_token(void);
/* The following definitions come from smbd/server.c */
struct memcache *smbd_memcache(void);
+bool snum_is_shared_printer(int snum);
void delete_and_reload_printers(struct tevent_context *ev,
struct messaging_context *msg_ctx);
bool reload_services(struct smbd_server_connection *sconn,
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 9e249d1a6b9..8856f43be59 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -29,7 +29,7 @@
#include "registry/reg_init_full.h"
#include "libcli/auth/schannel.h"
#include "secrets.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "ctdbd_conn.h"
#include "printing/queue_process.h"
#include "rpc_server/rpc_service_setup.h"
@@ -109,24 +109,6 @@ static void smbd_parent_conf_updated(struct messaging_context *msg,
}
/*******************************************************************
- What to do when printcap is updated.
- ********************************************************************/
-
-static void smb_pcap_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx =
- talloc_get_type_abort(private_data, struct tevent_context);
-
- DEBUG(10,("Got message saying pcap was updated. Reloading.\n"));
- change_to_root_user();
- delete_and_reload_printers(ev_ctx, msg);
-}
-
-/*******************************************************************
Delete a statcache entry.
********************************************************************/
@@ -881,8 +863,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
smb_stat_cache_delete);
messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
- messaging_register(msg_ctx, ev_ctx, MSG_PRINTER_PCAP,
- smb_pcap_updated);
messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
brl_revalidate);
messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
diff --git a/source3/smbd/server_reload.c b/source3/smbd/server_reload.c
index 1d6f9c2911f..971c8b86efb 100644
--- a/source3/smbd/server_reload.c
+++ b/source3/smbd/server_reload.c
@@ -31,20 +31,23 @@
#include "messages.h"
#include "lib/param/loadparm.h"
-static bool snum_is_shared_printer(int snum)
+/*
+ * The persistent pcap cache is populated by the background print process. Per
+ * client smbds should only reload their printer share inventories if this
+ * information has changed. Use reload_last_pcap_time to detect this.
+ */
+static time_t reload_last_pcap_time = 0;
+
+bool snum_is_shared_printer(int snum)
{
return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
}
/**
- * @brief Purge stale printers and reload from pre-populated pcap cache.
+ * @brief Purge stale printer shares and reload from pre-populated pcap cache.
*
* This function should normally only be called as a callback on a successful
- * pcap_cache_reload() or after a MSG_PRINTER_CAP message is received.
- *
- * This function can cause DELETION of printers and drivers from our registry,
- * so calling it on a failed pcap reload may REMOVE permanently all printers
- * and drivers.
+ * pcap_cache_reload(), or on client enumeration.
*
* @param[in] ev The event context.
*
@@ -53,14 +56,27 @@ static bool snum_is_shared_printer(int snum)
void delete_and_reload_printers(struct tevent_context *ev,
struct messaging_context *msg_ctx)
{
- struct auth_session_info *session_info = NULL;
- struct spoolss_PrinterInfo2 *pinfo2 = NULL;
int n_services;
int pnum;
int snum;
const char *pname;
- const char *sname;
- NTSTATUS status;
+ bool ok;
+ time_t pcap_last_update;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ ok = pcap_cache_loaded(&pcap_last_update);
+ if (!ok) {
+ DEBUG(1, ("pcap cache not loaded\n"));
+ talloc_free(frame);
+ return;
+ }
+
+ if (reload_last_pcap_time == pcap_last_update) {
+ DEBUG(5, ("skipping printer reload, already up to date.\n"));
+ talloc_free(frame);
+ return;
+ }
+ reload_last_pcap_time = pcap_last_update;
/* Get pcap printers updated */
load_printers(ev, msg_ctx);
@@ -70,15 +86,6 @@ void delete_and_reload_printers(struct tevent_context *ev,
DEBUG(10, ("reloading printer services from pcap cache\n"));
- status = make_session_info_system(talloc_tos(), &session_info);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("reload_printers: "
- "Could not create system session_info\n"));
- /* can't remove stale printers before we
- * are fully initilized */
- return;
- }
-
/*
* Add default config for printers added to smb.conf file and remove
* stale printers
@@ -94,41 +101,18 @@ void delete_and_reload_printers(struct tevent_context *ev,
continue;
}
- sname = lp_const_servicename(snum);
- pname = lp_printername(session_info, snum);
+ pname = lp_printername(frame, snum);
/* check printer, but avoid removing non-autoloaded printers */
if (lp_autoloaded(snum) && !pcap_printername_ok(pname)) {
- DEBUG(3, ("removing stale printer %s\n", pname));
-
- if (is_printer_published(session_info, session_info,
- msg_ctx,
- NULL,
- lp_servicename(session_info,
- snum),
- &pinfo2)) {
- nt_printer_publish(session_info,
- session_info,
- msg_ctx,
- pinfo2,
- DSPRINT_UNPUBLISH);
- TALLOC_FREE(pinfo2);
- }
- nt_printer_remove(session_info, session_info, msg_ctx,
- pname);
lp_killservice(snum);
- } else {
- DEBUG(8, ("Adding default registry entry for printer "
- "[%s], if it doesn't exist.\n", sname));
- nt_printer_add(session_info, session_info, msg_ctx,
- sname);
}
}
/* Make sure deleted printers are gone */
load_printers(ev, msg_ctx);
- TALLOC_FREE(session_info);
+ talloc_free(frame);
}
/****************************************************************************
diff --git a/source3/smbd/smb2_find.c b/source3/smbd/smb2_find.c
index c39a35d526c..02c554f0342 100644
--- a/source3/smbd/smb2_find.c
+++ b/source3/smbd/smb2_find.c
@@ -224,6 +224,7 @@ static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx,
uint32_t dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
bool dont_descend = false;
bool ask_sharemode = true;
+ bool wcard_has_wild;
struct tm tm;
char *p;
@@ -252,11 +253,11 @@ static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx,
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
- if (strcmp(in_file_name, "\\") == 0) {
+ if (strchr_m(in_file_name, '\\') != NULL) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
- if (strcmp(in_file_name, "/") == 0) {
+ if (strchr_m(in_file_name, '/') != NULL) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
@@ -323,11 +324,41 @@ static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx,
dptr_CloseDir(fsp);
}
- if (fsp->dptr == NULL) {
- bool wcard_has_wild;
+ wcard_has_wild = ms_has_wild(in_file_name);
- wcard_has_wild = ms_has_wild(in_file_name);
+ /* Ensure we've canonicalized any search path if not a wildcard. */
+ if (!wcard_has_wild) {
+ struct smb_filename *smb_fname = NULL;
+ const char *fullpath;
+ if (ISDOT(fsp->fsp_name->base_name)) {
+ fullpath = in_file_name;
+ } else {
+ fullpath = talloc_asprintf(state,
+ "%s/%s",
+ fsp->fsp_name->base_name,
+ in_file_name);
+ }
+ if (tevent_req_nomem(fullpath, req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = filename_convert(state,
+ conn,
+ false, /* Not a DFS path. */
+ fullpath,
+ UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP,
+ &wcard_has_wild,
+ &smb_fname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ in_file_name = smb_fname->original_lcomp;
+ }
+
+ if (fsp->dptr == NULL) {
status = dptr_create(conn,
NULL, /* req */
fsp,
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 449aeb3f5f4..bbc838dcc27 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -478,7 +478,8 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
state,
fsp,
/* Security info wanted. */
- in_additional_information,
+ in_additional_information &
+ SMB_SUPPORTED_SECINFO_FLAGS,
in_output_buffer_length,
&p_marshalled_sd,
&sd_size);
diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
index d88f7ac8a28..cda8abc2bd9 100644
--- a/source3/smbd/smb2_setinfo.c
+++ b/source3/smbd/smb2_setinfo.c
@@ -311,7 +311,8 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
status = set_sd_blob(fsp,
in_input_buffer.data,
in_input_buffer.length,
- in_additional_information);
+ in_additional_information &
+ SMB_SUPPORTED_SECINFO_FLAGS);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 92010c230dd..2f3b067012e 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -21,7 +21,7 @@
*/
#include "includes.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "smbd/smbd.h"
#include "messages.h"
#include "smbprofile.h"
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 49609d01794..4a0588e6f5e 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -27,7 +27,7 @@
#include "system/filesys.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "transfer_file.h"
#include "ntioctl.h"
#include "lib/util/tevent_unix.h"
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 50028872588..2e66912a942 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -26,7 +26,7 @@
#include "tldap.h"
#include "tldap_util.h"
#include "../librpc/gen_ndr/svcctl.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "nsswitch/winbind_client.h"
#include "dbwrap/dbwrap.h"
#include "dbwrap/dbwrap_open.h"
diff --git a/source3/utils/net_time.c b/source3/utils/net_time.c
index 847b4fe445c..56ce8f71ad6 100644
--- a/source3/utils/net_time.c
+++ b/source3/utils/net_time.c
@@ -84,10 +84,10 @@ static const char *systime(time_t t)
int net_time_usage(struct net_context *c, int argc, const char **argv)
{
d_printf(_(
-"net time\n\tdisplays time on a server\n\n"
-"net time system\n\tdisplays time on a server in a format ready for /bin/date\n\n"
-"net time set\n\truns /bin/date with the time from the server\n\n"
-"net time zone\n\tdisplays the timezone in hours from GMT on the remote computer\n\n"
+"net time\n\tdisplays time on a server (-S server)\n\n"
+"net time system\n\tdisplays time on a server (-S server) in a format ready for /bin/date\n\n"
+"net time set\n\truns /bin/date with the time from the server (-S server)\n\n"
+"net time zone\n\tdisplays the timezone in hours from GMT on the remote server (-S server)\n\n"
"\n"));
net_common_flags_usage(c, argc, argv);
return -1;
@@ -99,6 +99,16 @@ static int net_time_set(struct net_context *c, int argc, const char **argv)
struct timeval tv;
int result;
+ if (c->display_usage || c->opt_host == NULL) {
+ d_printf( "%s\n"
+ "net time set\n"
+ " %s\n",
+ _("Usage:"),
+ _("Set local time to that of remote time "
+ "server (-S server) "));
+ return 0;
+ }
+
tv.tv_sec = nettime(c, NULL);
tv.tv_usec=0;
@@ -118,13 +128,13 @@ static int net_time_system(struct net_context *c, int argc, const char **argv)
{
time_t t;
- if (c->display_usage) {
+ if (c->display_usage || c->opt_host == NULL) {
d_printf( "%s\n"
"net time system\n"
" %s\n",
_("Usage:"),
- _("Output remote time server time in a format "
- "ready for /bin/date"));
+ _("Output remote time server (-S server) "
+ "time in a format ready for /bin/date"));
return 0;
}
@@ -144,13 +154,13 @@ static int net_time_zone(struct net_context *c, int argc, const char **argv)
char zsign;
time_t t;
- if (c->display_usage) {
+ if (c->display_usage || c->opt_host == NULL) {
d_printf( "%s\n"
"net time zone\n"
" %s\n",
_("Usage:"),
- _("Display the remote time server's offset to "
- "UTC"));
+ _("Display the remote time server's (-S server) "
+ "offset to UTC"));
return 0;
}
diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c
index 97a34d4bddb..c3c88eae138 100644
--- a/source3/winbindd/idmap.c
+++ b/source3/winbindd/idmap.c
@@ -197,9 +197,9 @@ static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
range = lp_parm_const_string(-1, config_option, "range", NULL);
if (range == NULL) {
- DEBUG(1, ("idmap range not specified for domain %s\n",
- result->name));
if (check_range) {
+ DEBUG(1, ("idmap range not specified for domain %s\n",
+ result->name));
goto fail;
}
} else if (sscanf(range, "%u - %u", &result->low_id,
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index 68ffd7e03e5..f101e52f65f 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -999,6 +999,41 @@ static bool remove_idle_client(void)
return False;
}
+/*
+ * Terminate all clients whose requests have taken longer than
+ * "winbind request timeout" seconds to process, or have been
+ * idle for more than "winbind request timeout" seconds.
+ */
+
+static void remove_timed_out_clients(void)
+{
+ struct winbindd_cli_state *state, *next = NULL;
+ time_t curr_time = time(NULL);
+ int timeout_val = lp_winbind_request_timeout();
+
+ for (state = winbindd_client_list(); state; state = next) {
+ time_t expiry_time;
+
+ next = state->next;
+ expiry_time = state->last_access + timeout_val;
+
+ if (curr_time > expiry_time) {
+ if (client_is_idle(state)) {
+ DEBUG(5,("Idle client timed out, "
+ "shutting down sock %d, pid %u\n",
+ state->sock,
+ (unsigned int)state->pid));
+ } else {
+ DEBUG(5,("Client request timed out, "
+ "shutting down sock %d, pid %u\n",
+ state->sock,
+ (unsigned int)state->pid));
+ }
+ remove_client(state);
+ }
+ }
+}
+
struct winbindd_listen_state {
bool privileged;
int fd;
@@ -1024,6 +1059,7 @@ static void winbindd_listen_fde_handler(struct tevent_context *ev,
break;
}
}
+ remove_timed_out_clients();
new_connection(s->fd, s->privileged);
}
diff --git a/source3/wscript b/source3/wscript
index fda984cfac0..bac3dd588a2 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -194,27 +194,32 @@ main() {
Logs.warn('no suitable FAM library found')
# check for DMAPI libs
- Logs.info("Checking for DMAPI library existence")
- conf.env['dmapi_lib'] = ''
- samba_dmapi_lib = ''
- if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'dm'):
- samba_dmapi_lib = 'dm'
+ if Options.options.with_dmapi == False:
+ have_dmapi = False
else:
- if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'jfsdm'):
- samba_dmapi_lib = 'jfsdm'
+ have_dmapi = True
+ Logs.info("Checking for DMAPI library existence")
+ samba_dmapi_lib = ''
+ if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'dm'):
+ samba_dmapi_lib = 'dm'
else:
- if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'dmapi'):
- samba_dmapi_lib = 'dmapi'
+ if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'jfsdm'):
+ samba_dmapi_lib = 'jfsdm'
else:
- if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'xdsm'):
- samba_dmapi_lib = 'xdsm'
- # only bother to test headers and compilation when a candidate
- # library has been found
- if Options.options.with_dmapi == True and samba_dmapi_lib == '':
- conf.fatal('DMAPI support requested, but no suitable DMAPI library found')
- else:
- conf.CHECK_HEADERS('sys/dmi.h xfs/dmapi.h sys/jfsdmapi.h sys/dmapi.h dmapi.h')
- conf.CHECK_CODE('''
+ if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'dmapi'):
+ samba_dmapi_lib = 'dmapi'
+ else:
+ if conf.CHECK_FUNCS_IN('dm_get_eventlist', 'xdsm'):
+ samba_dmapi_lib = 'xdsm'
+ # only bother to test headers and compilation when a candidate
+ # library has been found
+ if samba_dmapi_lib == '':
+ have_dmapi = False
+ broken_dmapi = "no suitable DMAPI library found"
+
+ if have_dmapi:
+ conf.CHECK_HEADERS('sys/dmi.h xfs/dmapi.h sys/jfsdmapi.h sys/dmapi.h dmapi.h')
+ conf.CHECK_CODE('''
#include <time.h> /* needed by Tru64 */
#include <sys/types.h> /* needed by AIX */
#ifdef HAVE_XFS_DMAPI_H
@@ -244,17 +249,28 @@ int main(int argc, char **argv)
return 0;
}
''',
- 'USE_DMAPI',
- addmain=False,
- execute=False,
- lib=samba_dmapi_lib,
- msg='Checking whether DMAPI lib '+samba_dmapi_lib+' can be used')
-
- if conf.CONFIG_SET('USE_DMAPI'):
- conf.env['dmapi_lib'] = samba_dmapi_lib
+ 'USEABLE_DMAPI_LIBRARY',
+ addmain=False,
+ execute=False,
+ lib=samba_dmapi_lib,
+ msg='Checking whether DMAPI lib '+samba_dmapi_lib+' can be used')
+ if not conf.CONFIG_SET('USEABLE_DMAPI_LIBRARY'):
+ have_dmapi = False
+ broken_dmapi = "no usable DMAPI library found"
+
+ if have_dmapi:
+ Logs.info("Building with DMAPI support.")
+ conf.env['dmapi_lib'] = samba_dmapi_lib
+ conf.DEFINE('USE_DMAPI', 1)
+ else:
+ if Options.options.with_dmapi == False:
+ Logs.info("Building without DMAPI support (--without-dmapi).")
+ elif Options.options.with_dmapi == True:
+ Logs.error("DMAPI support not available: " + broken_dmapi)
+ conf.fatal('DMAPI support requested but not found.');
else:
- if Options.options.with_dmapi == True:
- conf.fatal('DMAPI support requested but not found');
+ Logs.warn("Building without DMAPI support: " + broken_dmapi)
+ conf.env['dmapi_lib'] = ''
# Check for various members of the stat structure
conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_blocks', define='HAVE_STAT_ST_BLOCKS',
diff --git a/source3/wscript_build b/source3/wscript_build
index d4f999a0c61..9461b05d32b 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1108,7 +1108,7 @@ bld.SAMBA3_SUBSYSTEM('tdb-wrap3',
vars=locals())
bld.SAMBA3_LIBRARY('samba3-util',
- source='''lib/util_sec.c lib/util_str.c lib/adt_tree.c lib/util_malloc.c lib/memcache.c lib/namearray.c lib/file_id.c''',
+ source='''lib/util_sec.c lib/util_str.c lib/adt_tree.c lib/util_malloc.c lib/namearray.c lib/file_id.c''',
deps='samba-util charset',
private_library=True)
diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c
index c0ed8e11cbd..38b765aa0dc 100644
--- a/source4/dns_server/dlz_bind9.c
+++ b/source4/dns_server/dlz_bind9.c
@@ -37,7 +37,7 @@
#include "messaging/messaging.h"
#include "lib/cmdline/popt_common.h"
#include "dlz_minimal.h"
-
+#include "dns_server/dnsserver_common.h"
struct b9_options {
const char *url;
@@ -459,7 +459,7 @@ static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state,
parse options
*/
static isc_result_t parse_options(struct dlz_bind9_data *state,
- unsigned int argc, char *argv[],
+ unsigned int argc, const char **argv,
struct b9_options *options)
{
int opt;
@@ -470,7 +470,7 @@ static isc_result_t parse_options(struct dlz_bind9_data *state,
{ NULL }
};
- pc = poptGetContext("dlz_bind9", argc, (const char **)argv, long_options,
+ pc = poptGetContext("dlz_bind9", argc, argv, long_options,
POPT_CONTEXT_KEEP_FIRST);
while ((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
@@ -564,7 +564,7 @@ static int dlz_state_debug_unregister(struct dlz_bind9_data *state)
called to initialise the driver
*/
_PUBLIC_ isc_result_t dlz_create(const char *dlzname,
- unsigned int argc, char *argv[],
+ unsigned int argc, const char **argv,
void **dbdata, ...)
{
struct dlz_bind9_data *state;
@@ -801,11 +801,10 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state,
const char **types)
{
TALLOC_CTX *tmp_ctx = talloc_new(state);
- const char *attrs[] = { "dnsRecord", NULL };
- int ret = LDB_SUCCESS, i;
- struct ldb_result *res;
- struct ldb_message_element *el;
struct ldb_dn *dn;
+ WERROR werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+ struct dnsp_DnssrvRpcRecord *records = NULL;
+ uint16_t num_records = 0, i;
for (i=0; zone_prefixes[i]; i++) {
dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
@@ -819,38 +818,21 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state,
return ISC_R_NOMEMORY;
}
- ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
- attrs, "objectClass=dnsNode");
- if (ret == LDB_SUCCESS) {
+ werr = dns_common_lookup(state->samdb, tmp_ctx, dn,
+ &records, &num_records, NULL);
+ if (W_ERROR_IS_OK(werr)) {
break;
}
}
- if (ret != LDB_SUCCESS || res->count == 0) {
- talloc_free(tmp_ctx);
- return ISC_R_NOTFOUND;
- }
-
- el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
- if (el == NULL || el->num_values == 0) {
+ if (!W_ERROR_IS_OK(werr)) {
talloc_free(tmp_ctx);
return ISC_R_NOTFOUND;
}
- for (i=0; i<el->num_values; i++) {
- struct dnsp_DnssrvRpcRecord rec;
- enum ndr_err_code ndr_err;
+ for (i=0; i < num_records; i++) {
isc_result_t result;
- ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(tmp_ctx);
- return ISC_R_FAILURE;
- }
-
- result = b9_putrr(state, lookup, &rec, types);
+ result = b9_putrr(state, lookup, &records[i], types);
if (result != ISC_R_SUCCESS) {
talloc_free(tmp_ctx);
return result;
@@ -929,6 +911,9 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata,
TALLOC_CTX *el_ctx = talloc_new(tmp_ctx);
const char *rdn, *name;
const struct ldb_val *v;
+ WERROR werr;
+ struct dnsp_DnssrvRpcRecord *recs = NULL;
+ uint16_t num_recs = 0;
el = ldb_msg_find_element(res->msgs[i], "dnsRecord");
if (el == NULL || el->num_values == 0) {
@@ -962,24 +947,24 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata,
return ISC_R_NOMEMORY;
}
- for (j=0; j<el->num_values; j++) {
- struct dnsp_DnssrvRpcRecord rec;
- enum ndr_err_code ndr_err;
- isc_result_t result;
+ werr = dns_common_extract(el, el_ctx, &recs, &num_recs);
+ if (!W_ERROR_IS_OK(werr)) {
+ state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s",
+ ldb_dn_get_linearized(dn), win_errstr(werr));
+ talloc_free(el_ctx);
+ continue;
+ }
- ndr_err = ndr_pull_struct_blob(&el->values[j], el_ctx, &rec,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- continue;
- }
+ for (j=0; j < num_recs; j++) {
+ isc_result_t result;
- result = b9_putnamedrr(state, allnodes, name, &rec);
+ result = b9_putnamedrr(state, allnodes, name, &recs[j]);
if (result != ISC_R_SUCCESS) {
continue;
}
}
+
+ talloc_free(el_ctx);
}
talloc_free(tmp_ctx);
@@ -1057,39 +1042,25 @@ _PUBLIC_ void dlz_closeversion(const char *zone, isc_boolean_t commit,
*/
static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const char *zone)
{
- const char *attrs[] = { "dnsRecord", NULL };
- struct ldb_result *res;
- struct ldb_message_element *el;
TALLOC_CTX *tmp_ctx = talloc_new(state);
- int ret, i;
+ WERROR werr;
+ struct dnsp_DnssrvRpcRecord *records = NULL;
+ uint16_t num_records = 0, i;
if (!ldb_dn_add_child_fmt(dn, "DC=@,DC=%s", zone)) {
talloc_free(tmp_ctx);
return false;
}
- ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
- attrs, "objectClass=dnsNode");
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return false;
- }
-
- el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
- if (el == NULL) {
+ werr = dns_common_lookup(state->samdb, tmp_ctx, dn,
+ &records, &num_records, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
talloc_free(tmp_ctx);
return false;
}
- for (i=0; i<el->num_values; i++) {
- struct dnsp_DnssrvRpcRecord rec;
- enum ndr_err_code ndr_err;
- ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- continue;
- }
- if (rec.wType == DNS_TYPE_SOA) {
+ for (i=0; i < num_records; i++) {
+ if (records[i].wType == DNS_TYPE_SOA) {
talloc_free(tmp_ctx);
return true;
}
@@ -1321,46 +1292,6 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const
return ISC_TRUE;
}
-
-/*
- add a new record
- */
-static isc_result_t b9_add_record(struct dlz_bind9_data *state, const char *name,
- struct ldb_dn *dn,
- struct dnsp_DnssrvRpcRecord *rec)
-{
- struct ldb_message *msg;
- enum ndr_err_code ndr_err;
- struct ldb_val v;
- int ret;
-
- msg = ldb_msg_new(rec);
- if (msg == NULL) {
- return ISC_R_NOMEMORY;
- }
- msg->dn = dn;
- ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
- if (ret != LDB_SUCCESS) {
- return ISC_R_FAILURE;
- }
-
- ndr_err = ndr_push_struct_blob(&v, rec, rec, (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return ISC_R_FAILURE;
- }
- ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
- if (ret != LDB_SUCCESS) {
- return ISC_R_FAILURE;
- }
-
- ret = ldb_add(state->samdb, msg);
- if (ret != LDB_SUCCESS) {
- return ISC_R_FAILURE;
- }
-
- return ISC_R_SUCCESS;
-}
-
/*
see if two DNS names are the same
*/
@@ -1488,12 +1419,14 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
struct dnsp_DnssrvRpcRecord *rec;
struct ldb_dn *dn;
isc_result_t result;
- struct ldb_result *res;
- const char *attrs[] = { "dnsRecord", NULL };
- int ret, i;
- struct ldb_message_element *el;
- enum ndr_err_code ndr_err;
+ bool tombstoned = false;
+ bool needs_add = false;
+ struct dnsp_DnssrvRpcRecord *recs = NULL;
+ uint16_t num_recs = 0;
+ uint16_t first = 0;
+ uint16_t i;
NTTIME t;
+ WERROR werr;
if (state->transaction_token != (void*)version) {
state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version");
@@ -1510,7 +1443,6 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
t /= 3600; /* convert to hours */
rec->rank = DNS_RANK_ZONE;
- rec->dwSerial = state->soa_serial;
rec->dwTimeStamp = (uint32_t)t;
if (!b9_parse(state, rdatastr, rec)) {
@@ -1527,70 +1459,55 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
}
/* get any existing records */
- ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode");
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
- if (!b9_set_session_info(state, name)) {
- talloc_free(rec);
- return ISC_R_FAILURE;
- }
- result = b9_add_record(state, name, dn, rec);
- b9_reset_session_info(state);
+ werr = dns_common_lookup(state->samdb, rec, dn,
+ &recs, &num_recs, &tombstoned);
+ if (W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+ needs_add = true;
+ werr = WERR_OK;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s",
+ ldb_dn_get_linearized(dn), win_errstr(werr));
talloc_free(rec);
- if (result == ISC_R_SUCCESS) {
- state->log(ISC_LOG_INFO, "samba_dlz: added %s %s", name, rdatastr);
- }
- return result;
+ return ISC_R_FAILURE;
}
- el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
- if (el == NULL) {
- ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", LDB_FLAG_MOD_ADD, &el);
- if (ret != LDB_SUCCESS) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to add dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(rec);
- return ISC_R_FAILURE;
- }
+ if (tombstoned) {
+ /*
+ * we need to keep the existing tombstone record
+ * and ignore it
+ */
+ first = num_recs;
}
/* there are existing records. We need to see if this will
* replace a record or add to it
*/
- for (i=0; i<el->num_values; i++) {
- struct dnsp_DnssrvRpcRecord rec2;
-
- ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(rec);
- return ISC_R_FAILURE;
- }
-
- if (b9_record_match(state, rec, &rec2)) {
+ for (i=first; i < num_recs; i++) {
+ if (b9_record_match(state, rec, &recs[i])) {
break;
}
}
- if (i == el->num_values) {
+ if (i == UINT16_MAX) {
+ state->log(ISC_LOG_ERROR, "samba_dlz: failed to already %u dnsRecord values for %s",
+ i, ldb_dn_get_linearized(dn));
+ talloc_free(rec);
+ return ISC_R_FAILURE;
+ }
+
+ if (i == num_recs) {
/* adding a new value */
- el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
- if (el->values == NULL) {
+ recs = talloc_realloc(rec, recs,
+ struct dnsp_DnssrvRpcRecord,
+ num_recs + 1);
+ if (recs == NULL) {
talloc_free(rec);
return ISC_R_NOMEMORY;
}
- el->num_values++;
- }
-
- ndr_err = ndr_push_struct_blob(&el->values[i], rec, rec,
- (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to push dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(rec);
- return ISC_R_FAILURE;
+ num_recs++;
}
+ recs[i] = *rec;
if (!b9_set_session_info(state, name)) {
talloc_free(rec);
@@ -1598,12 +1515,15 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
}
/* modify the record */
- el->flags = LDB_FLAG_MOD_REPLACE;
- ret = ldb_modify(state->samdb, res->msgs[0]);
+ werr = dns_common_replace(state->samdb, rec, dn,
+ needs_add,
+ state->soa_serial,
+ recs, num_recs);
b9_reset_session_info(state);
- if (ret != LDB_SUCCESS) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s",
- ldb_dn_get_linearized(dn), ldb_errstring(state->samdb));
+ if (!W_ERROR_IS_OK(werr)) {
+ state->log(ISC_LOG_ERROR, "samba_dlz: failed to %s %s - %s",
+ needs_add ? "add" : "modify",
+ ldb_dn_get_linearized(dn), win_errstr(werr));
talloc_free(rec);
return ISC_R_FAILURE;
}
@@ -1623,11 +1543,10 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo
struct dnsp_DnssrvRpcRecord *rec;
struct ldb_dn *dn;
isc_result_t result;
- struct ldb_result *res;
- const char *attrs[] = { "dnsRecord", NULL };
- int ret, i;
- struct ldb_message_element *el;
- enum ndr_err_code ndr_err;
+ struct dnsp_DnssrvRpcRecord *recs = NULL;
+ uint16_t num_recs = 0;
+ uint16_t i;
+ WERROR werr;
if (state->transaction_token != (void*)version) {
state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version");
@@ -1653,64 +1572,40 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo
}
/* get the existing records */
- ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode");
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ werr = dns_common_lookup(state->samdb, rec, dn,
+ &recs, &num_recs, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
talloc_free(rec);
return ISC_R_NOTFOUND;
}
- /* there are existing records. We need to see if any match
- */
- el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
- if (el == NULL || el->num_values == 0) {
- state->log(ISC_LOG_ERROR, "samba_dlz: no dnsRecord attribute for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(rec);
- return ISC_R_FAILURE;
- }
-
- for (i=0; i<el->num_values; i++) {
- struct dnsp_DnssrvRpcRecord rec2;
-
- ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(rec);
- return ISC_R_FAILURE;
- }
-
- if (b9_record_match(state, rec, &rec2)) {
+ for (i=0; i < num_recs; i++) {
+ if (b9_record_match(state, rec, &recs[i])) {
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
break;
}
}
- if (i == el->num_values) {
+ if (i == num_recs) {
talloc_free(rec);
return ISC_R_NOTFOUND;
}
- if (i < el->num_values-1) {
- memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
- }
- el->num_values--;
-
if (!b9_set_session_info(state, name)) {
talloc_free(rec);
return ISC_R_FAILURE;
}
- if (el->num_values == 0) {
- el->flags = LDB_FLAG_MOD_DELETE;
- } else {
- el->flags = LDB_FLAG_MOD_REPLACE;
- }
- ret = ldb_modify(state->samdb, res->msgs[0]);
-
+ /* modify the record */
+ werr = dns_common_replace(state->samdb, rec, dn,
+ false,/* needs_add */
+ state->soa_serial,
+ recs, num_recs);
b9_reset_session_info(state);
- if (ret != LDB_SUCCESS) {
+ if (!W_ERROR_IS_OK(werr)) {
state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s",
- ldb_dn_get_linearized(dn), ldb_errstring(state->samdb));
+ ldb_dn_get_linearized(dn), win_errstr(werr));
talloc_free(rec);
return ISC_R_FAILURE;
}
@@ -1731,13 +1626,12 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void *
TALLOC_CTX *tmp_ctx;
struct ldb_dn *dn;
isc_result_t result;
- struct ldb_result *res;
- const char *attrs[] = { "dnsRecord", NULL };
- int ret, i;
- struct ldb_message_element *el;
- enum ndr_err_code ndr_err;
enum dns_record_type dns_type;
bool found = false;
+ struct dnsp_DnssrvRpcRecord *recs = NULL;
+ uint16_t num_recs = 0;
+ uint16_t ri = 0;
+ WERROR werr;
if (state->transaction_token != (void*)version) {
state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version");
@@ -1759,41 +1653,22 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void *
}
/* get the existing records */
- ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode");
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
- talloc_free(tmp_ctx);
- return ISC_R_NOTFOUND;
- }
-
- /* there are existing records. We need to see if any match the type
- */
- el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
- if (el == NULL || el->num_values == 0) {
+ werr = dns_common_lookup(state->samdb, tmp_ctx, dn,
+ &recs, &num_recs, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
talloc_free(tmp_ctx);
return ISC_R_NOTFOUND;
}
- for (i=0; i<el->num_values; i++) {
- struct dnsp_DnssrvRpcRecord rec2;
-
- ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec2,
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
- ldb_dn_get_linearized(dn));
- talloc_free(tmp_ctx);
- return ISC_R_FAILURE;
+ for (ri=0; ri < num_recs; ri++) {
+ if (dns_type != recs[ri].wType) {
+ continue;
}
- if (dns_type == rec2.wType) {
- if (i < el->num_values-1) {
- memmove(&el->values[i], &el->values[i+1],
- sizeof(el->values[0])*((el->num_values-1)-i));
- }
- el->num_values--;
- i--;
- found = true;
- }
+ found = true;
+ recs[ri] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
if (!found) {
@@ -1806,17 +1681,15 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void *
return ISC_R_FAILURE;
}
- if (el->num_values == 0) {
- el->flags = LDB_FLAG_MOD_DELETE;
- } else {
- el->flags = LDB_FLAG_MOD_REPLACE;
- }
- ret = ldb_modify(state->samdb, res->msgs[0]);
-
+ /* modify the record */
+ werr = dns_common_replace(state->samdb, tmp_ctx, dn,
+ false,/* needs_add */
+ state->soa_serial,
+ recs, num_recs);
b9_reset_session_info(state);
- if (ret != LDB_SUCCESS) {
- state->log(ISC_LOG_ERROR, "samba_dlz: failed to delete type %s in %s - %s",
- type, ldb_dn_get_linearized(dn), ldb_errstring(state->samdb));
+ if (!W_ERROR_IS_OK(werr)) {
+ state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s",
+ ldb_dn_get_linearized(dn), win_errstr(werr));
talloc_free(tmp_ctx);
return ISC_R_FAILURE;
}
diff --git a/source4/dns_server/dlz_minimal.h b/source4/dns_server/dlz_minimal.h
index 5262cbdaa6a..98fb34e9745 100644
--- a/source4/dns_server/dlz_minimal.h
+++ b/source4/dns_server/dlz_minimal.h
@@ -100,7 +100,7 @@ int dlz_version(unsigned int *flags);
/*
* dlz_create() is required for all DLZ external drivers.
*/
-isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...);
+isc_result_t dlz_create(const char *dlzname, unsigned int argc, const char **argv, void **dbdata, ...);
/*
* dlz_destroy() is optional, and will be called when the driver is
diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h
index efe4db822fc..12ccc9b8999 100644
--- a/source4/dns_server/dns_server.h
+++ b/source4/dns_server/dns_server.h
@@ -86,7 +86,6 @@ WERROR dns_server_process_update(struct dns_server *dns,
struct dns_res_rec **updates, uint16_t *update_count,
struct dns_res_rec **additional, uint16_t *arcount);
-uint8_t werr_to_dns_err(WERROR werror);
bool dns_name_match(const char *zone, const char *name, size_t *host_part_len);
bool dns_name_equal(const char *name1, const char *name2);
bool dns_records_match(struct dnsp_DnssrvRpcRecord *rec1,
@@ -102,7 +101,7 @@ WERROR dns_replace_records(struct dns_server *dns,
TALLOC_CTX *mem_ctx,
struct ldb_dn *dn,
bool needs_add,
- const struct dnsp_DnssrvRpcRecord *records,
+ struct dnsp_DnssrvRpcRecord *records,
uint16_t rec_count);
WERROR dns_name2dn(struct dns_server *dns,
TALLOC_CTX *mem_ctx,
@@ -124,5 +123,6 @@ WERROR dns_sign_tsig(struct dns_server *dns,
struct dns_name_packet *packet,
uint16_t error);
-#define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str
+#include "source4/dns_server/dnsserver_common.h"
+
#endif /* __DNS_SERVER_H__ */
diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c
index 9edc40bc341..04e7d9adff7 100644
--- a/source4/dns_server/dns_update.c
+++ b/source4/dns_server/dns_update.c
@@ -82,6 +82,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns,
/*
*/
werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount);
+ if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+ return DNS_ERR(NAME_ERROR);
+ }
W_ERROR_NOT_OK_RETURN(werror);
if (acount == 0) {
@@ -91,6 +94,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns,
/*
*/
werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount);
+ if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+ return DNS_ERR(NXRRSET);
+ }
if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) {
return DNS_ERR(NXRRSET);
}
@@ -131,10 +137,11 @@ static WERROR check_one_prerequisite(struct dns_server *dns,
/*
*/
werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount);
+ if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+ werror = WERR_OK;
+ }
if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) {
werror = WERR_OK;
- ans = NULL;
- acount = 0;
}
for (i = 0; i < acount; i++) {
@@ -163,6 +170,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns,
*final_result = false;
werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount);
+ if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+ return DNS_ERR(NXRRSET);
+ }
if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) {
return DNS_ERR(NXRRSET);
}
@@ -302,8 +312,6 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
r->wType = rrec->rr_type;
r->dwTtlSeconds = rrec->ttl;
r->rank = DNS_RANK_ZONE;
- /* TODO: Autogenerate this somehow */
- r->dwSerial = 110;
/* If we get QCLASS_ANY, we're done here */
if (rrec->rr_class == DNS_QCLASS_ANY) {
@@ -392,7 +400,9 @@ static WERROR handle_one_update(struct dns_server *dns,
uint16_t rcount = 0;
struct ldb_dn *dn;
uint16_t i;
+ uint16_t first = 0;
WERROR werror;
+ bool tombstoned = false;
bool needs_add = false;
DEBUG(2, ("Looking at record: \n"));
@@ -420,22 +430,29 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_name2dn(dns, mem_ctx, update->name, &dn);
W_ERROR_NOT_OK_RETURN(werror);
- werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rcount);
- if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) {
- recs = NULL;
- rcount = 0;
+ werror = dns_common_lookup(dns->samdb, mem_ctx, dn,
+ &recs, &rcount, &tombstoned);
+ if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
needs_add = true;
werror = WERR_OK;
}
W_ERROR_NOT_OK_RETURN(werror);
+ if (tombstoned) {
+ /*
+ * we need to keep the existing tombstone record
+ * and ignore it
+ */
+ first = rcount;
+ }
+
if (update->rr_class == zone->question_class) {
if (update->rr_type == DNS_QTYPE_CNAME) {
/*
* If there is a record in the directory
* that's not a CNAME, ignore update
*/
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (recs[i].wType != DNS_TYPE_CNAME) {
DEBUG(5, ("Skipping update\n"));
return WERR_OK;
@@ -448,13 +465,14 @@ static WERROR handle_one_update(struct dns_server *dns,
* per name, so replace everything with the new CNAME
*/
- rcount = 1;
+ rcount = first;
recs = talloc_realloc(mem_ctx, recs,
- struct dnsp_DnssrvRpcRecord, rcount);
+ struct dnsp_DnssrvRpcRecord, rcount + 1);
W_ERROR_HAVE_NO_MEMORY(recs);
- werror = dns_rr_to_dnsp(recs, update, &recs[0]);
+ werror = dns_rr_to_dnsp(recs, update, &recs[rcount]);
W_ERROR_NOT_OK_RETURN(werror);
+ rcount += 1;
werror = dns_replace_records(dns, mem_ctx, dn,
needs_add, recs, rcount);
@@ -466,7 +484,7 @@ static WERROR handle_one_update(struct dns_server *dns,
* If there is a CNAME record for this name,
* ignore update
*/
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (recs[i].wType == DNS_TYPE_CNAME) {
DEBUG(5, ("Skipping update\n"));
return WERR_OK;
@@ -481,7 +499,7 @@ static WERROR handle_one_update(struct dns_server *dns,
* serial number is smaller than existing SOA's,
* ignore update
*/
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (recs[i].wType == DNS_TYPE_SOA) {
uint16_t n, o;
@@ -512,7 +530,9 @@ static WERROR handle_one_update(struct dns_server *dns,
continue;
}
- ZERO_STRUCT(recs[i]);
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
werror = dns_replace_records(dns, mem_ctx, dn,
@@ -529,7 +549,7 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_rr_to_dnsp(recs, update, &recs[rcount]);
W_ERROR_NOT_OK_RETURN(werror);
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (!dns_records_match(&recs[i], &recs[rcount])) {
continue;
}
@@ -551,7 +571,7 @@ static WERROR handle_one_update(struct dns_server *dns,
} else if (update->rr_class == DNS_QCLASS_ANY) {
if (update->rr_type == DNS_QTYPE_ALL) {
if (dns_name_equal(update->name, zone->name)) {
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (recs[i].wType == DNS_TYPE_SOA) {
continue;
@@ -561,12 +581,16 @@ static WERROR handle_one_update(struct dns_server *dns,
continue;
}
- ZERO_STRUCT(recs[i]);
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
} else {
- for (i = 0; i < rcount; i++) {
- ZERO_STRUCT(recs[i]);
+ for (i = first; i < rcount; i++) {
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
}
@@ -580,9 +604,11 @@ static WERROR handle_one_update(struct dns_server *dns,
return WERR_OK;
}
}
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (recs[i].wType == update->rr_type) {
- ZERO_STRUCT(recs[i]);
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
}
@@ -607,7 +633,7 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_rr_to_dnsp(ns_rec, update, ns_rec);
W_ERROR_NOT_OK_RETURN(werror);
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (dns_records_match(ns_rec, &recs[i])) {
found = true;
break;
@@ -624,9 +650,11 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_rr_to_dnsp(del_rec, update, del_rec);
W_ERROR_NOT_OK_RETURN(werror);
- for (i = 0; i < rcount; i++) {
+ for (i = first; i < rcount; i++) {
if (dns_records_match(del_rec, &recs[i])) {
- ZERO_STRUCT(recs[i]);
+ recs[i] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ };
}
}
diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c
index 72782cf4500..c757c157626 100644
--- a/source4/dns_server/dns_utils.c
+++ b/source4/dns_server/dns_utils.c
@@ -33,37 +33,6 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_DNS
-uint8_t werr_to_dns_err(WERROR werr)
-{
- if (W_ERROR_EQUAL(WERR_OK, werr)) {
- return DNS_RCODE_OK;
- } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) {
- return DNS_RCODE_FORMERR;
- } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) {
- return DNS_RCODE_SERVFAIL;
- } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) {
- return DNS_RCODE_NXDOMAIN;
- } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) {
- return DNS_RCODE_NOTIMP;
- } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) {
- return DNS_RCODE_REFUSED;
- } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) {
- return DNS_RCODE_YXDOMAIN;
- } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) {
- return DNS_RCODE_YXRRSET;
- } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) {
- return DNS_RCODE_NXRRSET;
- } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) {
- return DNS_RCODE_NOTAUTH;
- } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) {
- return DNS_RCODE_NOTZONE;
- } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
- return DNS_RCODE_BADKEY;
- }
- DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
- return DNS_RCODE_SERVFAIL;
-}
-
bool dns_name_match(const char *zone, const char *name, size_t *host_part_len)
{
size_t zl = strlen(zone);
@@ -185,126 +154,21 @@ WERROR dns_lookup_records(struct dns_server *dns,
struct dnsp_DnssrvRpcRecord **records,
uint16_t *rec_count)
{
- static const char * const attrs[] = { "dnsRecord", NULL};
- struct ldb_message_element *el;
- uint16_t ri;
- int ret;
- struct ldb_message *msg = NULL;
- struct dnsp_DnssrvRpcRecord *recs;
-
- ret = dsdb_search_one(dns->samdb, mem_ctx, &msg, dn,
- LDB_SCOPE_BASE, attrs, 0, "%s", "(objectClass=dnsNode)");
- if (ret != LDB_SUCCESS) {
- /* TODO: we need to check if there's a glue record we need to
- * create a referral to */
- return DNS_ERR(NAME_ERROR);
- }
-
- el = ldb_msg_find_element(msg, attrs[0]);
- if (el == NULL) {
- *records = NULL;
- *rec_count = 0;
- return DNS_ERR(NAME_ERROR);
- }
-
- recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord, el->num_values);
- if (recs == NULL) {
- return WERR_NOMEM;
- }
- for (ri = 0; ri < el->num_values; ri++) {
- struct ldb_val *v = &el->values[ri];
- enum ndr_err_code ndr_err;
-
- ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri],
- (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
- return DNS_ERR(SERVER_FAILURE);
- }
- }
- *records = recs;
- *rec_count = el->num_values;
- return WERR_OK;
+ return dns_common_lookup(dns->samdb, mem_ctx, dn,
+ records, rec_count, NULL);
}
WERROR dns_replace_records(struct dns_server *dns,
TALLOC_CTX *mem_ctx,
struct ldb_dn *dn,
bool needs_add,
- const struct dnsp_DnssrvRpcRecord *records,
+ struct dnsp_DnssrvRpcRecord *records,
uint16_t rec_count)
{
- struct ldb_message_element *el;
- uint16_t i;
- int ret;
- struct ldb_message *msg = NULL;
-
- msg = ldb_msg_new(mem_ctx);
- W_ERROR_HAVE_NO_MEMORY(msg);
-
- msg->dn = dn;
-
- ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el);
- if (ret != LDB_SUCCESS) {
- return DNS_ERR(SERVER_FAILURE);
- }
-
- el->values = talloc_zero_array(el, struct ldb_val, rec_count);
- if (rec_count > 0) {
- W_ERROR_HAVE_NO_MEMORY(el->values);
- }
-
- for (i = 0; i < rec_count; i++) {
- static const struct dnsp_DnssrvRpcRecord zero;
- struct ldb_val *v = &el->values[el->num_values];
- enum ndr_err_code ndr_err;
-
- if (memcmp(&records[i], &zero, sizeof(zero)) == 0) {
- continue;
- }
- ndr_err = ndr_push_struct_blob(v, el->values, &records[i],
- (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
- return DNS_ERR(SERVER_FAILURE);
- }
- el->num_values++;
- }
-
-
- if (el->num_values == 0) {
- if (needs_add) {
- return WERR_OK;
- }
- /* No entries left, delete the dnsNode object */
- ret = ldb_delete(dns->samdb, msg->dn);
- if (ret != LDB_SUCCESS) {
- DEBUG(0, ("Deleting record failed; %d\n", ret));
- return DNS_ERR(SERVER_FAILURE);
- }
- return WERR_OK;
- }
-
- if (needs_add) {
- ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
- if (ret != LDB_SUCCESS) {
- return DNS_ERR(SERVER_FAILURE);
- }
-
- ret = ldb_add(dns->samdb, msg);
- if (ret != LDB_SUCCESS) {
- return DNS_ERR(SERVER_FAILURE);
- }
-
- return WERR_OK;
- }
-
- ret = ldb_modify(dns->samdb, msg);
- if (ret != LDB_SUCCESS) {
- return DNS_ERR(SERVER_FAILURE);
- }
-
- return WERR_OK;
+ /* TODO: Autogenerate this somehow */
+ uint32_t dwSerial = 110;
+ return dns_common_replace(dns->samdb, mem_ctx, dn,
+ needs_add, dwSerial, records, rec_count);
}
bool dns_authorative_for_zone(struct dns_server *dns,
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
new file mode 100644
index 00000000000..c49d6ec87a6
--- /dev/null
+++ b/source4/dns_server/dnsserver_common.c
@@ -0,0 +1,342 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DNS server utils
+
+ Copyright (C) 2010 Kai Blin
+ Copyright (C) 2014 Stefan Metzmacher
+
+ 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 "libcli/util/ntstatus.h"
+#include "libcli/util/werror.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include <ldb.h>
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "dns_server/dnsserver_common.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DNS
+
+uint8_t werr_to_dns_err(WERROR werr)
+{
+ if (W_ERROR_EQUAL(WERR_OK, werr)) {
+ return DNS_RCODE_OK;
+ } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) {
+ return DNS_RCODE_FORMERR;
+ } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) {
+ return DNS_RCODE_SERVFAIL;
+ } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) {
+ return DNS_RCODE_NXDOMAIN;
+ } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST, werr)) {
+ return DNS_RCODE_NXDOMAIN;
+ } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) {
+ return DNS_RCODE_NOTIMP;
+ } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) {
+ return DNS_RCODE_REFUSED;
+ } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) {
+ return DNS_RCODE_YXDOMAIN;
+ } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) {
+ return DNS_RCODE_YXRRSET;
+ } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) {
+ return DNS_RCODE_NXRRSET;
+ } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) {
+ return DNS_RCODE_NOTAUTH;
+ } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) {
+ return DNS_RCODE_NOTZONE;
+ } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
+ return DNS_RCODE_BADKEY;
+ }
+ DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
+ return DNS_RCODE_SERVFAIL;
+}
+
+WERROR dns_common_extract(const struct ldb_message_element *el,
+ TALLOC_CTX *mem_ctx,
+ struct dnsp_DnssrvRpcRecord **records,
+ uint16_t *num_records)
+{
+ uint16_t ri;
+ struct dnsp_DnssrvRpcRecord *recs;
+
+ *records = NULL;
+ *num_records = 0;
+
+ recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
+ el->num_values);
+ if (recs == NULL) {
+ return WERR_NOMEM;
+ }
+ for (ri = 0; ri < el->num_values; ri++) {
+ struct ldb_val *v = &el->values[ri];
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri],
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(recs);
+ DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
+ return DNS_ERR(SERVER_FAILURE);
+ }
+ }
+ *records = recs;
+ *num_records = el->num_values;
+ return WERR_OK;
+}
+
+WERROR dns_common_lookup(struct ldb_context *samdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct dnsp_DnssrvRpcRecord **records,
+ uint16_t *num_records,
+ bool *tombstoned)
+{
+ static const char * const attrs[] = {
+ "dnsRecord",
+ "dNSTombstoned",
+ NULL
+ };
+ int ret;
+ WERROR werr;
+ struct ldb_message *msg = NULL;
+ struct ldb_message_element *el;
+
+ *records = NULL;
+ *num_records = 0;
+
+ if (tombstoned != NULL) {
+ *tombstoned = false;
+ ret = dsdb_search_one(samdb, mem_ctx, &msg, dn,
+ LDB_SCOPE_BASE, attrs, 0,
+ "(objectClass=dnsNode)");
+ } else {
+ ret = dsdb_search_one(samdb, mem_ctx, &msg, dn,
+ LDB_SCOPE_BASE, attrs, 0,
+ "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
+ }
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+ }
+ if (ret != LDB_SUCCESS) {
+ /* TODO: we need to check if there's a glue record we need to
+ * create a referral to */
+ return DNS_ERR(NAME_ERROR);
+ }
+
+ if (tombstoned != NULL) {
+ *tombstoned = ldb_msg_find_attr_as_bool(msg,
+ "dNSTombstoned", false);
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ if (el == NULL) {
+ TALLOC_FREE(msg);
+ if (tombstoned != NULL) {
+ struct dnsp_DnssrvRpcRecord *recs;
+ /*
+ * records produced by older Samba releases
+ * keep dnsNode objects without dnsRecord and
+ * without setting dNSTombstoned=TRUE.
+ *
+ * We just pretend they're tombstones.
+ */
+ recs = talloc_array(mem_ctx,
+ struct dnsp_DnssrvRpcRecord,
+ 1);
+ if (recs == NULL) {
+ return WERR_NOMEM;
+ }
+ recs[0] = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ /*
+ * A value of timestamp != 0
+ * indicated that the object was already
+ * a tombstone, this will be used
+ * in dns_common_replace()
+ */
+ .data.timestamp = 1,
+ };
+
+ *tombstoned = true;
+ *records = recs;
+ *num_records = 1;
+ return WERR_OK;
+ }
+ return DNS_ERR(NAME_ERROR);
+ }
+
+ werr = dns_common_extract(el, mem_ctx, records, num_records);
+ TALLOC_FREE(msg);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ return WERR_OK;
+}
+
+static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
+ const struct dnsp_DnssrvRpcRecord *r2)
+{
+ if (r1->wType != r2->wType) {
+ /*
+ * The records are sorted with higher types first
+ */
+ return r2->wType - r1->wType;
+ }
+
+ /*
+ * Then we need to sort from the oldest to newest timestamp
+ */
+ return r1->dwTimeStamp - r2->dwTimeStamp;
+}
+
+WERROR dns_common_replace(struct ldb_context *samdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ bool needs_add,
+ uint32_t serial,
+ struct dnsp_DnssrvRpcRecord *records,
+ uint16_t rec_count)
+{
+ struct ldb_message_element *el;
+ uint16_t i;
+ int ret;
+ struct ldb_message *msg = NULL;
+ bool was_tombstoned = false;
+ bool become_tombstoned = false;
+
+ msg = ldb_msg_new(mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(msg);
+
+ msg->dn = dn;
+
+ ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el);
+ if (ret != LDB_SUCCESS) {
+ return DNS_ERR(SERVER_FAILURE);
+ }
+
+ /*
+ * we have at least one value,
+ * which might be used for the tombstone marker
+ */
+ el->values = talloc_zero_array(el, struct ldb_val, MAX(1, rec_count));
+ if (rec_count > 0) {
+ W_ERROR_HAVE_NO_MEMORY(el->values);
+
+ /*
+ * We store a sorted list with the high wType values first
+ * that's what windows does. It also simplifies the
+ * filtering of DNS_TYPE_TOMBSTONE records
+ */
+ TYPESAFE_QSORT(records, rec_count, rec_cmp);
+ }
+
+ for (i = 0; i < rec_count; i++) {
+ struct ldb_val *v = &el->values[el->num_values];
+ enum ndr_err_code ndr_err;
+
+ if (records[i].wType == DNS_TYPE_TOMBSTONE) {
+ if (records[i].data.timestamp != 0) {
+ was_tombstoned = true;
+ }
+ continue;
+ }
+
+ records[i].dwSerial = serial;
+ ndr_err = ndr_push_struct_blob(v, el->values, &records[i],
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
+ return DNS_ERR(SERVER_FAILURE);
+ }
+ el->num_values++;
+ }
+
+ if (needs_add) {
+ if (el->num_values == 0) {
+ return WERR_OK;
+ }
+
+ ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
+ if (ret != LDB_SUCCESS) {
+ return DNS_ERR(SERVER_FAILURE);
+ }
+
+ ret = ldb_add(samdb, msg);
+ if (ret != LDB_SUCCESS) {
+ return DNS_ERR(SERVER_FAILURE);
+ }
+
+ return WERR_OK;
+ }
+
+ if (el->num_values == 0) {
+ struct dnsp_DnssrvRpcRecord tbs;
+ struct ldb_val *v = &el->values[el->num_values];
+ enum ndr_err_code ndr_err;
+ struct timeval tv;
+
+ if (was_tombstoned) {
+ /*
+ * This is already a tombstoned object.
+ * Just leave it instead of updating the time stamp.
+ */
+ return WERR_OK;
+ }
+
+ tv = timeval_current();
+ tbs = (struct dnsp_DnssrvRpcRecord) {
+ .wType = DNS_TYPE_TOMBSTONE,
+ .dwSerial = serial,
+ .data.timestamp = timeval_to_nttime(&tv),
+ };
+
+ ndr_err = ndr_push_struct_blob(v, el->values, &tbs,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
+ return DNS_ERR(SERVER_FAILURE);
+ }
+ el->num_values++;
+
+ become_tombstoned = true;
+ }
+
+ if (was_tombstoned || become_tombstoned) {
+ ret = ldb_msg_add_empty(msg, "dNSTombstoned",
+ LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ return DNS_ERR(SERVER_FAILURE);
+ }
+
+ ret = ldb_msg_add_fmt(msg, "dNSTombstoned", "%s",
+ become_tombstoned ? "TRUE" : "FALSE");
+ if (ret != LDB_SUCCESS) {
+ return DNS_ERR(SERVER_FAILURE);
+ }
+ }
+
+ ret = ldb_modify(samdb, msg);
+ if (ret != LDB_SUCCESS) {
+ NTSTATUS nt = dsdb_ldb_err_to_ntstatus(ret);
+ return ntstatus_to_werror(nt);
+ }
+
+ return WERR_OK;
+}
diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h
new file mode 100644
index 00000000000..becd243f6a9
--- /dev/null
+++ b/source4/dns_server/dnsserver_common.h
@@ -0,0 +1,50 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DNS server utils
+
+ Copyright (C) 2014 Stefan Metzmacher
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DNSSERVER_COMMON_H__
+#define __DNSSERVER_COMMON_H__
+
+uint8_t werr_to_dns_err(WERROR werr);
+#define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str
+
+struct ldb_message_element;
+
+WERROR dns_common_extract(const struct ldb_message_element *el,
+ TALLOC_CTX *mem_ctx,
+ struct dnsp_DnssrvRpcRecord **records,
+ uint16_t *num_records);
+
+WERROR dns_common_lookup(struct ldb_context *samdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct dnsp_DnssrvRpcRecord **records,
+ uint16_t *num_records,
+ bool *tombstoned);
+
+WERROR dns_common_replace(struct ldb_context *samdb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ bool needs_add,
+ uint32_t serial,
+ struct dnsp_DnssrvRpcRecord *records,
+ uint16_t rec_count);
+
+#endif /* __DNSSERVER_COMMON_H__ */
diff --git a/source4/dns_server/wscript_build b/source4/dns_server/wscript_build
index 280f8de49c0..a92ab67a40f 100644
--- a/source4/dns_server/wscript_build
+++ b/source4/dns_server/wscript_build
@@ -1,10 +1,16 @@
#!/usr/bin/env python
+bld.SAMBA_LIBRARY('dnsserver_common',
+ source='dnsserver_common.c',
+ deps='samba-util errors ldbsamba clidns',
+ private_library=True,
+ )
+
bld.SAMBA_MODULE('service_dns',
source='dns_server.c dns_query.c dns_update.c dns_utils.c dns_crypto.c',
subsystem='service',
init_function='server_service_dns_init',
- deps='samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET ldbsamba clidns gensec auth samba_server_gensec',
+ deps='samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET ldbsamba clidns gensec auth samba_server_gensec dnsserver_common',
local_include=False,
internal_module=False,
enabled=bld.AD_DC_BUILD_IS_ENABLED()
@@ -18,7 +24,7 @@ bld.SAMBA_LIBRARY('dlz_bind9',
link_name='modules/bind9/dlz_bind9.so',
realname='dlz_bind9.so',
install_path='${MODULESDIR}/bind9',
- deps='samba-hostconfig samdb-common gensec popt',
+ deps='samba-hostconfig samdb-common gensec popt dnsserver_common',
enabled=bld.AD_DC_BUILD_IS_ENABLED())
bld.SAMBA_LIBRARY('dlz_bind9_9',
@@ -28,12 +34,12 @@ bld.SAMBA_LIBRARY('dlz_bind9_9',
link_name='modules/bind9/dlz_bind9_9.so',
realname='dlz_bind9_9.so',
install_path='${MODULESDIR}/bind9',
- deps='samba-hostconfig samdb-common gensec popt',
+ deps='samba-hostconfig samdb-common gensec popt dnsserver_common',
enabled=bld.AD_DC_BUILD_IS_ENABLED())
bld.SAMBA_LIBRARY('dlz_bind9_for_torture',
source='dlz_bind9.c',
cflags='-DBIND_VERSION_9_8',
private_library=True,
- deps='samba-hostconfig samdb-common gensec popt',
+ deps='samba-hostconfig samdb-common gensec popt dnsserver_common',
enabled=bld.AD_DC_BUILD_IS_ENABLED())
diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c
index 3e10447f0fc..aa617c6aeca 100644
--- a/source4/dsdb/dns/dns_update.c
+++ b/source4/dsdb/dns/dns_update.c
@@ -397,6 +397,7 @@ struct dnsupdate_RODC_state {
struct irpc_message *msg;
struct dnsupdate_RODC *r;
char *tmp_path;
+ char *tmp_path2;
int fd;
};
@@ -406,6 +407,9 @@ static int dnsupdate_RODC_destructor(struct dnsupdate_RODC_state *st)
close(st->fd);
}
unlink(st->tmp_path);
+ if (st->tmp_path2 != NULL) {
+ unlink(st->tmp_path2);
+ }
return 0;
}
@@ -483,6 +487,13 @@ static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg,
talloc_set_destructor(st, dnsupdate_RODC_destructor);
+ st->tmp_path2 = talloc_asprintf(st, "%s.cache", st->tmp_path);
+ if (!st->tmp_path2) {
+ talloc_free(st);
+ r->out.result = NT_STATUS_NO_MEMORY;
+ return NT_STATUS_OK;
+ }
+
sid_dn = ldb_dn_new_fmt(st, s->samdb, "<SID=%s>", dom_sid_string(st, r->in.dom_sid));
if (!sid_dn) {
talloc_free(st);
@@ -575,6 +586,8 @@ static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg,
dns_update_command,
"--update-list",
st->tmp_path,
+ "--update-cache",
+ st->tmp_path2,
NULL);
NT_STATUS_HAVE_NO_MEMORY(req);
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index be1ab240bd7..1480486c320 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -187,6 +187,7 @@ static void continue_srv_challenge(struct tevent_req *subreq)
s->creds = netlogon_creds_client_init(s,
s->a.in.account_name,
s->a.in.computer_name,
+ s->a.in.secure_channel_type,
&s->credentials1, &s->credentials2,
s->mach_pwd, &s->credentials3,
s->local_negotiate_flags);
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
index 5733a51177a..dee69fe2387 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -1625,7 +1625,8 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
}
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
- LDB_SCOPE_ONELEVEL, attrs, "(&(objectClass=dnsNode)(name=@))");
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=@)(!(dNSTombstoned=TRUE)))");
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return WERR_INTERNAL_DB_ERROR;
@@ -1657,8 +1658,9 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) {
for (i=0; i<add_count; i++) {
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
- LDB_SCOPE_ONELEVEL, attrs,
- "(&(objectClass=dnsNode)(name=%s))", add_names[i]);
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ add_names[i]);
if (ret != LDB_SUCCESS || res->count == 0) {
talloc_free(res);
continue;
@@ -1722,11 +1724,12 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
/* search all records under parent tree */
if (strcasecmp(name, z->name) == 0) {
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
- LDB_SCOPE_ONELEVEL, attrs, "(objectClass=dnsNode)");
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
} else {
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
- LDB_SCOPE_ONELEVEL, attrs,
- "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s)))",
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))",
name, name);
}
if (ret != LDB_SUCCESS) {
@@ -1801,7 +1804,8 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
name = dns_split_node_name(tmp_ctx, add_names[i], z2->name);
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z2->zone_dn,
LDB_SCOPE_ONELEVEL, attrs,
- "(&(objectClass=dnsNode)(name=%s))", name);
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ name);
talloc_free(name);
if (ret != LDB_SUCCESS) {
continue;
@@ -1853,7 +1857,9 @@ static WERROR dnsserver_update_record(struct dnsserver_state *dsstate,
W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
/* If node_name is @ or zone name, dns record is @ */
- if (strcmp(node_name, "@") == 0 || strcasecmp(node_name, z->name) == 0) {
+ if (strcmp(node_name, "@") == 0 ||
+ strcmp(node_name, ".") == 0 ||
+ strcasecmp(node_name, z->name) == 0) {
name = talloc_strdup(tmp_ctx, "@");
} else {
name = dns_split_node_name(tmp_ctx, node_name, z->name);
diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c
index fb2547ff7ec..f752490101a 100644
--- a/source4/rpc_server/dnsserver/dnsdata.c
+++ b/source4/rpc_server/dnsserver/dnsdata.c
@@ -798,6 +798,15 @@ WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
if (dnsp_rec.rank == DNS_RANK_ZONE) {
found = true;
+ } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
+ /*
+ * If branch_name is NULL, we're
+ * explicitly asked to also return
+ * DNS_RANK_NS_GLUE records
+ */
+ if (branch_name == NULL) {
+ found = true;
+ }
}
}
if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
@@ -806,7 +815,7 @@ WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
}
}
if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
- if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
+ if (dnsp_rec.rank == DNS_RANK_GLUE) {
found = true;
}
}
diff --git a/source4/rpc_server/dnsserver/dnsdb.c b/source4/rpc_server/dnsserver/dnsdb.c
index 8cdeae41f52..e567f5a4f80 100644
--- a/source4/rpc_server/dnsserver/dnsdb.c
+++ b/source4/rpc_server/dnsserver/dnsdb.c
@@ -395,7 +395,7 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
const char *name,
struct DNS_RPC_RECORD *add_record)
{
- const char * const attrs[] = { "dnsRecord", NULL };
+ const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
struct ldb_result *res;
struct dnsp_DnssrvRpcRecord *rec;
struct ldb_message_element *el;
@@ -404,14 +404,18 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
NTTIME t;
int ret, i;
int serial;
+ bool was_tombstoned = false;
rec = dns_to_dnsp_copy(mem_ctx, add_record);
W_ERROR_HAVE_NO_MEMORY(rec);
- /* Set the correct rank for the record.
- * FIXME: add logic to check for glue records */
+ /* Set the correct rank for the record. */
if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
- rec->rank |= DNS_RANK_ZONE;
+ if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
+ rec->rank = DNS_RANK_NS_GLUE;
+ } else {
+ rec->rank |= DNS_RANK_ZONE;
+ }
} else if (strcmp(z->name, ".") == 0) {
rec->rank |= DNS_RANK_ROOT_HINT;
}
@@ -449,6 +453,12 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
}
}
+ was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
+ "dNSTombstoned", false);
+ if (was_tombstoned) {
+ el->num_values = 0;
+ }
+
for (i=0; i<el->num_values; i++) {
struct dnsp_DnssrvRpcRecord rec2;
@@ -479,6 +489,12 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
}
el->flags = LDB_FLAG_MOD_REPLACE;
+
+ el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
+ if (el != NULL) {
+ el->flags = LDB_FLAG_MOD_DELETE;
+ }
+
ret = ldb_modify(samdb, res->msgs[0]);
if (ret != LDB_SUCCESS) {
return WERR_INTERNAL_DB_ERROR;
@@ -517,7 +533,7 @@ WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
arec->dwTimeStamp = t;
ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
- "(&(objectClass=dnsNode)(name=%s))", name);
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))", name);
if (ret != LDB_SUCCESS) {
return WERR_INTERNAL_DB_ERROR;
}
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index b3b9989f9b7..70239a4c834 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -27,6 +27,7 @@
#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
#include "../lib/util/util_ldb.h"
+#include "../lib/util/memcache.h"
#include "../libcli/auth/schannel.h"
#include "libcli/security/security.h"
#include "param/param.h"
@@ -39,6 +40,8 @@
#include "librpc/gen_ndr/ndr_irpc.h"
#include "lib/socket/netif.h"
+static struct memcache *global_challenge_table;
+
struct netlogon_server_pipe_state {
struct netr_Credential client_challenge;
struct netr_Credential server_challenge;
@@ -49,9 +52,27 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
{
struct netlogon_server_pipe_state *pipe_state =
talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+ DATA_BLOB key, val;
ZERO_STRUCTP(r->out.return_credentials);
+ if (global_challenge_table == NULL) {
+ /*
+ * We maintain a global challenge table
+ * with a fixed size (8k)
+ *
+ * This is required for the strange clients
+ * which use different connections for
+ * netr_ServerReqChallenge() and netr_ServerAuthenticate3()
+ *
+ */
+ global_challenge_table = memcache_init(talloc_autofree_context(),
+ 8192);
+ if (global_challenge_table == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
/* destroyed on pipe shutdown */
if (pipe_state) {
@@ -71,6 +92,11 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
dce_call->context->private_data = pipe_state;
+ key = data_blob_string_const(r->in.computer_name);
+ val = data_blob_const(pipe_state, sizeof(*pipe_state));
+
+ memcache_add(global_challenge_table, SINGLETON_CACHE, key, val);
+
return NT_STATUS_OK;
}
@@ -79,6 +105,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
{
struct netlogon_server_pipe_state *pipe_state =
talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+ DATA_BLOB challenge_key;
+ bool challenge_valid = false;
+ struct netlogon_server_pipe_state challenge;
struct netlogon_creds_CredentialState *creds;
struct ldb_context *sam_ctx;
struct samr_Password *mach_pwd;
@@ -96,6 +125,57 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
ZERO_STRUCTP(r->out.return_credentials);
*r->out.rid = 0;
+ challenge_key = data_blob_string_const(r->in.computer_name);
+ if (pipe_state != NULL) {
+ dce_call->context->private_data = NULL;
+
+ /*
+ * If we had a challenge remembered on the connection
+ * consider this for usage. This can't be cleanup
+ * by other clients.
+ *
+ * This is the default code path for typical clients
+ * which call netr_ServerReqChallenge() and
+ * netr_ServerAuthenticate3() on the same dcerpc connection.
+ */
+ challenge = *pipe_state;
+ TALLOC_FREE(pipe_state);
+ challenge_valid = true;
+ } else {
+ DATA_BLOB val;
+ bool ok;
+
+ /*
+ * Fallback and try to get the challenge from
+ * the global cache.
+ *
+ * If too many clients are using this code path,
+ * they may destroy their cache entries as the
+ * global_challenge_table memcache has a fixed size.
+ *
+ * Note: this handles global_challenge_table == NULL fine
+ */
+ ok = memcache_lookup(global_challenge_table, SINGLETON_CACHE,
+ challenge_key, &val);
+ if (ok && val.length == sizeof(challenge)) {
+ memcpy(&challenge, val.data, sizeof(challenge));
+ challenge_valid = true;
+ } else {
+ ZERO_STRUCT(challenge);
+ }
+ }
+
+ /*
+ * At this point we can cleanup the cache entry,
+ * if we fail the client needs to call netr_ServerReqChallenge
+ * again.
+ *
+ * Note: this handles global_challenge_table == NULL
+ * and also a non existing record just fine.
+ */
+ memcache_delete(global_challenge_table,
+ SINGLETON_CACHE, challenge_key);
+
negotiate_flags = NETLOGON_NEG_ACCOUNT_LOCKOUT |
NETLOGON_NEG_PERSISTENT_SAMREPL |
NETLOGON_NEG_ARCFOUR |
@@ -257,8 +337,11 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
return NT_STATUS_ACCESS_DENIED;
}
- if (!pipe_state) {
- DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
+ if (!challenge_valid) {
+ DEBUG(1, ("No challenge requested by client [%s/%s], "
+ "cannot authenticate\n",
+ r->in.computer_name,
+ r->in.account_name));
return NT_STATUS_ACCESS_DENIED;
}
@@ -266,8 +349,8 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
r->in.account_name,
r->in.computer_name,
r->in.secure_channel_type,
- &pipe_state->client_challenge,
- &pipe_state->server_challenge,
+ &challenge.client_challenge,
+ &challenge.server_challenge,
mach_pwd,
r->in.credentials,
r->out.return_credentials,
diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate
index 68b0f72151f..30d5608d50a 100755
--- a/source4/scripting/bin/samba_dnsupdate
+++ b/source4/scripting/bin/samba_dnsupdate
@@ -42,6 +42,7 @@ import samba
import optparse
from samba import getopt as options
from ldb import SCOPE_BASE
+from samba import dsdb
from samba.auth import system_session
from samba.samdb import SamDB
from samba.dcerpc import netlogon, winbind
@@ -63,6 +64,7 @@ parser.add_option("--all-names", action="store_true")
parser.add_option("--all-interfaces", action="store_true")
parser.add_option("--use-file", type="string", help="Use a file, rather than real DNS calls")
parser.add_option("--update-list", type="string", help="Add DNS names from the given file")
+parser.add_option("--update-cache", type="string", help="Cache database of already registered records")
parser.add_option("--fail-immediately", action='store_true', help="Exit on first failure")
parser.add_option("--no-credentials", dest='nocreds', action='store_true', help="don't try and get credentials")
parser.add_option("--no-substiutions", dest='nosubs', action='store_true', help="don't try and expands variables in file specified by --update-list")
@@ -136,41 +138,44 @@ class dnsobj(object):
self.existing_port = None
self.existing_weight = None
self.type = list[0]
- self.name = list[1].lower()
+ self.name = list[1]
if self.type == 'SRV':
if len(list) < 4:
raise Exception("Invalid DNS entry %r" % string_form)
- self.dest = list[2].lower()
+ self.dest = list[2]
self.port = list[3]
elif self.type in ['A', 'AAAA']:
self.ip = list[2] # usually $IP, which gets replaced
elif self.type == 'CNAME':
- self.dest = list[2].lower()
+ self.dest = list[2]
elif self.type == 'NS':
- self.dest = list[2].lower()
+ self.dest = list[2]
else:
- raise Exception("Received unexpected DNS reply of type %s" % self.type)
+ raise Exception("Received unexpected DNS reply of type %s: %s" % (self.type, string_form))
def __str__(self):
- if d.type == "A":
+ if self.type == "A":
return "%s %s %s" % (self.type, self.name, self.ip)
- if d.type == "AAAA":
+ if self.type == "AAAA":
return "%s %s %s" % (self.type, self.name, self.ip)
- if d.type == "SRV":
+ if self.type == "SRV":
return "%s %s %s %s" % (self.type, self.name, self.dest, self.port)
- if d.type == "CNAME":
+ if self.type == "CNAME":
return "%s %s %s" % (self.type, self.name, self.dest)
- if d.type == "NS":
+ if self.type == "NS":
return "%s %s %s" % (self.type, self.name, self.dest)
def parse_dns_line(line, sub_vars):
"""parse a DNS line from."""
if line.startswith("SRV _ldap._tcp.pdc._msdcs.") and not samdb.am_pdc():
+ # We keep this as compat to the dns_update_list of 4.0/4.1
if opts.verbose:
print "Skipping PDC entry (%s) as we are not a PDC" % line
return None
subline = samba.substitute_var(line, sub_vars)
+ if subline == '' or subline[0] == "#":
+ return None
return dnsobj(subline)
@@ -202,25 +207,6 @@ def check_dns_name(d):
return False
resolver = dns.resolver.Resolver()
- if d.type == "NS":
- # we need to lookup the nameserver for the parent domain,
- # and use that to check the NS record
- parent_domain = '.'.join(normalised_name.split('.')[1:])
- try:
- ans = resolver.query(parent_domain, 'NS')
- except dns.exception.DNSException:
- if opts.verbose:
- print "Failed to find parent NS for %s" % d
- return False
- nameservers = set()
- for i in range(len(ans)):
- try:
- ns = resolver.query(str(ans[i]), 'A')
- except dns.exception.DNSException:
- continue
- for j in range(len(ns)):
- nameservers.add(str(ns[j]))
- d.nameservers = list(nameservers)
try:
if getattr(d, 'nameservers', None):
@@ -273,17 +259,72 @@ def get_subst_vars(samdb):
res = samdb.search(base=samdb.get_default_basedn(), scope=SCOPE_BASE, attrs=["objectGUID"])
guid = samdb.schema_format_value("objectGUID", res[0]['objectGUID'][0])
vars['DOMAINGUID'] = guid
+
+ vars['IF_DC'] = ""
+ vars['IF_RWDC'] = "# "
+ vars['IF_RODC'] = "# "
+ vars['IF_PDC'] = "# "
+ vars['IF_GC'] = "# "
+ vars['IF_RWGC'] = "# "
+ vars['IF_ROGC'] = "# "
+ vars['IF_DNS_DOMAIN'] = "# "
+ vars['IF_RWDNS_DOMAIN'] = "# "
+ vars['IF_RODNS_DOMAIN'] = "# "
+ vars['IF_DNS_FOREST'] = "# "
+ vars['IF_RWDNS_FOREST'] = "# "
+ vars['IF_R0DNS_FOREST'] = "# "
+
am_rodc = samdb.am_rodc()
+ if am_rodc:
+ vars['IF_RODC'] = ""
+ else:
+ vars['IF_RWDC'] = ""
+
+ if samdb.am_pdc():
+ vars['IF_PDC'] = ""
+
+ # check if we "are DNS server"
+ res = samdb.search(base=samdb.get_config_basedn(),
+ expression='(objectguid=%s)' % vars['NTDSGUID'],
+ attrs=["options", "msDS-hasMasterNCs"])
+
+ if len(res) == 1:
+ if "options" in res[0]:
+ options = int(res[0]["options"][0])
+ if (options & dsdb.DS_NTDSDSA_OPT_IS_GC) != 0:
+ vars['IF_GC'] = ""
+ if am_rodc:
+ vars['IF_ROGC'] = ""
+ else:
+ vars['IF_RWGC'] = ""
+
+ basedn = str(samdb.get_default_basedn())
+ if "msDS-hasMasterNCs" in res[0]:
+ for e in res[0]["msDS-hasMasterNCs"]:
+ if str(e) == "DC=DomainDnsZones,%s" % basedn:
+ vars['IF_DNS_DOMAIN'] = ""
+ if am_rodc:
+ vars['IF_RODNS_DOMAIN'] = ""
+ else:
+ vars['IF_RWDNS_DOMAIN'] = ""
+ if str(e) == "DC=ForestDnsZones,%s" % basedn:
+ vars['IF_DNS_FOREST'] = ""
+ if am_rodc:
+ vars['IF_RODNS_FOREST'] = ""
+ else:
+ vars['IF_RWDNS_FOREST'] = ""
return vars
-def call_nsupdate(d):
+def call_nsupdate(d, op="add"):
"""call nsupdate for an entry."""
global ccachename, nsupdate_cmd, krb5conf
+ assert(op in ["add", "delete"])
+
if opts.verbose:
- print "Calling nsupdate for %s" % d
+ print "Calling nsupdate for %s (%s)" % (d, op)
if opts.use_file is not None:
try:
@@ -299,8 +340,13 @@ def call_nsupdate(d):
wfile = os.fdopen(tmp_fd, 'a')
rfile.seek(0)
for line in rfile:
+ if op == "delete":
+ l = parse_dns_line(line, {})
+ if str(l).lower() == str(d).lower():
+ continue
wfile.write(line)
- wfile.write(str(d)+"\n")
+ if op == "add":
+ wfile.write(str(d)+"\n")
os.rename(tmpfile, opts.use_file)
fcntl.lockf(rfile, fcntl.LOCK_UN)
return
@@ -312,18 +358,18 @@ def call_nsupdate(d):
if getattr(d, 'nameservers', None):
f.write('server %s\n' % d.nameservers[0])
if d.type == "A":
- f.write("update add %s %u A %s\n" % (normalised_name, default_ttl, d.ip))
+ f.write("update %s %s %u A %s\n" % (op, normalised_name, default_ttl, d.ip))
if d.type == "AAAA":
- f.write("update add %s %u AAAA %s\n" % (normalised_name, default_ttl, d.ip))
+ f.write("update %s %s %u AAAA %s\n" % (op, normalised_name, default_ttl, d.ip))
if d.type == "SRV":
- if d.existing_port is not None:
+ if op == "add" and d.existing_port is not None:
f.write("update delete %s SRV 0 %s %s %s\n" % (normalised_name, d.existing_weight,
d.existing_port, d.dest))
- f.write("update add %s %u SRV 0 100 %s %s\n" % (normalised_name, default_ttl, d.port, d.dest))
+ f.write("update %s %s %u SRV 0 100 %s %s\n" % (op, normalised_name, default_ttl, d.port, d.dest))
if d.type == "CNAME":
- f.write("update add %s %u CNAME %s\n" % (normalised_name, default_ttl, d.dest))
+ f.write("update %s %s %u CNAME %s\n" % (op, normalised_name, default_ttl, d.dest))
if d.type == "NS":
- f.write("update add %s %u NS %s\n" % (normalised_name, default_ttl, d.dest))
+ f.write("update %s %s %u NS %s\n" % (op, normalised_name, default_ttl, d.dest))
if opts.verbose:
f.write("show\n")
f.write("send\n")
@@ -359,10 +405,12 @@ def call_nsupdate(d):
-def rodc_dns_update(d, t):
+def rodc_dns_update(d, t, op):
'''a single DNS update via the RODC netlogon call'''
global sub_vars
+ assert(op in ["add", "delete"])
+
if opts.verbose:
print "Calling netlogon RODC update for %s" % d
@@ -386,7 +434,10 @@ def rodc_dns_update(d, t):
name.weight = 0
if d.port is not None:
name.port = int(d.port)
- name.dns_register = True
+ if op == "add":
+ name.dns_register = True
+ else:
+ name.dns_register = False
dns_names.names = [ name ]
site_name = sub_vars['SITE'].decode('utf-8')
@@ -405,10 +456,12 @@ def rodc_dns_update(d, t):
sys.exit(1)
-def call_rodc_update(d):
+def call_rodc_update(d, op="add"):
'''RODCs need to use the netlogon API for nsupdate'''
global lp, sub_vars
+ assert(op in ["add", "delete"])
+
# we expect failure for 3268 if we aren't a GC
if d.port is not None and int(d.port) == 3268:
return
@@ -428,7 +481,7 @@ def call_rodc_update(d):
subname = samba.substitute_var(map[t], sub_vars)
if subname.lower() == d.name.lower():
# found a match - do the update
- rodc_dns_update(d, t)
+ rodc_dns_update(d, t, op)
return
if opts.verbose:
print("Unable to map to netlogon DNS update: %s" % d)
@@ -440,6 +493,11 @@ if opts.update_list:
else:
dns_update_list = lp.private_path('dns_update_list')
+if opts.update_cache:
+ dns_update_cache = opts.update_cache
+else:
+ dns_update_cache = lp.private_path('dns_update_cache')
+
# use our private krb5.conf to avoid problems with the wrong domain
# bind9 nsupdate wants the default domain set
krb5conf = lp.private_path('krb5.conf')
@@ -458,8 +516,31 @@ else:
# build up a list of update commands to pass to nsupdate
update_list = []
dns_list = []
+cache_list = []
+delete_list = []
dup_set = set()
+cache_set = set()
+
+rebuild_cache = False
+try:
+ cfile = open(dns_update_cache, 'r+')
+except IOError:
+ # Perhaps create it
+ cfile = open(dns_update_cache, 'w+')
+ # Open it for reading again, in case someone else got to it first
+ cfile = open(dns_update_cache, 'r+')
+fcntl.lockf(cfile, fcntl.LOCK_EX)
+for line in cfile:
+ line = line.strip()
+ if line == '' or line[0] == "#":
+ continue
+ c = parse_dns_line(line, {})
+ if c is None:
+ continue
+ if str(c) not in cache_set:
+ cache_list.append(c)
+ cache_set.add(str(c))
# read each line, and check that the DNS name exists
for line in file:
@@ -497,17 +578,50 @@ for d in dns_list:
# now check if the entries already exist on the DNS server
for d in dns_list:
+ found = False
+ for c in cache_list:
+ if str(c).lower() == str(d).lower():
+ found = True
+ break
+ if not found:
+ rebuild_cache = True
if opts.all_names or not check_dns_name(d):
update_list.append(d)
-if len(update_list) == 0:
+for c in cache_list:
+ found = False
+ for d in dns_list:
+ if str(c).lower() == str(d).lower():
+ found = True
+ break
+ if found:
+ continue
+ rebuild_cache = True
+ if not opts.all_names and not check_dns_name(c):
+ continue
+ delete_list.append(c)
+
+if len(delete_list) == 0 and len(update_list) == 0 and not rebuild_cache:
if opts.verbose:
print "No DNS updates needed"
sys.exit(0)
# get our krb5 creds
-if not opts.nocreds:
- get_credentials(lp)
+if len(delete_list) != 0 or len(update_list) != 0:
+ if not opts.nocreds:
+ get_credentials(lp)
+
+# ask nsupdate to delete entries as needed
+for d in delete_list:
+ if am_rodc:
+ if d.name.lower() == domain.lower():
+ continue
+ if not d.type in [ 'A', 'AAAA' ]:
+ call_rodc_update(d, op="delete")
+ else:
+ call_nsupdate(d, op="delete")
+ else:
+ call_nsupdate(d, op="delete")
# ask nsupdate to add entries as needed
for d in update_list:
@@ -521,6 +635,15 @@ for d in update_list:
else:
call_nsupdate(d)
+if rebuild_cache:
+ (file_dir, file_name) = os.path.split(dns_update_cache)
+ (tmp_fd, tmpfile) = tempfile.mkstemp(dir=file_dir, prefix=file_name, suffix="XXXXXX")
+ wfile = os.fdopen(tmp_fd, 'a')
+ for d in dns_list:
+ wfile.write(str(d)+"\n")
+ os.rename(tmpfile, dns_update_cache)
+fcntl.lockf(cfile, fcntl.LOCK_UN)
+
# delete the ccache if we created it
if ccachename is not None:
os.unlink(ccachename)
diff --git a/source4/setup/dns_update_list b/source4/setup/dns_update_list
index 4da0398196e..deac459d7aa 100644
--- a/source4/setup/dns_update_list
+++ b/source4/setup/dns_update_list
@@ -1,39 +1,49 @@
# this is a list of DNS entries which will be put into DNS using
# dynamic DNS update. It is processed by the samba_dnsupdate script
-A ${DNSDOMAIN} $IP
-A ${HOSTNAME} $IP
-AAAA ${DNSDOMAIN} $IP
-AAAA ${HOSTNAME} $IP
+A ${HOSTNAME} $IP
+AAAA ${HOSTNAME} $IP
+
+# RW domain controller
+${IF_RWDC}A ${DNSDOMAIN} $IP
+${IF_RWDC}AAAA ${DNSDOMAIN} $IP
+${IF_RWDC}SRV _ldap._tcp.${DNSDOMAIN} ${HOSTNAME} 389
+${IF_RWDC}SRV _ldap._tcp.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
+${IF_RWDC}SRV _ldap._tcp.${DOMAINGUID}.domains._msdcs.${DNSFOREST} ${HOSTNAME} 389
+${IF_RWDC}SRV _kerberos._tcp.${DNSDOMAIN} ${HOSTNAME} 88
+${IF_RWDC}SRV _kerberos._udp.${DNSDOMAIN} ${HOSTNAME} 88
+${IF_RWDC}SRV _kerberos._tcp.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 88
+${IF_RWDC}SRV _kpasswd._tcp.${DNSDOMAIN} ${HOSTNAME} 464
+${IF_RWDC}SRV _kpasswd._udp.${DNSDOMAIN} ${HOSTNAME} 464
+# RW and RO domain controller
+${IF_DC}CNAME ${NTDSGUID}._msdcs.${DNSFOREST} ${HOSTNAME}
+${IF_DC}SRV _ldap._tcp.${SITE}._sites.${DNSDOMAIN} ${HOSTNAME} 389
+${IF_DC}SRV _ldap._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
+${IF_DC}SRV _kerberos._tcp.${SITE}._sites.${DNSDOMAIN} ${HOSTNAME} 88
+${IF_DC}SRV _kerberos._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 88
+
+# The PDC emulator
+${IF_PDC}SRV _ldap._tcp.pdc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
+
+# RW GC servers
+${IF_RWGC}A gc._msdcs.${DNSFOREST} $IP
+${IF_RWGC}AAAA gc._msdcs.${DNSFOREST} $IP
+${IF_RWGC}SRV _gc._tcp.${DNSFOREST} ${HOSTNAME} 3268
+${IF_RWGC}SRV _ldap._tcp.gc._msdcs.${DNSFOREST} ${HOSTNAME} 3268
+# RW and RO GC servers
+${IF_GC}SRV _gc._tcp.${SITE}._sites.${DNSFOREST} ${HOSTNAME} 3268
+${IF_GC}SRV _ldap._tcp.${SITE}._sites.gc._msdcs.${DNSFOREST} ${HOSTNAME} 3268
+
+# RW DNS servers
+${IF_RWDNS_DOMAIN}A DomainDnsZones.${DNSDOMAIN} $IP
+${IF_RWDNS_DOMAIN}AAAA DomainDnsZones.${DNSDOMAIN} $IP
+${IF_RWDNS_DOMAIN}SRV _ldap._tcp.DomainDnsZones.${DNSDOMAIN} ${HOSTNAME} 389
+# RW and RO DNS servers
+${IF_DNS_DOMAIN}SRV _ldap._tcp.${SITE}._sites.DomainDnsZones.${DNSDOMAIN} ${HOSTNAME} 389
+
+# RW DNS servers
+${IF_RWDNS_FOREST}A ForestDnsZones.${DNSFOREST} $IP
+${IF_RWDNS_FOREST}AAAA ForestDnsZones.${DNSFOREST} $IP
+${IF_RWDNS_FOREST}SRV _ldap._tcp.ForestDnsZones.${DNSFOREST} ${HOSTNAME} 389
+# RW and RO DNS servers
+${IF_DNS_FOREST}SRV _ldap._tcp.${SITE}._sites.ForestDnsZones.${DNSFOREST} ${HOSTNAME} 389
-A gc._msdcs.${DNSFOREST} $IP
-AAAA gc._msdcs.${DNSFOREST} $IP
-
-CNAME ${NTDSGUID}._msdcs.${DNSFOREST} ${HOSTNAME}
-
-SRV _kpasswd._tcp.${DNSDOMAIN} ${HOSTNAME} 464
-SRV _kpasswd._udp.${DNSDOMAIN} ${HOSTNAME} 464
-
-SRV _kerberos._tcp.${DNSDOMAIN} ${HOSTNAME} 88
-SRV _kerberos._tcp.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 88
-SRV _kerberos._tcp.dc._msdcs.${DNSFOREST} ${HOSTNAME} 88
-SRV _kerberos._tcp.${SITE}._sites.${DNSDOMAIN} ${HOSTNAME} 88
-SRV _kerberos._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 88
-SRV _kerberos._tcp.${SITE}._sites.dc._msdcs.${DNSFOREST} ${HOSTNAME} 88
-
-SRV _kerberos._udp.${DNSDOMAIN} ${HOSTNAME} 88
-
-SRV _ldap._tcp.${DNSDOMAIN} ${HOSTNAME} 389
-SRV _ldap._tcp.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
-SRV _ldap._tcp.dc._msdcs.${DNSFOREST} ${HOSTNAME} 389
-SRV _ldap._tcp.gc._msdcs.${DNSFOREST} ${HOSTNAME} 3268
-SRV _ldap._tcp.pdc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
-SRV _ldap._tcp.pdc._msdcs.${DNSFOREST} ${HOSTNAME} 389
-SRV _ldap._tcp.${SITE}._sites.${DNSDOMAIN} ${HOSTNAME} 389
-SRV _ldap._tcp.${SITE}._sites.dc._msdcs.${DNSDOMAIN} ${HOSTNAME} 389
-SRV _ldap._tcp.${SITE}._sites.dc._msdcs.${DNSFOREST} ${HOSTNAME} 389
-SRV _ldap._tcp.${SITE}._sites.gc._msdcs.${DNSFOREST} ${HOSTNAME} 3268
-SRV _ldap._tcp.${DOMAINGUID}.domains._msdcs.${DNSFOREST} ${HOSTNAME} 389
-
-
-SRV _gc._tcp.${DNSFOREST} ${HOSTNAME} 3268
-SRV _gc._tcp.${SITE}._sites.${DNSFOREST} ${HOSTNAME} 3268
diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c
index d7d1736a6fa..fa6967dc761 100644
--- a/source4/torture/dns/dlz_bind9.c
+++ b/source4/torture/dns/dlz_bind9.c
@@ -61,7 +61,7 @@ static bool test_dlz_bind9_create(struct torture_context *tctx)
NULL
};
tctx_static = tctx;
- torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata,
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
"log", dlz_bind9_log_wrapper, NULL), ISC_R_SUCCESS,
"Failed to create samba_dlz");
@@ -109,7 +109,7 @@ static bool test_dlz_bind9_configure(struct torture_context *tctx)
NULL
};
tctx_static = tctx;
- torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata,
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
"log", dlz_bind9_log_wrapper,
"writeable_zone", dlz_bind9_writeable_zone_hook, NULL),
ISC_R_SUCCESS,
@@ -144,7 +144,7 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech
NULL
};
tctx_static = tctx;
- torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata,
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
"log", dlz_bind9_log_wrapper,
"writeable_zone", dlz_bind9_writeable_zone_hook, NULL),
ISC_R_SUCCESS,
@@ -158,9 +158,19 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech
lpcfg_gensec_settings(tctx, tctx->lp_ctx));
torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
- status = gensec_set_target_hostname(gensec_client_context, torture_setting_string(tctx, "host", NULL));
+ /*
+ * dlz_bind9 use the special dns/host.domain account
+ */
+ status = gensec_set_target_hostname(gensec_client_context,
+ talloc_asprintf(tctx,
+ "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx)));
torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+ status = gensec_set_target_service(gensec_client_context, "dns");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");
+
status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
@@ -181,7 +191,7 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech
client_to_server.length,
client_to_server.data,
dbdata),
- ISC_R_SUCCESS,
+ ISC_TRUE,
"Failed to check key for update rights samba_dlz");
dlz_destroy(dbdata);
@@ -199,6 +209,850 @@ static bool test_dlz_bind9_spnego(struct torture_context *tctx)
return test_dlz_bind9_gensec(tctx, "GSS-SPNEGO");
}
+struct test_expected_record {
+ const char *name;
+ const char *type;
+ const char *data;
+ int ttl;
+ bool printed;
+};
+
+struct test_expected_rr {
+ struct torture_context *tctx;
+ const char *query_name;
+ size_t num_records;
+ struct test_expected_record *records;
+ size_t num_rr;
+};
+
+static bool dlz_bind9_putnamedrr_torture_hook(struct test_expected_rr *expected,
+ const char *name,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ size_t i;
+
+ torture_assert(expected->tctx, name != NULL,
+ talloc_asprintf(expected->tctx,
+ "Got unnamed record type[%s] data[%s]\n",
+ type, data));
+
+ expected->num_rr++;
+ torture_comment(expected->tctx, "%u: name[%s] type[%s] ttl[%u] data[%s]\n",
+ (unsigned)expected->num_rr, name, type, (unsigned)ttl, data);
+
+ for (i = 0; i < expected->num_records; i++) {
+ if (expected->records[i].name != NULL) {
+ if (strcmp(name, expected->records[i].name) != 0) {
+ continue;
+ }
+ }
+
+ if (strcmp(type, expected->records[i].type) != 0) {
+ continue;
+ }
+
+ if (expected->records[i].data != NULL) {
+ if (strcmp(data, expected->records[i].data) != 0) {
+ continue;
+ }
+ }
+
+ torture_assert_int_equal(expected->tctx, ttl,
+ expected->records[i].ttl,
+ talloc_asprintf(expected->tctx,
+ "TTL did not match expectations for type %s",
+ type));
+
+ expected->records[i].printed = true;
+ }
+
+ return true;
+}
+
+static isc_result_t dlz_bind9_putrr_hook(dns_sdlzlookup_t *lookup,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ struct test_expected_rr *expected =
+ talloc_get_type_abort(lookup, struct test_expected_rr);
+ bool ok;
+
+ ok = dlz_bind9_putnamedrr_torture_hook(expected, expected->query_name,
+ type, ttl, data);
+ if (!ok) {
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t dlz_bind9_putnamedrr_hook(dns_sdlzallnodes_t *allnodes,
+ const char *name,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ struct test_expected_rr *expected =
+ talloc_get_type_abort(allnodes, struct test_expected_rr);
+ bool ok;
+
+ ok = dlz_bind9_putnamedrr_torture_hook(expected, name, type, ttl, data);
+ if (!ok) {
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * Tests some lookups
+ */
+static bool test_dlz_bind9_lookup(struct torture_context *tctx)
+{
+ size_t i;
+ void *dbdata;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+ struct test_expected_rr *expected2 = NULL;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->query_name = "@";
+
+ expected1->num_records = 4;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = expected1->query_name;
+ expected1->records[0].type = "soa";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = talloc_asprintf(expected1->records,
+ "%s.%s hostmaster.%s 1 900 600 86400 3600",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed");
+
+ expected1->records[1].name = expected1->query_name;
+ expected1->records[1].type = "ns";
+ expected1->records[1].ttl = 900;
+ expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed");
+
+ expected1->records[2].name = expected1->query_name;
+ expected1->records[2].type = "aaaa";
+ expected1->records[2].ttl = 900;
+
+ expected1->records[3].name = expected1->query_name;
+ expected1->records[3].type = "a";
+ expected1->records[3].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Failed to lookup @");
+ for (i = 0; i < expected1->num_records; i++) {
+ torture_assert(tctx, expected1->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run for type %s",
+ expected1->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected1->num_rr,
+ expected1->num_records,
+ "Got too much data");
+
+ expected2 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected2 != NULL, "talloc failed");
+ expected2->tctx = tctx;
+
+ expected2->query_name = torture_setting_string(tctx, "host", NULL);
+ torture_assert(tctx, expected2->query_name != NULL, "unknown host");
+
+ expected2->num_records = 2;
+ expected2->records = talloc_zero_array(expected2,
+ struct test_expected_record,
+ expected2->num_records);
+ torture_assert(tctx, expected2->records != NULL, "talloc failed");
+
+ expected2->records[0].name = expected2->query_name;
+ expected2->records[0].type = "aaaa";
+ expected2->records[0].ttl = 900;
+
+ expected2->records[1].name = expected2->query_name;
+ expected2->records[1].type = "a";
+ expected2->records[1].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected2->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected2),
+ ISC_R_SUCCESS,
+ "Failed to lookup hostname");
+ for (i = 0; i < expected2->num_records; i++) {
+ torture_assert(tctx, expected2->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected2->records[i].name,
+ expected2->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected2->num_rr,
+ expected2->num_records,
+ "Got too much data");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+/*
+ * Test some zone dumps
+ */
+static bool test_dlz_bind9_zonedump(struct torture_context *tctx)
+{
+ size_t i;
+ void *dbdata;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->num_records = 7;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = lpcfg_dnsdomain(tctx->lp_ctx);
+ expected1->records[0].type = "soa";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = talloc_asprintf(expected1->records,
+ "%s.%s hostmaster.%s 1 900 600 86400 3600",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed");
+
+ expected1->records[1].name = lpcfg_dnsdomain(tctx->lp_ctx);
+ expected1->records[1].type = "ns";
+ expected1->records[1].ttl = 900;
+ expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed");
+
+ expected1->records[2].name = lpcfg_dnsdomain(tctx->lp_ctx);
+ expected1->records[2].type = "aaaa";
+ expected1->records[2].ttl = 900;
+
+ expected1->records[3].name = lpcfg_dnsdomain(tctx->lp_ctx);
+ expected1->records[3].type = "a";
+ expected1->records[3].ttl = 900;
+
+ expected1->records[4].name = talloc_asprintf(expected1->records, "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[4].name != NULL, "unknown host");
+ expected1->records[4].type = "aaaa";
+ expected1->records[4].ttl = 900;
+
+ expected1->records[5].name = talloc_asprintf(expected1->records, "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[5].name != NULL, "unknown host");
+ expected1->records[5].type = "a";
+ expected1->records[5].ttl = 900;
+
+ /*
+ * We expect multiple srv records
+ */
+ expected1->records[6].name = NULL;
+ expected1->records[6].type = "srv";
+ expected1->records[6].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_allnodes(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, (dns_sdlzallnodes_t *)expected1),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+ for (i = 0; i < expected1->num_records; i++) {
+ torture_assert(tctx, expected1->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[i].name,
+ expected1->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected1->num_rr, 24,
+ "Got wrong record count");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+/*
+ * Test some updates
+ */
+static bool test_dlz_bind9_update01(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct gensec_security *gensec_client_context;
+ DATA_BLOB client_to_server, server_to_client;
+ void *dbdata;
+ void *version = NULL;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+ char *name = NULL;
+ char *data0 = NULL;
+ char *data1 = NULL;
+ char *data2 = NULL;
+ bool ret = false;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->query_name = __func__;
+
+ name = talloc_asprintf(expected1, "%s.%s",
+ expected1->query_name,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, name != NULL, "talloc failed");
+
+ expected1->num_records = 2;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = expected1->query_name;
+ expected1->records[0].type = "a";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = "127.1.2.3";
+ expected1->records[0].printed = false;
+
+ data0 = talloc_asprintf(expected1,
+ "%s.\t" "%u\t" "%s\t" "%s\t" "%s",
+ name,
+ (unsigned)expected1->records[0].ttl,
+ "in",
+ expected1->records[0].type,
+ expected1->records[0].data);
+ torture_assert(tctx, data0 != NULL, "talloc failed");
+
+ expected1->records[1].name = expected1->query_name;
+ expected1->records[1].type = "a";
+ expected1->records[1].ttl = 3600;
+ expected1->records[1].data = "127.3.2.1";
+ expected1->records[1].printed = false;
+
+ data1 = talloc_asprintf(expected1,
+ "%s.\t" "%u\t" "%s\t" "%s\t" "%s",
+ name,
+ (unsigned)expected1->records[1].ttl,
+ "in",
+ expected1->records[1].type,
+ expected1->records[1].data);
+ torture_assert(tctx, data1 != NULL, "talloc failed");
+
+ data2 = talloc_asprintf(expected1,
+ "%s.\t" "0\t" "in\t" "a\t" "127.3.3.3",
+ name);
+ torture_assert(tctx, data2 != NULL, "talloc failed");
+
+ /*
+ * Prepare session info
+ */
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ /*
+ * dlz_bind9 use the special dns/host.domain account
+ */
+ status = gensec_set_target_hostname(gensec_client_context,
+ talloc_asprintf(tctx,
+ "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx)));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+
+ status = gensec_set_target_service(gensec_client_context, "dns");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");
+
+ status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSS-SPNEGO");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ /* Do one step of the client-server update dance */
+ status = gensec_update(gensec_client_context, tctx, tctx->ev, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ torture_assert_int_equal(tctx, dlz_ssumatch(cli_credentials_get_username(cmdline_credentials),
+ name,
+ "127.0.0.1",
+ expected1->records[0].type,
+ "key",
+ client_to_server.length,
+ client_to_server.data,
+ dbdata),
+ ISC_TRUE,
+ "Failed to check key for update rights samba_dlz");
+
+ /*
+ * We test the following:
+ *
+ * 1. lookup the records => NOT_FOUND
+ * 2. delete all records => NOT_FOUND
+ * 3. delete 1st record => NOT_FOUND
+ * 4. create 1st record => SUCCESS
+ * 5. lookup the records => found 1st
+ * 6. create 2nd record => SUCCESS
+ * 7. lookup the records => found 1st and 2nd
+ * 8. delete unknown record => NOT_FOUND
+ * 9. lookup the records => found 1st and 2nd
+ * 10. delete 1st record => SUCCESS
+ * 11. lookup the records => found 2nd
+ * 12. delete 2nd record => SUCCESS
+ * 13. lookup the records => NOT_FOUND
+ * 14. create 1st record => SUCCESS
+ * 15. lookup the records => found 1st
+ * 16. create 2nd record => SUCCESS
+ * 17. lookup the records => found 1st and 2nd
+ * 18. update 1st record => SUCCESS
+ * 19. lookup the records => found 1st and 2nd
+ * 20. delete all unknown type records => NOT_FOUND
+ * 21. lookup the records => found 1st and 2nd
+ * 22. delete all records => SUCCESS
+ * 23. lookup the records => NOT_FOUND
+ */
+
+ /* Step 1. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ /* Step 2. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name,
+ expected1->records[0].type,
+ dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
+ name, expected1->records[0].type));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 3. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data0, dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 4. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 5. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 6. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 7. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 8. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data2, dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
+ name, data2));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 9. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 10. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 11. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 12. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 13. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ /* Step 14. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 15. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 16. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 17. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 18. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to update name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 19. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 20. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name, "txt", dbdata, version),
+ ISC_R_FAILURE, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
+ name, "txt"));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 21. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 22. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name,
+ expected1->records[0].type,
+ dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] type[%s]\n",
+ name, expected1->records[0].type));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 23. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ dlz_destroy(dbdata);
+
+ return true;
+
+cancel_version:
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+ return ret;
+}
+
static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx)
{
struct torture_suite *suite = torture_suite_create(ctx, "dlz_bind9");
@@ -210,12 +1064,16 @@ static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx)
torture_suite_add_simple_test(suite, "configure", test_dlz_bind9_configure);
torture_suite_add_simple_test(suite, "gssapi", test_dlz_bind9_gssapi);
torture_suite_add_simple_test(suite, "spnego", test_dlz_bind9_spnego);
+ torture_suite_add_simple_test(suite, "lookup", test_dlz_bind9_lookup);
+ torture_suite_add_simple_test(suite, "zonedump", test_dlz_bind9_zonedump);
+ torture_suite_add_simple_test(suite, "update01", test_dlz_bind9_update01);
return suite;
}
/**
* DNS torture module initialization
*/
+NTSTATUS torture_bind_dns_init(void);
NTSTATUS torture_bind_dns_init(void)
{
struct torture_suite *suite;
diff --git a/source4/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c
index 89eb1a0022a..5f097fedd01 100644
--- a/source4/torture/ntp/ntp_signd.c
+++ b/source4/torture/ntp/ntp_signd.c
@@ -113,6 +113,7 @@ static bool test_ntp_signd(struct torture_context *tctx,
creds = netlogon_creds_client_init(tctx, a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
&credentials1, &credentials2,
pwhash, &credentials3,
negotiate_flags);
diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
index 107af110886..7385ad4b911 100644
--- a/source4/torture/rpc/lsa.c
+++ b/source4/torture/rpc/lsa.c
@@ -2715,6 +2715,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p,
creds = netlogon_creds_client_init(tctx, a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
&credentials1, &credentials2,
&mach_password, &credentials3,
negotiate_flags);
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index dadf8bc4f98..7569117ddd5 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -173,6 +173,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
creds = netlogon_creds_client_init(tctx, a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
&credentials1, &credentials2,
mach_password, &credentials3,
0);
@@ -201,28 +202,28 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
return true;
}
-bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
- uint32_t negotiate_flags,
- struct cli_credentials *machine_credentials,
- enum netr_SchannelType sec_chan_type,
- struct netlogon_creds_CredentialState **creds_out)
+bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ const char *computer_name,
+ enum netr_SchannelType sec_chan_type,
+ NTSTATUS expected_result,
+ struct netlogon_creds_CredentialState **creds_out)
{
struct netr_ServerReqChallenge r;
struct netr_ServerAuthenticate2 a;
struct netr_Credential credentials1, credentials2, credentials3;
struct netlogon_creds_CredentialState *creds;
const struct samr_Password *mach_password;
- const char *machine_name;
struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *account_name = cli_credentials_get_username(machine_credentials);
mach_password = cli_credentials_get_nt_hash(machine_credentials, tctx);
- machine_name = cli_credentials_get_workstation(machine_credentials);
torture_comment(tctx, "Testing ServerReqChallenge\n");
-
r.in.server_name = NULL;
- r.in.computer_name = machine_name;
+ r.in.computer_name = computer_name;
r.in.credentials = &credentials1;
r.out.return_credentials = &credentials2;
@@ -233,9 +234,9 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
a.in.server_name = NULL;
- a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.account_name = account_name;
a.in.secure_channel_type = sec_chan_type;
- a.in.computer_name = machine_name;
+ a.in.computer_name = computer_name;
a.in.negotiate_flags = &negotiate_flags;
a.out.negotiate_flags = &negotiate_flags;
a.in.credentials = &credentials3;
@@ -243,6 +244,7 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
creds = netlogon_creds_client_init(tctx, a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
&credentials1, &credentials2,
mach_password, &credentials3,
negotiate_flags);
@@ -253,10 +255,16 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
"ServerAuthenticate2 failed");
- torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(tctx, a.out.result, expected_result,
+ "ServerAuthenticate2 unexpected");
- torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3),
- "Credential chaining failed");
+ if (NT_STATUS_IS_OK(expected_result)) {
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining failed");
+ } else {
+ torture_assert(tctx, !netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining passed unexptected");
+ }
torture_comment(tctx, "negotiate_flags=0x%08x\n", negotiate_flags);
@@ -264,6 +272,22 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
return true;
}
+bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ enum netr_SchannelType sec_chan_type,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ const char *computer_name =
+ cli_credentials_get_workstation(machine_credentials);
+
+ return test_SetupCredentials2ex(p, tctx, negotiate_flags,
+ machine_credentials,
+ computer_name,
+ sec_chan_type,
+ NT_STATUS_OK,
+ creds_out);
+}
bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
uint32_t negotiate_flags,
@@ -310,6 +334,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
creds = netlogon_creds_client_init(tctx, a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
&credentials1, &credentials2,
&mach_password, &credentials3,
negotiate_flags);
@@ -1041,6 +1066,115 @@ static bool test_SamLogon(struct torture_context *tctx,
return test_netlogon_ops(p, tctx, credentials, creds);
}
+static bool test_invalidAuthenticate2(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netlogon_creds_CredentialState *creds;
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+
+ torture_comment(tctx, "Testing invalidAuthenticate2\n");
+
+ if (!test_SetupCredentials2(p, tctx, flags,
+ credentials,
+ cli_credentials_get_secure_channel_type(credentials),
+ &creds)) {
+ return false;
+ }
+
+ if (!test_SetupCredentials2ex(p, tctx, flags,
+ credentials,
+ "1234567890123456",
+ cli_credentials_get_secure_channel_type(credentials),
+ STATUS_BUFFER_OVERFLOW,
+ &creds)) {
+ return false;
+ }
+
+ if (!test_SetupCredentials2ex(p, tctx, flags,
+ credentials,
+ "123456789012345",
+ cli_credentials_get_secure_channel_type(credentials),
+ NT_STATUS_OK,
+ &creds)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_ServerReqChallengeGlobal(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ plain_pass = cli_credentials_get_password(machine_credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b2");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ return true;
+}
+
static bool test_SamLogon_NULL_domain(struct torture_context *tctx,
struct dcerpc_pipe *p,
struct cli_credentials *credentials)
@@ -3880,6 +4014,8 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx)
torture_rpc_tcase_add_test(tcase, "LogonUasLogon", test_LogonUasLogon);
torture_rpc_tcase_add_test(tcase, "LogonUasLogoff", test_LogonUasLogoff);
torture_rpc_tcase_add_test_creds(tcase, "SamLogon", test_SamLogon);
+ torture_rpc_tcase_add_test_creds(tcase, "invalidAuthenticate2", test_invalidAuthenticate2);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeGlobal", test_ServerReqChallengeGlobal);
torture_rpc_tcase_add_test_creds(tcase, "SetPassword", test_SetPassword);
torture_rpc_tcase_add_test_creds(tcase, "SetPassword2", test_SetPassword2);
torture_rpc_tcase_add_test_creds(tcase, "SetPassword2_AES", test_SetPassword2_AES);
diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c
index 9443d5e8480..432e9d53509 100644
--- a/source4/torture/rpc/samba3rpc.c
+++ b/source4/torture/rpc/samba3rpc.c
@@ -1015,6 +1015,7 @@ static bool auth2(struct torture_context *tctx,
creds_state = netlogon_creds_client_init(mem_ctx,
a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
r.in.credentials,
r.out.return_credentials, &mach_pw,
&netr_cred, negotiate_flags);
@@ -2146,6 +2147,7 @@ static bool torture_samba3_rpc_randomauth2(struct torture_context *torture)
creds_state = netlogon_creds_client_init(mem_ctx,
a.in.account_name,
a.in.computer_name,
+ a.in.secure_channel_type,
r.in.credentials,
r.out.return_credentials, &mach_pw,
&netr_cred, negotiate_flags);