195 lines
6.4 KiB
Diff
195 lines
6.4 KiB
Diff
# UNDF: UNDF-2026-000001031
|
|
# UNDF: UNDF-2026-XXXXXXXXX
|
|
--- a/source4/dsdb/samdb/samdb.c
|
|
+++ b/source4/dsdb/samdb/samdb.c
|
|
@@ -163,6 +163,35 @@ NTSTATUS samdb_set_global_schema(struct ldb_context *ldb)
|
|
return NULL;
|
|
}
|
|
|
|
+/*
|
|
+ * Binary insertion into a sorted struct dom_sid array.
|
|
+ *
|
|
+ * Returns count+1 if the SID was inserted (new, unique).
|
|
+ * Returns count unchanged if the SID was already present (duplicate).
|
|
+ *
|
|
+ * Used by security_token_create() to replace O(N) linear dedup scan with
|
|
+ * O(log N) bsearch + O(N) shift. Total token-build cost drops from O(N^2)
|
|
+ * to O(N log N).
|
|
+ */
|
|
+static uint32_t sid_sorted_insert_unique(struct dom_sid *scratch,
|
|
+ uint32_t count,
|
|
+ const struct dom_sid *sid)
|
|
+{
|
|
+ uint32_t lo = 0, hi = count;
|
|
+ while (lo < hi) {
|
|
+ uint32_t mid = lo + (hi - lo) / 2;
|
|
+ int cmp = dom_sid_compare(&scratch[mid], sid);
|
|
+ if (cmp == 0) return count; /* duplicate */
|
|
+ if (cmp < 0) lo = mid + 1;
|
|
+ else hi = mid;
|
|
+ }
|
|
+ /* lo is the sorted insertion point */
|
|
+ memmove(&scratch[lo + 1], &scratch[lo],
|
|
+ (count - lo) * sizeof(struct dom_sid));
|
|
+ scratch[lo] = *sid;
|
|
+ return count + 1;
|
|
+}
|
|
+
|
|
/****************************************************************************
|
|
Create the SID list for this user.
|
|
****************************************************************************/
|
|
@@ -187,6 +216,16 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
|
|
enum claims_evaluation_control evaluate_claims;
|
|
bool sids_are_valid = false;
|
|
bool device_sids_are_valid = false;
|
|
+ /*
|
|
+ * Sorted scratch arrays for O(N log N) dedup.
|
|
+ * The existing nested for-loop dedup is O(N^2): for each incoming SID
|
|
+ * it scans all already-accepted SIDs linearly. For a Kerberos PAC
|
|
+ * with ~500 group SIDs that is ~125,000 dom_sid_equal() calls at login.
|
|
+ * We replace it with binary-insertion-sort into a scratch array so each
|
|
+ * membership test costs O(log N) instead of O(N).
|
|
+ */
|
|
+ struct dom_sid *sorted_sids = NULL;
|
|
+ uint32_t sorted_count = 0;
|
|
+ struct dom_sid *sorted_device_sids = NULL;
|
|
+ uint32_t sorted_device_count = 0;
|
|
bool authentication_was_compounded = session_info_flags & AUTH_SESSION_INFO_FORCE_COMPOUNDED_AUTHENTICATION;
|
|
|
|
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
|
@@ -224,31 +263,42 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
|
|
|
|
ptoken->num_sids = 0;
|
|
|
|
+ sorted_sids = talloc_array(tmp_ctx, struct dom_sid,
|
|
+ num_sids > 0 ? num_sids : 1);
|
|
+ if (sorted_sids == NULL) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ return NT_STATUS_NO_MEMORY;
|
|
+ }
|
|
+
|
|
for (i = 0; i < num_sids; i++) {
|
|
- uint32_t check_sid_idx;
|
|
- for (check_sid_idx = 0;
|
|
- check_sid_idx < ptoken->num_sids;
|
|
- check_sid_idx++) {
|
|
- if (dom_sid_equal(&ptoken->sids[check_sid_idx], &sids[i].sid)) {
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (check_sid_idx == ptoken->num_sids) {
|
|
- const struct dom_sid *sid = &sids[i].sid;
|
|
-
|
|
- sids_are_valid = sids_are_valid || dom_sid_equal(
|
|
- sid, &global_sid_Claims_Valid);
|
|
- authentication_was_compounded = authentication_was_compounded || dom_sid_equal(
|
|
- sid, &global_sid_Compounded_Authentication);
|
|
-
|
|
- ptoken->sids = talloc_realloc(ptoken, ptoken->sids, struct dom_sid, ptoken->num_sids + 1);
|
|
- if (ptoken->sids == NULL) {
|
|
- talloc_free(ptoken);
|
|
- return NT_STATUS_NO_MEMORY;
|
|
- }
|
|
-
|
|
- ptoken->sids[ptoken->num_sids] = *sid;
|
|
- ptoken->num_sids++;
|
|
+ const struct dom_sid *sid = &sids[i].sid;
|
|
+ uint32_t new_count;
|
|
+
|
|
+ /* O(log sorted_count) membership test + O(sorted_count) shift */
|
|
+ new_count = sid_sorted_insert_unique(sorted_sids, sorted_count, sid);
|
|
+ if (new_count == sorted_count) {
|
|
+ continue; /* duplicate */
|
|
}
|
|
+ sorted_count = new_count;
|
|
+
|
|
+ sids_are_valid = sids_are_valid || dom_sid_equal(
|
|
+ sid, &global_sid_Claims_Valid);
|
|
+ authentication_was_compounded = authentication_was_compounded || dom_sid_equal(
|
|
+ sid, &global_sid_Compounded_Authentication);
|
|
+
|
|
+ ptoken->sids = talloc_realloc(ptoken, ptoken->sids,
|
|
+ struct dom_sid, ptoken->num_sids + 1);
|
|
+ if (ptoken->sids == NULL) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ talloc_free(ptoken);
|
|
+ return NT_STATUS_NO_MEMORY;
|
|
+ }
|
|
+ ptoken->sids[ptoken->num_sids] = *sid;
|
|
+ ptoken->num_sids++;
|
|
}
|
|
|
|
if (authentication_was_compounded && num_device_sids) {
|
|
@@ -258,31 +308,40 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
- for (i = 0; i < num_device_sids; i++) {
|
|
- uint32_t check_sid_idx;
|
|
- for (check_sid_idx = 0;
|
|
- check_sid_idx < ptoken->num_device_sids;
|
|
- check_sid_idx++) {
|
|
- if (dom_sid_equal(&ptoken->device_sids[check_sid_idx], &device_sids[i].sid)) {
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (check_sid_idx == ptoken->num_device_sids) {
|
|
- const struct dom_sid *device_sid = &device_sids[i].sid;
|
|
-
|
|
- device_sids_are_valid = device_sids_are_valid || dom_sid_equal(
|
|
- device_sid, &global_sid_Claims_Valid);
|
|
-
|
|
- ptoken->device_sids = talloc_realloc(ptoken,
|
|
- ptoken->device_sids,
|
|
- struct dom_sid,
|
|
- ptoken->num_device_sids + 1);
|
|
- if (ptoken->device_sids == NULL) {
|
|
- talloc_free(ptoken);
|
|
- return NT_STATUS_NO_MEMORY;
|
|
- }
|
|
-
|
|
- ptoken->device_sids[ptoken->num_device_sids] = *device_sid;
|
|
- ptoken->num_device_sids++;
|
|
+ sorted_device_sids = talloc_array(tmp_ctx, struct dom_sid,
|
|
+ num_device_sids > 0 ? num_device_sids : 1);
|
|
+ if (sorted_device_sids == NULL) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ talloc_free(ptoken);
|
|
+ return NT_STATUS_NO_MEMORY;
|
|
+ }
|
|
+ for (i = 0; i < num_device_sids; i++) {
|
|
+ const struct dom_sid *device_sid = &device_sids[i].sid;
|
|
+ uint32_t new_dev_count;
|
|
+
|
|
+ new_dev_count = sid_sorted_insert_unique(sorted_device_sids,
|
|
+ sorted_device_count,
|
|
+ device_sid);
|
|
+ if (new_dev_count == sorted_device_count) {
|
|
+ continue; /* duplicate */
|
|
}
|
|
+ sorted_device_count = new_dev_count;
|
|
+
|
|
+ device_sids_are_valid = device_sids_are_valid || dom_sid_equal(
|
|
+ device_sid, &global_sid_Claims_Valid);
|
|
+
|
|
+ ptoken->device_sids = talloc_realloc(ptoken,
|
|
+ ptoken->device_sids,
|
|
+ struct dom_sid,
|
|
+ ptoken->num_device_sids + 1);
|
|
+ if (ptoken->device_sids == NULL) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ talloc_free(ptoken);
|
|
+ return NT_STATUS_NO_MEMORY;
|
|
+ }
|
|
+ ptoken->device_sids[ptoken->num_device_sids] = *device_sid;
|
|
+ ptoken->num_device_sids++;
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
+ * Sort ptoken->sids[REMAINING_SIDS_INDEX..] so security_token_has_sid
|
|
+ * can use bsearch for O(log S) access checks (samba-0001 companion fix).
|
|
+ */
|
|
+ security_token_sort_sids(ptoken);
|
|
+
|