summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW.txt55
-rw-r--r--auth/kerberos/kerberos_pac.c47
-rw-r--r--docs-xml/manpages/idmap_ad.8.xml10
-rw-r--r--lib/krb5_wrap/krb5_samba.h28
-rw-r--r--libcli/http/http.c309
-rw-r--r--libcli/http/http_internal.h4
-rwxr-xr-xnsswitch/tests/test_idmap_ad.sh22
-rw-r--r--packaging/systemd/samba-bgqd.service.in16
-rw-r--r--packaging/wscript_build3
-rw-r--r--python/samba/tests/blackbox/http_chunk.py129
-rw-r--r--python/samba/tests/blackbox/http_content.py95
-rw-r--r--python/samba/tests/blackbox/smbcacls_propagate_inhertance.py108
-rwxr-xr-xselftest/target/Samba3.pm1
-rw-r--r--selftest/tests.py2
-rw-r--r--source3/utils/smbcacls.c4
-rw-r--r--source3/winbindd/winbindd_ads.c11
-rw-r--r--source4/client/http_test.c401
-rw-r--r--source4/dns_server/dnsserver_common.c9
-rw-r--r--source4/wscript_build5
20 files changed, 1212 insertions, 49 deletions
diff --git a/VERSION b/VERSION
index 482360b..cfa7539 100644
--- a/VERSION
+++ b/VERSION
@@ -27,7 +27,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew Tridgell and the Samba Team 1992-2024"
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=20
-SAMBA_VERSION_RELEASE=0
+SAMBA_VERSION_RELEASE=1
########################################################
# If a official release has a serious bug #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 5c97836..8249e93 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,59 @@
==============================
+ Release Notes for Samba 4.20.1
+ May 08, 2024
+ ==============================
+
+
+This is the latest stable release of the Samba 4.20 release series.
+
+
+Changes since 4.20.0
+--------------------
+
+o Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+ * BUG 15630: dns update debug message is too noisy.
+
+o Alexander Bokovoy <ab@samba.org>
+ * BUG 15635: Do not fail PAC validation for RFC8009 checksums types.
+
+o Pavel Filipenský <pfilipensky@samba.org>
+ * BUG 15605: Improve performance of lookup_groupmem() in idmap_ad.
+
+o Anna Popova <popova.anna235@gmail.com>
+ * BUG 15636: Smbcacls incorrectly propagates inheritance with Inherit-Only
+ flag.
+
+o Noel Power <noel.power@suse.com>
+ * BUG 15611: http library doesn't support 'chunked transfer encoding'.
+
+o Andreas Schneider <asn@samba.org>
+ * BUG 15600: Provide a systemd service file for the background queue daemon.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical:matrix.org matrix room, or
+#samba-technical IRC channel on irc.libera.chat.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+ ==============================
Release Notes for Samba 4.20.0
March 27, 2024
==============================
diff --git a/auth/kerberos/kerberos_pac.c b/auth/kerberos/kerberos_pac.c
index ae4557b..b6272ac 100644
--- a/auth/kerberos/kerberos_pac.c
+++ b/auth/kerberos/kerberos_pac.c
@@ -33,6 +33,7 @@
#include "librpc/gen_ndr/auth.h"
#include "auth/common_auth.h"
#include "auth/kerberos/pac_utils.h"
+#include "lib/krb5_wrap/krb5_samba.h"
krb5_error_code check_pac_checksum(DATA_BLOB pac_data,
struct PAC_SIGNATURE_DATA *sig,
@@ -44,26 +45,34 @@ krb5_error_code check_pac_checksum(DATA_BLOB pac_data,
krb5_keyusage usage = 0;
krb5_boolean checksum_valid = false;
krb5_data input;
-
- switch (sig->type) {
- case CKSUMTYPE_HMAC_MD5:
- /* ignores the key type */
- break;
- case CKSUMTYPE_HMAC_SHA1_96_AES_256:
- if (KRB5_KEY_TYPE(keyblock) != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
- return EINVAL;
- }
- /* ok */
- break;
- case CKSUMTYPE_HMAC_SHA1_96_AES_128:
- if (KRB5_KEY_TYPE(keyblock) != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
- return EINVAL;
+ size_t idx = 0;
+ struct {
+ krb5_cksumtype cksum_type;
+ krb5_enctype enc_type;
+ } supported_types[] = {
+ {CKSUMTYPE_HMAC_SHA1_96_AES_256, ENCTYPE_AES256_CTS_HMAC_SHA1_96},
+ {CKSUMTYPE_HMAC_SHA1_96_AES_128, ENCTYPE_AES128_CTS_HMAC_SHA1_96},
+ /* RFC8009 types. Not supported by AD yet but used by FreeIPA and MIT Kerberos */
+ {CKSUMTYPE_HMAC_SHA256_128_AES128, ENCTYPE_AES128_CTS_HMAC_SHA256_128},
+ {CKSUMTYPE_HMAC_SHA384_192_AES256, ENCTYPE_AES256_CTS_HMAC_SHA384_192},
+ {0, 0},
+ };
+
+ for(idx = 0; supported_types[idx].cksum_type != 0; idx++) {
+ if (sig->type == supported_types[idx].cksum_type) {
+ if (KRB5_KEY_TYPE(keyblock) != supported_types[idx].enc_type) {
+ return EINVAL;
+ }
+ /* ok */
+ break;
}
- /* ok */
- break;
- default:
- DEBUG(2,("check_pac_checksum: Checksum Type %"PRIu32" is not supported\n",
- sig->type));
+ }
+
+ /* do not do key type check for HMAC-MD5 */
+ if ((sig->type != CKSUMTYPE_HMAC_MD5) &&
+ (supported_types[idx].cksum_type == 0)) {
+ DEBUG(2,("check_pac_checksum: Checksum Type %d is not supported\n",
+ (int)sig->type));
return EINVAL;
}
diff --git a/docs-xml/manpages/idmap_ad.8.xml b/docs-xml/manpages/idmap_ad.8.xml
index 32df8d0..c7fcc65 100644
--- a/docs-xml/manpages/idmap_ad.8.xml
+++ b/docs-xml/manpages/idmap_ad.8.xml
@@ -105,6 +105,16 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term>all_groupmem = yes/no</term>
+ <listitem><para>
+ If set to <parameter>yes</parameter> winbind will retrieve all
+ group members for getgrnam(3), getgrgid(3) and getgrent(3) calls,
+ including those with missing uidNumber.
+ </para>
+ <para>Default: no</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term>deny ous</term>
<listitem><para>This parameter is a list of OUs from
which objects will not be mapped via the ad idmap
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
index e158a40..7951064 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -89,6 +89,34 @@
#endif
/*
+ * RFC8009 encryption types' defines have different names:
+ *
+ * KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128 in Heimdal
+ * ENCTYPE_AES128_CTS_HMAC_SHA256_128 in MIT
+ *
+ * and
+ *
+ * KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192 in Heimdal
+ * ENCTYPE_AES256_CTS_HMAC_SHA384_192 in MIT
+ */
+#if !defined(ENCTYPE_AES128_CTS_HMAC_SHA256_128)
+#define ENCTYPE_AES128_CTS_HMAC_SHA256_128 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128
+#endif
+#if !defined(ENCTYPE_AES256_CTS_HMAC_SHA384_192)
+#define ENCTYPE_AES256_CTS_HMAC_SHA384_192 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192
+#endif
+
+/*
+ * Same for older encryption types, rename to have the same defines
+ */
+#if !defined(ENCTYPE_AES128_CTS_HMAC_SHA1_96)
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+#endif
+#if !defined(ENCTYPE_AES256_CTS_HMAC_SHA1_96)
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+#endif
+
+/*
* KRB5_KU_OTHER_ENCRYPTED in Heimdal
* KRB5_KEYUSAGE_APP_DATA_ENCRYPT in MIT
*/
diff --git a/libcli/http/http.c b/libcli/http/http.c
index 96c573a..6f22214 100644
--- a/libcli/http/http.c
+++ b/libcli/http/http.c
@@ -28,16 +28,28 @@
#undef strcasecmp
+enum http_body_type {
+ BODY_NONE = 0,
+ BODY_CONTENT_LENGTH,
+ BODY_CHUNKED,
+ BODY_ERROR = -1
+};
+
/**
* Determines if a response should have a body.
- * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
- * a body. Returns -1 on error.
+ * @return 2 if response MUST use chunked encoding,
+ * 1 if the response MUST have a body;
+ * 0 if the response MUST NOT have a body.
+ * Returns -1 on error.
*/
-static int http_response_needs_body(struct http_request *req)
+static enum http_body_type http_response_needs_body(
+ struct http_request *req)
{
struct http_header *h = NULL;
- if (!req) return -1;
+ if (!req) {
+ return BODY_ERROR;
+ }
for (h = req->headers; h != NULL; h = h->next) {
int cmp;
@@ -45,6 +57,18 @@ static int http_response_needs_body(struct http_request *req)
char c;
unsigned long long v;
+ cmp = strcasecmp(h->key, "Transfer-Encoding");
+ if (cmp == 0) {
+ cmp = strcasecmp(h->value, "chunked");
+ if (cmp == 0) {
+ return BODY_CHUNKED;
+ }
+ /* unsupported Transfer-Encoding type */
+ DBG_ERR("Unsupported transfer encoding type %s\n",
+ h->value);
+ return BODY_ERROR;
+ }
+
cmp = strcasecmp(h->key, "Content-Length");
if (cmp != 0) {
continue;
@@ -52,20 +76,25 @@ static int http_response_needs_body(struct http_request *req)
n = sscanf(h->value, "%llu%c", &v, &c);
if (n != 1) {
- return -1;
+ return BODY_ERROR;
}
req->remaining_content_length = v;
if (v != 0) {
- return 1;
+ return BODY_CONTENT_LENGTH;
}
- return 0;
+ return BODY_NONE;
}
- return 0;
+ return BODY_NONE;
}
+struct http_chunk
+{
+ struct http_chunk *prev, *next;
+ DATA_BLOB blob;
+};
struct http_read_response_state {
enum http_parser_state parser_state;
@@ -73,6 +102,7 @@ struct http_read_response_state {
uint64_t max_content_length;
DATA_BLOB buffer;
struct http_request *response;
+ struct http_chunk *chunks;
};
/**
@@ -86,7 +116,7 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
char *key = NULL;
char *value = NULL;
int n = 0;
- int ret;
+ enum http_body_type ret;
/* Sanity checks */
if (!state || !state->response) {
@@ -119,19 +149,24 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
ret = http_response_needs_body(state->response);
switch (ret) {
- case 1:
+ case BODY_CHUNKED:
+ DEBUG(11, ("%s: need to process chunks... %d\n", __func__,
+ state->response->response_code));
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ break;
+ case BODY_CONTENT_LENGTH:
if (state->response->remaining_content_length <= state->max_content_length) {
DEBUG(11, ("%s: Start of read body\n", __func__));
state->parser_state = HTTP_READING_BODY;
break;
}
FALL_THROUGH;
- case 0:
+ case BODY_NONE:
DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
state->response->response_code));
state->parser_state = HTTP_READING_DONE;
break;
- case -1:
+ case BODY_ERROR:
DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
TALLOC_FREE(line);
return HTTP_DATA_CORRUPTED;
@@ -162,6 +197,141 @@ error:
return status;
}
+static bool http_response_process_chunks(struct http_read_response_state *state)
+{
+ struct http_chunk *chunk = NULL;
+ struct http_request *resp = state->response;
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ DBG_DEBUG("processing chunk of size %zi\n",
+ chunk->blob.length);
+ if (resp->body.data == NULL) {
+ resp->body = chunk->blob;
+ chunk->blob = data_blob_null;
+ talloc_steal(resp, resp->body.data);
+ continue;
+ }
+
+ resp->body.data =
+ talloc_realloc(resp,
+ resp->body.data,
+ uint8_t,
+ resp->body.length + chunk->blob.length);
+ if (!resp->body.data) {
+ return false;
+ }
+ memcpy(resp->body.data + resp->body.length,
+ chunk->blob.data,
+ chunk->blob.length);
+
+ resp->body.length += chunk->blob.length;
+
+ TALLOC_FREE(chunk->blob.data);
+ chunk->blob = data_blob_null;
+ }
+ return true;
+}
+
+static enum http_read_status http_read_chunk_term(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ if (strncmp(line, "\r\n", 2) == 0) {
+ /* chunk terminator */
+ if (state->parser_state == HTTP_READING_FINAL_CHUNK_TERM) {
+ if (http_response_process_chunks(state) == false) {
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ state->parser_state = HTTP_READING_DONE;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ }
+ status = HTTP_ALL_DATA_READ;
+ goto out;
+ }
+
+ status = HTTP_DATA_CORRUPTED;
+out:
+ TALLOC_FREE(line);
+ return status;
+}
+
+static enum http_read_status http_read_chunk_size(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+ char *value = NULL;
+ int n = 0;
+ unsigned long long v;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ n = sscanf(line, "%m[^\r\n]\r\n", &value);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+
+ DBG_DEBUG("Got chunk size string %s\n", value);
+ n = sscanf(value, "%llx", &v);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ DBG_DEBUG("Got chunk size %llu 0x%llx\n", v, v);
+ if (v == 0) {
+ state->parser_state = HTTP_READING_FINAL_CHUNK_TERM;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK;
+ }
+ state->response->remaining_content_length = v;
+ status = HTTP_ALL_DATA_READ;
+out:
+ if (value) {
+ free(value);
+ }
+ TALLOC_FREE(line);
+ return status;
+}
+
/**
* Parses the first line of a HTTP response
*/
@@ -301,6 +471,55 @@ static enum http_read_status http_read_body(struct http_read_response_state *sta
return HTTP_ALL_DATA_READ;
}
+static enum http_read_status http_read_chunk(struct http_read_response_state *state)
+{
+ struct http_request *resp = state->response;
+ struct http_chunk *chunk = NULL;
+ size_t total = 0;
+ size_t prev = 0;
+
+ if (state->buffer.length < resp->remaining_content_length) {
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ total += chunk->blob.length;
+ }
+
+ prev = total;
+ total = total + state->buffer.length;
+ if (total < prev) {
+ DBG_ERR("adding chunklen %zu to buf len %zu "
+ "will overflow\n",
+ state->buffer.length,
+ prev);
+ return HTTP_DATA_CORRUPTED;
+ }
+ if (total > state->max_content_length) {
+ DBG_DEBUG("size %zu exceeds "
+ "max content len %"PRIu64" skipping body\n",
+ total,
+ state->max_content_length);
+ state->parser_state = HTTP_READING_DONE;
+ goto out;
+ }
+
+ /* chunk read */
+ chunk = talloc_zero(state, struct http_chunk);
+ if (chunk == NULL) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ chunk->blob = state->buffer;
+ talloc_steal(chunk, chunk->blob.data);
+ DLIST_ADD_END(state->chunks, chunk);
+ state->parser_state = HTTP_READING_CHUNK_TERM;
+out:
+ state->buffer = data_blob_null;
+ resp->remaining_content_length = 0;
+ return HTTP_ALL_DATA_READ;
+}
+
static enum http_read_status http_read_trailer(struct http_read_response_state *state)
{
enum http_read_status status = HTTP_DATA_CORRUPTED;
@@ -323,6 +542,16 @@ static enum http_read_status http_parse_buffer(struct http_read_response_state *
case HTTP_READING_BODY:
return http_read_body(state);
break;
+ case HTTP_READING_FINAL_CHUNK_TERM:
+ case HTTP_READING_CHUNK_TERM:
+ return http_read_chunk_term(state);
+ break;
+ case HTTP_READING_CHUNK_SIZE:
+ return http_read_chunk_size(state);
+ break;
+ case HTTP_READING_CHUNK:
+ return http_read_chunk(state);
+ break;
case HTTP_READING_TRAILER:
return http_read_trailer(state);
break;
@@ -527,20 +756,60 @@ static int http_read_response_next_vector(struct tstream_context *stream,
*_count = 1;
}
break;
- case HTTP_MORE_DATA_EXPECTED:
- /* TODO Optimize, allocating byte by byte */
- state->buffer.data = talloc_realloc(state, state->buffer.data,
- uint8_t, state->buffer.length + 1);
+ case HTTP_MORE_DATA_EXPECTED: {
+ size_t toread = 1;
+ size_t total;
+ if (state->parser_state == HTTP_READING_BODY ||
+ state->parser_state == HTTP_READING_CHUNK) {
+ struct http_request *resp = state->response;
+ toread = resp->remaining_content_length -
+ state->buffer.length;
+ }
+
+ total = toread + state->buffer.length;
+
+ if (total < state->buffer.length) {
+ DBG_ERR("adding %zu to buf len %zu "
+ "will overflow\n",
+ toread,
+ state->buffer.length);
+ return -1;
+ }
+
+ /*
+ * test if content-length message exceeds the
+ * specified max_content_length
+ * Note: This check won't be hit at the moment
+ * due to an existing check in parse_headers
+ * which will skip the body. Check is here
+ * for completeness and to cater for future
+ * code changes.
+ */
+ if (state->parser_state == HTTP_READING_BODY) {
+ if (total > state->max_content_length) {
+ DBG_ERR("content size %zu exceeds "
+ "max content len %"PRIu64"\n",
+ total,
+ state->max_content_length);
+ return -1;
+ }
+ }
+
+ state->buffer.data =
+ talloc_realloc(state, state->buffer.data,
+ uint8_t,
+ state->buffer.length + toread);
if (!state->buffer.data) {
return -1;
}
- state->buffer.length++;
+ state->buffer.length += toread;
vector[0].iov_base = (void *)(state->buffer.data +
- state->buffer.length - 1);
- vector[0].iov_len = 1;
+ state->buffer.length - toread);
+ vector[0].iov_len = toread;
*_vector = vector;
*_count = 1;
break;
+ }
case HTTP_DATA_CORRUPTED:
case HTTP_REQUEST_CANCELED:
case HTTP_DATA_TOO_LONG:
@@ -603,7 +872,7 @@ static void http_read_response_done(struct tevent_req *subreq)
{
NTSTATUS status;
struct tevent_req *req;
- int ret;
+ enum http_body_type ret;
int sys_errno;
if (!subreq) {
diff --git a/libcli/http/http_internal.h b/libcli/http/http_internal.h
index ec17f7e..786ace6 100644
--- a/libcli/http/http_internal.h
+++ b/libcli/http/http_internal.h
@@ -28,6 +28,10 @@ enum http_parser_state {
HTTP_READING_BODY,
HTTP_READING_TRAILER,
HTTP_READING_DONE,
+ HTTP_READING_CHUNK_SIZE,
+ HTTP_READING_CHUNK,
+ HTTP_READING_CHUNK_TERM,
+ HTTP_READING_FINAL_CHUNK_TERM,
};
enum http_read_status {
diff --git a/nsswitch/tests/test_idmap_ad.sh b/nsswitch/tests/test_idmap_ad.sh
index 7ae112a..1d4bd39 100755
--- a/nsswitch/tests/test_idmap_ad.sh
+++ b/nsswitch/tests/test_idmap_ad.sh
@@ -94,6 +94,14 @@ gidNumber: 2000001
unixHomeDirectory: /home/forbidden
loginShell: /bin/tcsh
gecos: User in forbidden OU
+
+dn: CN=no_posix_id,CN=Users,$BASE_DN
+changetype: add
+objectClass: user
+samaccountName: no_posix_id
+unixHomeDirectory: /home/no_posix_id
+loginShell: /bin/sh
+gecos: User without uidNumber and gidNumber
EOF
#
@@ -172,6 +180,17 @@ then
fi
#
+# Test 6: Make sure that with the default "all_groups=no"
+# the group "domain users" will not show user "no_posix_id"
+# but will show "SAMBA2008R2/administrator"
+#
+
+dom_users="$DOMAIN/domain users" # Extra step to make sure that all is one word
+out="$($wbinfo --group-info "$dom_users")"
+testit_grep_count "no_posix_id1" "no_posix_id" 0 echo "$out" || failed=$(expr $failed + 1)
+testit_grep "no_posix_id2" "SAMBA2008R2/administrator" echo "$out" || failed=$(expr $failed + 1)
+
+#
# Trusted domain test 1: Test uid of Administrator, should be 2500000
#
@@ -241,6 +260,9 @@ gidNumber: 2000002
dn: cn=forbidden,ou=sub,$BASE_DN
changetype: delete
+dn: CN=no_posix_id,CN=Users,$BASE_DN
+changetype: delete
+
dn: ou=sub,$BASE_DN
changetype: delete
EOF
diff --git a/packaging/systemd/samba-bgqd.service.in b/packaging/systemd/samba-bgqd.service.in
new file mode 100644
index 0000000..0254ebd
--- /dev/null
+++ b/packaging/systemd/samba-bgqd.service.in
@@ -0,0 +1,16 @@
+[Unit]
+Description=Samba Background Queue Daemon for printing-related jobs
+Documentation=man:samba-bgqd(8) man:smb.conf(5)
+Wants=network-online.target
+After=network.target network-online.target
+
+[Service]
+Type=notify
+LimitNOFILE=16384
+PIDFile=@PIDDIR@/samba-bgqd.pid
+EnvironmentFile=-@SYSCONFDIR@/sysconfig/samba
+ExecStart=@LIBEXECDIR@/samba/samba-bgqd --foreground --no-process-group $SAMBAOPTIONS
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/wscript_build b/packaging/wscript_build
index 217bd99..dc95beb 100644
--- a/packaging/wscript_build
+++ b/packaging/wscript_build
@@ -4,7 +4,8 @@ systemd_services = [
'systemd/smb.service',
'systemd/nmb.service',
'systemd/winbind.service',
- 'systemd/samba.service'
+ 'systemd/samba.service',
+ 'systemd/samba-bgqd.service',
]
for srv in systemd_services:
diff --git a/python/samba/tests/blackbox/http_chunk.py b/python/samba/tests/blackbox/http_chunk.py
new file mode 100644
index 0000000..6745c8c
--- /dev/null
+++ b/python/samba/tests/blackbox/http_chunk.py
@@ -0,0 +1,129 @@
+# Blackbox tests for http_test
+#
+# Copyright (C) Noel Power noel.power@suse.com
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import time
+import threading
+import logging
+import json
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from samba.logger import get_samba_logger
+from samba.tests import BlackboxTestCase, BlackboxProcessError
+
+logger = get_samba_logger(name=__name__)
+COMMAND = "bin/http_test"
+def make_chunks(msg, chunk_size):
+ chunks = []
+ while len(msg) > chunk_size:
+ chunk = msg[:chunk_size]
+ chunks.append(chunk)
+ msg = msg[chunk_size:]
+ if len(msg):
+ chunks.append(msg)
+ return chunks
+
+# simple handler, spits back the 'path' passed in
+# GET or POST and a chunked encoded http response
+# where the chunk size is 10 octets
+class ChunkHTTPRequestHandler(BaseHTTPRequestHandler):
+ def handle_req(self):
+ msg = bytes(self.path, encoding="utf-8")
+ chunks = make_chunks(msg, 10)
+
+ self.send_response(200)
+ self.send_header('content-type', 'application/json; charset=UTF-8')
+ if self.path == "usegziptransferencoding":
+ self.send_header('Transfer-Encoding', 'gzip')
+ else:
+ self.send_header('Transfer-Encoding', 'chunked')
+ self.end_headers()
+ resp = bytes()
+ for chunk in chunks:
+ resp = resp + ("%x" % len(chunk)).encode("utf-8") + b'\r\n' + chunk + b'\r\n'
+ resp += b'0\r\n\r\n'
+ self.wfile.write(resp)
+
+ def do_POST(self):
+ self.handle_req()
+ def do_GET(self):
+ self.handle_req()
+
+class HttpChunkBlackboxTests(BlackboxTestCase):
+ def setUp(self):
+ self.server = HTTPServer((os.getenv("SERVER_IP", "localhost"), 8080),
+ ChunkHTTPRequestHandler,
+ bind_and_activate=False)
+ self.t = threading.Thread(target=HttpChunkBlackboxTests.http_server, args=(self,))
+ self.t.setDaemon(True)
+ self.t.start()
+ time.sleep(1)
+
+ def tearDown(self):
+ super().tearDown()
+
+ def http_server(self):
+ self.server.server_bind()
+ self.server.server_activate()
+ self.server.serve_forever()
+
+ def test_single_chunk(self):
+ try:
+ msg = "one_chunk"
+ resp = self.check_output("%s -U%% -I%s --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg,resp.decode('utf-8'))
+ except BlackboxProcessError as e:
+ print("Failed with: %s" % e)
+ self.fail(str(e))
+
+ def test_multi_chunks(self):
+ try:
+ msg = "snglechunksnglechunksnglechunksnglechunksnglechunk"
+ resp = self.check_output("%s -U%% -I%s --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg, resp.decode('utf-8'))
+ except BlackboxProcessError as e:
+ print("Failed with: %s" % e)
+ self.fail(str(e))
+
+ def test_exceed_request_size(self):
+ try:
+ msg = "snglechunksnglechunksnglechunksnglechunksnglechunk"
+ resp = self.check_output("%s -d11 -U%% -I%s --rsize 49 --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.fail("unexpected success")
+ except BlackboxProcessError as e:
+ if "http_read_chunk: size 50 exceeds max content len 49 skipping body" not in e.stderr.decode('utf-8'):
+ self.fail(str(e))
+ if "unexpected 0 len response" not in e.stdout.decode('utf-8'):
+ self.fail(str(e))
+
+ def test_exact_request_size(self):
+ try:
+ msg = "snglechunksnglechunksnglechunksnglechunksnglechunk"
+ resp = self.check_output("%s -U%% -I%s --rsize 50 --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg, resp.decode('utf-8'))
+ except BlackboxProcessError as e:
+ print("Failed with: %s" % e)
+ self.fail(str(e))
+
+ def test_gzip_transfer_encoding(self):
+ try:
+ msg = "usegziptransferencoding"
+ resp = self.check_output("%s -U%% -I%s --rsize 50 --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg, resp.decode('utf-8'))
+ self.fail("unexpected success")
+ except BlackboxProcessError as e:
+ if "http_response_needs_body: Unsupported transfer encoding type gzip" not in e.stderr.decode('utf-8'):
+ self.fail(str(e))
diff --git a/python/samba/tests/blackbox/http_content.py b/python/samba/tests/blackbox/http_content.py
new file mode 100644
index 0000000..3d674aa
--- /dev/null
+++ b/python/samba/tests/blackbox/http_content.py
@@ -0,0 +1,95 @@
+# Blackbox tests for http_test
+#
+# Copyright (C) Noel Power noel.power@suse.com
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import time
+import threading
+import logging
+import json
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from samba.logger import get_samba_logger
+from samba.tests import BlackboxTestCase, BlackboxProcessError
+
+logger = get_samba_logger(name=__name__)
+COMMAND = "bin/http_test"
+
+# simple handler, spits back the 'path' passed in
+# GET or POST and a chunked encoded http response
+# where the chunk size is 10 octets
+class ContentHTTPRequestHandler(BaseHTTPRequestHandler):
+ def handle_req(self):
+ msg = bytes(self.path, encoding="utf-8")
+
+ self.send_response(200)
+ self.send_header('content-type', 'application/json; charset=UTF-8')
+ self.send_header('content-length', len(msg))
+ self.end_headers()
+ self.wfile.write(msg)
+
+ def do_POST(self):
+ self.handle_req()
+ def do_GET(self):
+ self.handle_req()
+
+class HttpContentBlackboxTests(BlackboxTestCase):
+ def setUp(self):
+ self.server = HTTPServer((os.getenv("SERVER_IP", "localhost"), 8080),
+ ContentHTTPRequestHandler,
+ bind_and_activate=False)
+ self.t = threading.Thread(target=HttpContentBlackboxTests.http_server, args=(self,))
+ self.t.setDaemon(True)
+ self.t.start()
+ time.sleep(1)
+
+ def tearDown(self):
+ super().tearDown()
+
+ def http_server(self):
+ self.server.server_bind()
+ self.server.server_activate()
+ self.server.serve_forever()
+
+ def notest_simple_msg(self):
+ try:
+ msg = "simplemessage"
+ resp = self.check_output("%s -U%% -I%s --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg, resp.decode('utf-8'))
+ except BlackboxProcessError as e:
+ print("Failed with: %s" % e)
+ self.fail(str(e))
+
+ def test_exceed_request_size(self):
+ try:
+ msg = "012345678" # 9 bytes
+ # limit response to 8 bytes
+ resp = self.check_output("%s -d11 -U%% -I%s --rsize 8 --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.fail("unexpected success")
+ except BlackboxProcessError as e:
+ if "unexpected 0 len response" not in e.stdout.decode('utf-8'):
+ self.fail(str(e))
+ if "http_parse_headers: Skipping body for code 200" not in e.stderr.decode('utf-8'):
+ self.fail(str(e))
+
+ def test_exact_request_size(self):
+ try:
+ msg = "012345678" # 9 bytes
+ # limit response to 9 bytes
+ resp = self.check_output("%s -U%% -I%s --rsize 9 --uri %s" % (COMMAND, os.getenv("SERVER_IP", "localhost"), msg))
+ self.assertEqual(msg, resp.decode('utf-8'))
+ except BlackboxProcessError as e:
+ print("Failed with: %s" % e)
+ self.fail(str(e))
diff --git a/python/samba/tests/blackbox/smbcacls_propagate_inhertance.py b/python/samba/tests/blackbox/smbcacls_propagate_inhertance.py
index cc13727..5b3a271 100644
--- a/python/samba/tests/blackbox/smbcacls_propagate_inhertance.py
+++ b/python/samba/tests/blackbox/smbcacls_propagate_inhertance.py
@@ -1288,3 +1288,111 @@ class InheritanceSmbCaclsTests(SmbCaclsBlockboxTestBase):
except BlackboxProcessError as e:
self.fail(str(e))
+
+ def test_simple_iocioi_add(self):
+ """test smbcacls '--propagate-inheritance --add' which attempts to add the ACL
+ for the file and additionally use inheritance rules to propagate appropriate
+ changes to children
+
+ This test adds an ACL with (IO)(CI)(OI)(READ)
+
+ before:
+
+ +-tar_test_dir/ (OI)(CI)(I)(F)
+ +-oi_dir/ (OI)(CI)(I)(F)
+ | +-file.1 (I)(F)
+ | +-nested/ (OI)(CI)(I)(F)
+ | +-file.2 (I)(F)
+ | +-nested_again/ (OI)(CI)(I)(F)
+ | +-file.3 (I)(F)
+
+ after/expected:
+
+ +-tar_test_dir/ (OI)(CI)(I)(F)
+ +-oi_dir/ (OI)(CI)(I)(F), (IO)(CI)(OI)(READ)
+ | +-file.1 (I)(F), (I)(READ)
+ | +-nested/ (OI)(CI)(I)(F), (I)(CI)(OI)(READ)
+ | +-file.2 (I)(F), (I)(READ)
+ | +-nested_again/ (OI)(CI)(I)(F), (I)(CI)(OI)(READ)
+ | +-file.3 (I)(F), (I)(READ)"""
+
+ dir_add_acl_str = "ACL:%s:ALLOWED/OI|CI|IO/READ" % self.user
+ obj_inherited_ace_str = "ACL:%s:ALLOWED/I/READ" % self.user
+ dir_inherited_ace_str = "ACL:%s:ALLOWED/OI|CI|I/READ" % self.user
+
+ try:
+
+ self.smb_cacls(["--propagate-inheritance", "--add",
+ dir_add_acl_str, self.oi_dir])
+
+ # check top level container 'oi_dir' has IO|CI|OI/READ
+ dir_ace = self.ace_parse_str(dir_add_acl_str)
+ self.assertTrue(self.file_ace_check(self.oi_dir, dir_ace))
+
+ # file 'oi_dir/file-1' should have inherited I/READ
+ child_file_ace = self.ace_parse_str(obj_inherited_ace_str)
+ self.assertTrue(self.file_ace_check(self.f1, child_file_ace))
+
+ # nested dir 'oi_dir/nested/' should have I|CI|OI/READ
+ child_dir_ace = self.ace_parse_str(dir_inherited_ace_str)
+ self.assertTrue(self.file_ace_check(self.nested_dir, child_dir_ace))
+
+ # nested file 'oi_dir/nested/file-2' should have inherited I/READ
+ self.assertTrue(self.file_ace_check(self.f2, child_file_ace))
+
+ # nested_again dir 'oi_dir/nested/nested_again' should have I|CI|OI/READ
+ child_dir_ace = self.ace_parse_str(dir_inherited_ace_str)
+ self.assertTrue(self.file_ace_check(self.nested_again_dir, child_dir_ace))
+ # nested_again file 'oi_dir/nested/nested_again/file-3' should have inherited I/READ
+ self.assertTrue(self.file_ace_check(self.f3, child_file_ace))
+ except BlackboxProcessError as e:
+ self.fail(str(e))
+
+ def test_simple_ioci_add(self):
+ """test smbcacls '--propagate-inheritance --add' which attempts to add the ACL
+ for the file and additionally use inheritance rules to propagate appropriate
+ changes to children
+
+ This test adds an ACL with (IO)(CI)(READ)
+
+ before:
+
+ +-tar_test_dir/ (OI)(CI)(I)(F)
+ +-oi_dir/ (OI)(CI)(I)(F)
+ | +-file.1 (I)(F)
+ | +-nested/ (OI)(CI)(I)(F)
+ | +-file.2 (I)(F)
+ | +-nested_again/ (OI)(CI)(I)(F)
+ | +-file.3 (I)(F)
+
+ after/expected:
+
+ +-tar_test_dir/ (OI)(CI)(I)(F)
+ +-oi_dir/ (OI)(CI)(I)(F), (IO)(CI)(READ)
+ | +-file.1 (I)(F)
+ | +-nested/ (OI)(CI)(I)(F), (I)(CI)(READ)
+ | +-file.2 (I)(F)
+ | +-nested_again/ (OI)(CI)(I)(F), (I)(CI)(READ)
+ | +-file.3 (I)(F)"""
+
+ dir_add_acl_str = "ACL:%s:ALLOWED/CI|IO/READ" % self.user
+ dir_inherited_ace_str = "ACL:%s:ALLOWED/CI|I/READ" % self.user
+
+ try:
+
+ self.smb_cacls(["--propagate-inheritance", "--add",
+ dir_add_acl_str, self.oi_dir])
+
+ # check top level container 'oi_dir' has IO|CI/READ
+ dir_ace = self.ace_parse_str(dir_add_acl_str)
+ self.assertTrue(self.file_ace_check(self.oi_dir, dir_ace))
+
+ # nested dir 'oi_dir/nested/' should have I|CI/READ
+ child_dir_ace = self.ace_parse_str(dir_inherited_ace_str)
+ self.assertTrue(self.file_ace_check(self.nested_dir, child_dir_ace))
+
+ # nested_again dir 'oi_dir/nested/nested_again' should have I|CI/READ
+ child_dir_ace = self.ace_parse_str(dir_inherited_ace_str)
+ self.assertTrue(self.file_ace_check(self.nested_again_dir, child_dir_ace))
+ except BlackboxProcessError as e:
+ self.fail(str(e))
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index bbce55e..cf40633 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1420,6 +1420,7 @@ sub setup_ad_member_idmap_ad
idmap config $dcvars->{TRUST_DOMAIN} : range = 2000000-2999999
gensec_gssapi:requested_life_time = 5
winbind scan trusted domains = yes
+ winbind expand groups = 1
";
my $ret = $self->provision(
diff --git a/selftest/tests.py b/selftest/tests.py
index 10d5536..0d5db68 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -221,6 +221,8 @@ plantestsuite(
"samba4.blackbox.test_special_group", "none",
cmdline('test_special_group.sh', '$PREFIX_ABS/provision'))
+planpythontestsuite("fileserver", "samba.tests.blackbox.http_content")
+planpythontestsuite("fileserver", "samba.tests.blackbox.http_chunk")
planpythontestsuite("none", "samba.tests.upgradeprovision")
planpythontestsuite("none", "samba.tests.xattr")
planpythontestsuite("none", "samba.tests.ntacls")
diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
index ff11ba4..e0591ac 100644
--- a/source3/utils/smbcacls.c
+++ b/source3/utils/smbcacls.c
@@ -914,6 +914,10 @@ static uint8_t get_flags_to_propagate(bool is_container,
/* Assume we are not propagating the ACE */
newflags &= ~SEC_ACE_FLAG_INHERITED_ACE;
+
+ /* Inherit-only flag is not propagated to children */
+
+ newflags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
/* all children need to have the SEC_ACE_FLAG_INHERITED_ACE set */
if (acl_cntrinherit || acl_objinherit) {
/*
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index 7e572e5..7d63240 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -1039,7 +1039,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
}
static NTSTATUS add_primary_group_members(
- ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
+ ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
char ***all_members, size_t *num_all_members)
{
char *filter;
@@ -1051,10 +1051,13 @@ static NTSTATUS add_primary_group_members(
char **members;
size_t num_members;
ads_control args;
+ bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
filter = talloc_asprintf(
- mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
- (unsigned)rid);
+ mem_ctx,
+ "(&(objectCategory=user)(primaryGroupID=%u)%s)",
+ (unsigned)rid,
+ all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
if (filter == NULL) {
goto done;
}
@@ -1206,7 +1209,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
- status = add_primary_group_members(ads, mem_ctx, rid,
+ status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
&members, &num_members);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
diff --git a/source4/client/http_test.c b/source4/client/http_test.c
new file mode 100644
index 0000000..ca542ba
--- /dev/null
+++ b/source4/client/http_test.c
@@ -0,0 +1,401 @@
+#include "includes.h"
+#include "version.h"
+#include "libcli/libcli.h"
+#include "lib/events/events.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/http/http.h"
+#include "credentials.h"
+#include "util/tevent_ntstatus.h"
+#include "lib/tls/tls.h"
+#include "lib/cmdline/cmdline.h"
+
+
+struct http_client_info {
+ struct http_conn *http_conn;
+ uint16_t server_port;
+ const char *server_addr;
+ struct tstream_tls_params *tls_params;
+ struct cli_credentials *creds;
+ struct loadparm_context *lp_ctx;
+ const char *uri;
+};
+
+static bool send_http_request(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev_ctx,
+ struct http_client_info* es,
+ size_t response_size,
+ NTSTATUS *pstatus)
+{
+ struct http_request *http_req = NULL;
+ struct tevent_req *req = NULL;
+ char *uri = NULL;
+ struct http_request *http_response = NULL;
+ NTSTATUS status;
+
+ http_req = talloc_zero(mem_ctx, struct http_request);
+ if (!http_req) {
+ DBG_ERR("no memory\n");
+ return false;
+ }
+
+ uri = talloc_strdup(mem_ctx, es->uri);
+
+ http_req->type = HTTP_REQ_POST;
+ http_req->uri = uri;
+ http_req->body = data_blob_null;
+ http_req->major = '1';
+ http_req->minor = '1';
+
+ http_add_header(mem_ctx, &http_req->headers,
+ "User-Agent", "Samba/http_test");
+ http_add_header(mem_ctx, &http_req->headers,
+ "Accept", "*/*");
+
+ req = http_send_auth_request_send(mem_ctx,
+ ev_ctx,
+ es->http_conn,
+ http_req,
+ es->creds,
+ es->lp_ctx,
+ HTTP_AUTH_BASIC);
+ if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
+ DBG_ERR("Failed to set timeout\n");
+ return false;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
+ DBG_ERR("Failed to connect: %s\n", nt_errstr(*pstatus));
+ return false;
+ }
+
+ status = http_send_auth_request_recv(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Auth request failed: %s\n", nt_errstr(status));
+ return false;
+ }
+
+ req = http_read_response_send(mem_ctx,
+ ev_ctx,
+ es->http_conn,
+ response_size);
+ if (!req) {
+ DBG_ERR("no memory\n");
+ return -1;
+ }
+
+ if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
+ DBG_ERR("Failed to set timeout\n");
+ return false;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
+ DBG_ERR("Failed to read_resonse: %s\n", nt_errstr(*pstatus));
+ return false;
+ }
+
+ *pstatus = http_read_response_recv(req, mem_ctx, &http_response);
+
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ DBG_ERR("Failed to receive response: %s\n", nt_errstr(*pstatus));
+ return false;
+ }
+ /* following are not 'hard' errors */
+ if (http_response->response_code != 200) {
+ fprintf(stdout, "HTTP server response: %u\n",
+ http_response->response_code);
+ fflush(stdout);
+ return false;
+
+ }
+ if (http_response->body.length == 0) {
+ fprintf(stdout, "unexpected 0 len response\n");
+ fflush(stdout);
+ return false;
+ }
+ DBG_ERR("response: len (%d)\n%s\n",
+ (int)http_response->body.length,
+ talloc_strndup(mem_ctx,
+ (char *)http_response->body.data,
+ http_response->body.length));
+ fprintf(stdout,"%s", talloc_strndup(mem_ctx,
+ (char *)http_response->body.data,
+ http_response->body.length));
+ fflush(stdout);
+ return true;
+}
+
+int main(int argc, const char *argv[])
+
+{
+ TALLOC_CTX *mem_ctx;
+ struct tevent_context *ev_ctx;
+ int retries = 4;
+ int count = 0;
+ struct http_client_info *http_info = NULL;
+ bool use_tls = false;
+ int res;
+ NTSTATUS status;
+ struct tevent_req *req = NULL;
+ bool connected = false;
+ poptContext pc;
+ const char **const_argv = discard_const_p(const char *, argv);
+ int opt;
+ bool ok;
+ const char *ca_file = NULL;
+ int port = 0;
+ size_t response_size = 8192000;
+ struct cli_credentials *cli_creds;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+
+ {
+ .longName = "usetls",
+ .shortName = 't',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 't',
+ .descrip = "Use tls",
+ .argDescrip = "enable tls",
+ },
+ {
+ .longName = "ip-address",
+ .shortName = 'I',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'I',
+ .descrip = "Use this IP to connect to",
+ .argDescrip = "IP",
+ },
+ {
+ .longName = "port",
+ .shortName = 'p',
+ .argInfo = POPT_ARG_INT,
+ .arg = &port,
+ .val = 'p',
+ .descrip = "port to connect to",
+ .argDescrip = "port",
+ },
+ {
+ .longName = "cacart",
+ .shortName = 'c',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'c',
+ .descrip = "CA certificate to verify peer against",
+ .argDescrip = "ca cert",
+ },
+ {
+ .longName = "uri",
+ .shortName = 'u',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'u',
+ .descrip = "uri to send as part of http request",
+ .argDescrip = "uri",
+ },
+ {
+ .longName = "rsize",
+ .argInfo = POPT_ARG_LONG,
+ .arg = &response_size,
+ .descrip = "response size",
+ },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ POPT_TABLEEND
+ };
+
+ mem_ctx = talloc_init("http_test");
+
+ if (!mem_ctx) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+
+ http_info = talloc_zero(mem_ctx, struct http_client_info);
+
+ if (http_info == NULL) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ res = -1;
+ goto done;
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ const_argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ res = -1;
+ goto done;
+ }
+
+ /* some defaults */
+
+ http_info->server_addr = "localhost";
+ http_info->uri = "/_search?pretty";
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 't':
+ use_tls = true;
+ break;
+ case 'c': {
+ ca_file = talloc_strdup(mem_ctx,
+ poptGetOptArg(pc));
+ if (ca_file == NULL) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+ break;
+ }
+ case 'I': {
+ http_info->server_addr = talloc_strdup(mem_ctx,
+ poptGetOptArg(pc));
+ if (http_info->server_addr == NULL) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+ break;
+ }
+ case 'u': {
+ http_info->uri = talloc_strdup(mem_ctx,
+ poptGetOptArg(pc));
+ if (http_info->uri == NULL) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+ }
+
+ if (use_tls && ca_file == NULL) {
+ DBG_ERR("No cacert\n");
+ res = -1;
+ poptPrintUsage(pc, stderr, 0);
+ goto done;
+ }
+
+ if (!port) {
+ port = 8080;
+ }
+ http_info->server_port = port;
+
+ ev_ctx = s4_event_context_init(mem_ctx);
+ if (!ev_ctx) {
+ DBG_ERR("Not enough memory\n");
+ res = -1;
+ goto done;
+ }
+
+
+ cli_creds = samba_cmdline_get_creds();
+ if (!cli_credentials_is_anonymous(cli_creds)) {
+ http_info->creds = cli_credentials_init(mem_ctx);
+ cli_credentials_set_username(
+ http_info->creds,
+ cli_credentials_get_username(cli_creds),
+ CRED_SPECIFIED);
+ cli_credentials_set_password(http_info->creds,
+ cli_credentials_get_password(cli_creds),
+ CRED_SPECIFIED);
+ } else {
+ DBG_DEBUG("Anonymous creds!!!\n");
+ http_info->creds = cli_creds;
+ }
+ if (http_info->creds == NULL) {
+ DBG_ERR("Failed to create creds\n");
+ res = -1;
+ goto done;
+ }
+ http_info->lp_ctx = samba_cmdline_get_lp_ctx();
+
+ DBG_ERR("retries = %d/%d, Using server %s, port %d, using tls %s\n",
+ count, retries,
+ http_info->server_addr,
+ http_info->server_port,
+ use_tls ? "true" : "false");
+
+ while (count < retries) {
+ int error;
+ DBG_ERR("Connecting to HTTP [%s] port [%"PRIu16"]%s\n",
+ http_info->server_addr, http_info->server_port,
+ use_tls ? " with tls" : " without tls");
+ if (use_tls) {
+ const char *crl_file = NULL;
+ const char *tls_priority = "NORMAL:-VERS-SSL3.0";
+ enum tls_verify_peer_state verify_peer =
+ TLS_VERIFY_PEER_CA_ONLY;
+
+ status = tstream_tls_params_client(mem_ctx,
+ ca_file,
+ crl_file,
+ tls_priority,
+ verify_peer,
+ http_info->server_addr,
+ &http_info->tls_params);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed tstream_tls_params_client - %s\n",
+ nt_errstr(status));
+ res = -1;
+ goto done;
+ }
+ }
+
+ req = http_connect_send(mem_ctx,
+ ev_ctx,
+ http_info->server_addr,
+ http_info->server_port,
+ http_info->creds,
+ http_info->tls_params);
+ if (!tevent_req_poll_ntstatus(req, ev_ctx, &status)) {
+ res = -1;
+ goto done;
+ }
+
+ error = http_connect_recv(req,
+ mem_ctx,
+ &http_info->http_conn);
+ if (error != 0) {
+ count++;
+ DBG_ERR("HTTP connection failed retry %d/%d: %s\n", count, retries, strerror(error));
+ } else {
+ DBG_ERR("HTTP connection succeeded\n");
+ connected = true;
+ break;
+ }
+ }
+
+ if (!connected) {
+ DBG_ERR("Leaving early\n");
+ res = -1;
+ goto done;
+ }
+
+ if (!send_http_request(mem_ctx, ev_ctx, http_info, response_size, &status)) {
+ DBG_ERR("Failure\n");
+ res = -1;
+ goto done;
+ }
+ res = 0;
+done:
+ TALLOC_FREE(mem_ctx);
+ return res;
+}
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index fbe39d9..aba7f41 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -1034,10 +1034,11 @@ WERROR dns_common_replace(struct ldb_context *samdb,
* record.
*/
if (records[i].data.EntombedTime != 0) {
- if (rec_count != 1) {
- DBG_ERR("tombstone record has %u neighbour "
- "records.\n",
- rec_count - 1);
+ if (rec_count != 1 && DEBUGLVL(DBGLVL_NOTICE)) {
+ DBG_NOTICE("tombstone record [%u] has "
+ "%u neighbour records.\n",
+ i, rec_count - 1);
+ NDR_PRINT_DEBUG(dnsp_DnssrvRpcRecord, &records[i]);
}
was_tombstoned = true;
}
diff --git a/source4/wscript_build b/source4/wscript_build
index d204441..db2ad3e 100644
--- a/source4/wscript_build
+++ b/source4/wscript_build
@@ -6,6 +6,11 @@ bld.SAMBA_BINARY('client/smbclient' + bld.env.suffix4,
install=False
)
+bld.SAMBA_BINARY('client/http_test',
+ source='client/http_test.c',
+ deps='samba-hostconfig SMBREADLINE samba-util LIBCLI_SMB RPC_NDR_SRVSVC LIBCLI_LSA popt CMDLINE_S4',
+ for_selftest=True,
+ )
bld.SAMBA_BINARY('client/cifsdd',
source='client/cifsdd.c client/cifsddio.c',