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