The branch, v4-20-stable has been updated
       via  0ba948cba0b VERSION: Disable GIT_SNAPSHOT for the 4.20.1 release.
       via  d01b50ec4f3 WHATSNEW: Add release notes for Samba 4.20.1.
       via  db658c40f5d s3:utils: Fix Inherit-Only flag being automatically 
propagated to children
       via  d28a889aed2 python/samba/tests/blackbox: Add tests for Inherit-only 
flag propagation
       via  83da49f3489 tests: Add a test for "all_groups=no" to 
test_idmap_ad.sh
       via  84f82a09ffd selftest: Add "winbind expand groups = 1" to 
setup_ad_member_idmap_ad
       via  83701298384 s3:winbindd: Improve performance of lookup_groupmem() 
in idmap_ad
       via  8857cf29979 docs-xml: Add parameter all_groupmem to idmap_ad
       via  215bb9bd48e Do not fail checksums for RFC8009 types
       via  db60a1947b8 s4:dns_server: less noisy, more informative debug 
messages
       via  9155d89a2ae packaging: Provide a systemd service file for samba-bgqd
       via  077f39baf7c libcli/http: Detect unsupported Transfer-encoding type
       via  2fb1bf0205f selftest: Add new test for testing non-chunk transfer 
encoding
       via  30bf3d1430f selftest: fix potential reference before assigned error
       via  a70e3a36c82 libcli/http: Handle http chunked transfer encoding
       via  7e17e4809d5 tests: add test for chunked encoding with http cli 
library
       via  26206392153 libcli/http: Optimise reading for content-length
       via  71eac5a065f selftest: Add basic content-lenght http tests
       via  19250e13ab6 Add simple http_client for use in black box tests (in 
following commits)
       via  eaefe50327d VERSION: Bump version up to Samba 4.20.1...
      from  8fdd82c8b9c VERSION: Disable GIT_SNAPSHOT for the 4.20.0 release.

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-20-stable


- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 VERSION                                            |   2 +-
 WHATSNEW.txt                                       |  55 +++
 auth/kerberos/kerberos_pac.c                       |  47 ++-
 docs-xml/manpages/idmap_ad.8.xml                   |  10 +
 lib/krb5_wrap/krb5_samba.h                         |  28 ++
 libcli/http/http.c                                 | 309 +++++++++++++++-
 libcli/http/http_internal.h                        |   4 +
 nsswitch/tests/test_idmap_ad.sh                    |  22 ++
 .../{samba.service.in => samba-bgqd.service.in}    |   9 +-
 packaging/wscript_build                            |   3 +-
 python/samba/tests/blackbox/http_chunk.py          | 129 +++++++
 python/samba/tests/blackbox/http_content.py        |  95 +++++
 .../blackbox/smbcacls_propagate_inhertance.py      | 108 ++++++
 selftest/target/Samba3.pm                          |   1 +
 selftest/tests.py                                  |   2 +
 source3/utils/smbcacls.c                           |   4 +
 source3/winbindd/winbindd_ads.c                    |  11 +-
 source4/client/http_test.c                         | 401 +++++++++++++++++++++
 source4/dns_server/dnsserver_common.c              |   9 +-
 source4/wscript_build                              |   5 +
 20 files changed, 1200 insertions(+), 54 deletions(-)
 copy packaging/systemd/{samba.service.in => samba-bgqd.service.in} (50%)
 create mode 100644 python/samba/tests/blackbox/http_chunk.py
 create mode 100644 python/samba/tests/blackbox/http_content.py
 create mode 100644 source4/client/http_test.c


Changeset truncated at 500 lines:

diff --git a/VERSION b/VERSION
index 482360b7d68..cfa7539380b 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 5c97836d36f..8249e9326f9 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,3 +1,58 @@
+                   ==============================
+                   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.bagn...@catalyst.net.nz>
+   * BUG 15630: dns update debug message is too noisy.
+
+o  Alexander Bokovoy <a...@samba.org>
+   * BUG 15635: Do not fail PAC validation for RFC8009 checksums types.
+
+o  Pavel Filipenský <pfilipen...@samba.org>
+   * BUG 15605: Improve performance of lookup_groupmem() in idmap_ad.
+
+o  Anna Popova <popova.anna...@gmail.com>
+   * BUG 15636: Smbcacls incorrectly propagates inheritance with Inherit-Only
+     flag.
+
+o  Noel Power <noel.po...@suse.com>
+   * BUG 15611: http library doesn't support 'chunked transfer encoding'.
+
+o  Andreas Schneider <a...@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 ae4557bbd6f..b6272ac15eb 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 32df8d066c2..c7fcc65d763 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 e158a404dea..795106453c9 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -88,6 +88,34 @@
 #define CKSUMTYPE_HMAC_SHA1_96_AES_256 CKSUMTYPE_HMAC_SHA1_96_AES256
 #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 96c573af137..6f22214f706 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,


-- 
Samba Shared Repository

Reply via email to