From 1ea5ee8d88ad9b8f8feb0787251e731d93c85023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Wed, 19 Dec 2012 13:53:23 +0100 Subject: [PATCH 1/9] libcli/auth: also set secure channel type in netlogon_creds_client_init(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Günther Deschner Reviewed-by: Stefan Metzmacher Reviewed-by: Andreas Schneider (cherry picked from commit a9d5b2fdf03a25e7669258de6c83288be3335cef) --- libcli/auth/credentials.c | 2 ++ libcli/auth/proto.h | 1 + source3/rpc_client/cli_netlogon.c | 1 + source4/librpc/rpc/dcerpc_schannel.c | 1 + source4/torture/ntp/ntp_signd.c | 1 + source4/torture/rpc/lsa.c | 1 + source4/torture/rpc/netlogon.c | 3 +++ source4/torture/rpc/samba3rpc.c | 2 ++ 8 files changed, 12 insertions(+) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index 7c8d53c..fb77ede 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 89a732e..6bc18d7 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/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 66a50a8..3d6a3e1 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/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index be1ab24..1480486 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/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c index 89eb1a0..5f097fe 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 107af11..7385ad4 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 dadf8bc..c7bdf49 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); @@ -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); @@ -310,6 +312,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); diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index 9443d5e..432e9d5 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); -- 1.9.1 From f74f84f377075de062663543caab74ba7f2a4b5a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 18 Jul 2014 11:06:50 +0200 Subject: [PATCH 2/9] selftest/knownfail: add ^samba4.rpc.netlogon.*.invalidAuthenticate2 for v4-1-* This works in master (>= 4.2), but not in 4.1.x. Signed-off-by: Stefan Metzmacher --- selftest/knownfail | 1 + 1 file changed, 1 insertion(+) diff --git a/selftest/knownfail b/selftest/knownfail index 3768f82..c493dba 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 -- 1.9.1 From 68eba8e34b521de92f7965bbb39c88942b584da7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 10 Jan 2014 12:19:08 +0100 Subject: [PATCH 3/9] s4:torture/rpc: add invalidAuthenticate2 This add 'rpc.netlogon.netlogon.invalidAuthenticate2' as new test it demonstrates the STATUS_BUFFER_OVERFLOW on computer names larger than 15 characters. Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Jan 22 19:07:12 CET 2014 on sn-devel-104 (cherry picked from commit 38f8788d6bf7fac509dcf492214a66a8bb3ac3fc) --- source4/torture/rpc/netlogon.c | 88 +++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index c7bdf49..666f60c 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -202,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; @@ -234,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; @@ -255,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); @@ -266,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, @@ -1044,6 +1066,43 @@ 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_SamLogon_NULL_domain(struct torture_context *tctx, struct dcerpc_pipe *p, struct cli_credentials *credentials) @@ -3883,6 +3942,7 @@ 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, "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); -- 1.9.1 From fc2021bd9c7bc6024823ae69fa3b319d49a78c0c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:41:20 +0200 Subject: [PATCH 4/9] s3:lib/memcache: use uint8_t instead of uint8 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit d7cbc63dc7537fc9562da985b77f6d62dc41fd84) --- source3/lib/memcache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/lib/memcache.c b/source3/lib/memcache.c index 88453f3..fe38c9d 100644 --- a/source3/lib/memcache.c +++ b/source3/lib/memcache.c @@ -26,7 +26,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 */ }; @@ -96,7 +96,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; -- 1.9.1 From 078295be58dcff19d7150e4a12d17fa600475ef5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:48:51 +0200 Subject: [PATCH 5/9] s3:lib/memcache: make use of talloc for memcache_elements Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 91105d1057c29c5878f50678baeb1bd1a6f1abe3) --- source3/lib/memcache.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source3/lib/memcache.c b/source3/lib/memcache.c index fe38c9d..0f0538f 100644 --- a/source3/lib/memcache.c +++ b/source3/lib/memcache.c @@ -63,7 +63,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; } @@ -206,7 +206,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 +285,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; -- 1.9.1 From d39aa8bc07d8829afbef6bbbcc836cc54e75a4d5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:49:48 +0200 Subject: [PATCH 6/9] s3:lib/memcache: only include the required header files We don't need the full "includes.h". Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit b560fac7f78b761ee279d8e87a749125665eb5d1) --- source3/include/memcache.h | 2 -- source3/lib/memcache.c | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source3/include/memcache.h b/source3/include/memcache.h index 9362483..11e5971 100644 --- a/source3/include/memcache.h +++ b/source3/include/memcache.h @@ -20,8 +20,6 @@ #ifndef __MEMCACHE_H__ #define __MEMCACHE_H__ -#include "includes.h" - struct memcache; /* diff --git a/source3/lib/memcache.c b/source3/lib/memcache.c index 0f0538f..50e59fc 100644 --- a/source3/lib/memcache.c +++ b/source3/lib/memcache.c @@ -17,8 +17,13 @@ along with this program. If not, see . */ -#include "memcache.h" +#include "replace.h" +#include +#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; -- 1.9.1 From 1bb27163a0df16f778f4aa9f94f34e701afdb0b5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:58:34 +0200 Subject: [PATCH 7/9] lib/util: move memcache.[ch] to the toplevel 'samba-util' library This is generic enough that it could be used in all code. Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Fri Jul 18 15:43:33 CEST 2014 on sn-devel-104 (cherry picked from commit 45807028d478c082fef6f3a3d5a142d96d63fb50) --- lib/util/memcache.c | 421 +++++++++++++++++++++++++++++++++++++++++ lib/util/memcache.h | 110 +++++++++++ lib/util/wscript_build | 2 +- source3/auth/token_util.c | 2 +- source3/include/memcache.h | 110 ----------- source3/lib/access.c | 2 +- source3/lib/id_cache.c | 2 +- source3/lib/memcache.c | 421 ----------------------------------------- source3/lib/username.c | 2 +- source3/lib/util_sock.c | 2 +- source3/passdb/lookup_sid.c | 2 +- source3/passdb/pdb_interface.c | 2 +- source3/smbd/dir.c | 2 +- source3/smbd/globals.c | 2 +- source3/smbd/mangle_hash2.c | 2 +- source3/smbd/server.c | 2 +- source3/smbd/statcache.c | 2 +- source3/smbd/vfs.c | 2 +- source3/torture/torture.c | 2 +- source3/wscript_build | 2 +- 20 files changed, 547 insertions(+), 547 deletions(-) create mode 100644 lib/util/memcache.c create mode 100644 lib/util/memcache.h delete mode 100644 source3/include/memcache.h delete mode 100644 source3/lib/memcache.c diff --git a/lib/util/memcache.c b/lib/util/memcache.c new file mode 100644 index 0000000..50e59fc --- /dev/null +++ b/lib/util/memcache.c @@ -0,0 +1,421 @@ +/* + Unix SMB/CIFS implementation. + In-memory cache + Copyright (C) Volker Lendecke 2007 + + 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 . +*/ + +#include "replace.h" +#include +#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; + +struct memcache_element { + struct rb_node rb_node; + struct memcache_element *prev, *next; + size_t keylength, valuelength; + uint8_t n; /* This is really an enum, but save memory */ + char data[1]; /* placeholder for offsetof */ +}; + +struct memcache { + struct memcache_element *mru; + struct rb_root tree; + size_t size; + size_t max_size; +}; + +static void memcache_element_parse(struct memcache_element *e, + DATA_BLOB *key, DATA_BLOB *value); + +static bool memcache_is_talloc(enum memcache_number n) +{ + bool result; + + switch (n) { + case GETPWNAM_CACHE: + case PDB_GETPWSID_CACHE: + case SINGLETON_CACHE_TALLOC: + result = true; + break; + default: + result = false; + break; + } + + return result; +} + +static int memcache_destructor(struct memcache *cache) { + struct memcache_element *e, *next; + + for (e = cache->mru; e != NULL; e = next) { + next = e->next; + TALLOC_FREE(e); + } + return 0; +} + +struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size) +{ + struct memcache *result; + + result = talloc_zero(mem_ctx, struct memcache); + if (result == NULL) { + return NULL; + } + result->max_size = max_size; + talloc_set_destructor(result, memcache_destructor); + return result; +} + +void memcache_set_global(struct memcache *cache) +{ + TALLOC_FREE(global_cache); + global_cache = cache; +} + +static struct memcache_element *memcache_node2elem(struct rb_node *node) +{ + return (struct memcache_element *) + ((char *)node - offsetof(struct memcache_element, rb_node)); +} + +static void memcache_element_parse(struct memcache_element *e, + DATA_BLOB *key, DATA_BLOB *value) +{ + key->data = ((uint8_t *)e) + offsetof(struct memcache_element, data); + key->length = e->keylength; + value->data = key->data + e->keylength; + value->length = e->valuelength; +} + +static size_t memcache_element_size(size_t key_length, size_t value_length) +{ + return sizeof(struct memcache_element) - 1 + key_length + value_length; +} + +static int memcache_compare(struct memcache_element *e, enum memcache_number n, + DATA_BLOB key) +{ + DATA_BLOB this_key, this_value; + + if ((int)e->n < (int)n) return 1; + if ((int)e->n > (int)n) return -1; + + if (e->keylength < key.length) return 1; + if (e->keylength > key.length) return -1; + + memcache_element_parse(e, &this_key, &this_value); + return memcmp(this_key.data, key.data, key.length); +} + +static struct memcache_element *memcache_find( + struct memcache *cache, enum memcache_number n, DATA_BLOB key) +{ + struct rb_node *node; + + node = cache->tree.rb_node; + + while (node != NULL) { + struct memcache_element *elem = memcache_node2elem(node); + int cmp; + + cmp = memcache_compare(elem, n, key); + if (cmp == 0) { + return elem; + } + node = (cmp < 0) ? node->rb_left : node->rb_right; + } + + return NULL; +} + +bool memcache_lookup(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, DATA_BLOB *value) +{ + struct memcache_element *e; + + if (cache == NULL) { + cache = global_cache; + } + if (cache == NULL) { + return false; + } + + e = memcache_find(cache, n, key); + if (e == NULL) { + return false; + } + + if (cache->size != 0) { + DLIST_PROMOTE(cache->mru, e); + } + + memcache_element_parse(e, &key, value); + return true; +} + +void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n, + DATA_BLOB key) +{ + DATA_BLOB value; + void *result; + + if (!memcache_lookup(cache, n, key, &value)) { + return NULL; + } + + if (value.length != sizeof(result)) { + return NULL; + } + + memcpy(&result, value.data, sizeof(result)); + + return result; +} + +static void memcache_delete_element(struct memcache *cache, + struct memcache_element *e) +{ + rb_erase(&e->rb_node, &cache->tree); + + DLIST_REMOVE(cache->mru, e); + + if (memcache_is_talloc(e->n)) { + DATA_BLOB cache_key, cache_value; + void *ptr; + + memcache_element_parse(e, &cache_key, &cache_value); + SMB_ASSERT(cache_value.length == sizeof(ptr)); + memcpy(&ptr, cache_value.data, sizeof(ptr)); + TALLOC_FREE(ptr); + } + + cache->size -= memcache_element_size(e->keylength, e->valuelength); + + TALLOC_FREE(e); +} + +static void memcache_trim(struct memcache *cache) +{ + if (cache->max_size == 0) { + return; + } + + while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) { + memcache_delete_element(cache, DLIST_TAIL(cache->mru)); + } +} + +void memcache_delete(struct memcache *cache, enum memcache_number n, + DATA_BLOB key) +{ + struct memcache_element *e; + + if (cache == NULL) { + cache = global_cache; + } + if (cache == NULL) { + return; + } + + e = memcache_find(cache, n, key); + if (e == NULL) { + return; + } + + memcache_delete_element(cache, e); +} + +void memcache_add(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, DATA_BLOB value) +{ + struct memcache_element *e; + struct rb_node **p; + struct rb_node *parent; + DATA_BLOB cache_key, cache_value; + size_t element_size; + + if (cache == NULL) { + cache = global_cache; + } + if (cache == NULL) { + return; + } + + if (key.length == 0) { + return; + } + + e = memcache_find(cache, n, key); + + if (e != NULL) { + memcache_element_parse(e, &cache_key, &cache_value); + + if (value.length <= cache_value.length) { + if (memcache_is_talloc(e->n)) { + void *ptr; + SMB_ASSERT(cache_value.length == sizeof(ptr)); + memcpy(&ptr, cache_value.data, sizeof(ptr)); + TALLOC_FREE(ptr); + } + /* + * We can reuse the existing record + */ + memcpy(cache_value.data, value.data, value.length); + e->valuelength = value.length; + return; + } + + memcache_delete_element(cache, e); + } + + element_size = memcache_element_size(key.length, value.length); + + e = talloc_size(cache, element_size); + if (e == NULL) { + DEBUG(0, ("talloc failed\n")); + return; + } + talloc_set_type(e, struct memcache_element); + + e->n = n; + e->keylength = key.length; + e->valuelength = value.length; + + memcache_element_parse(e, &cache_key, &cache_value); + memcpy(cache_key.data, key.data, key.length); + memcpy(cache_value.data, value.data, value.length); + + parent = NULL; + p = &cache->tree.rb_node; + + while (*p) { + struct memcache_element *elem = memcache_node2elem(*p); + int cmp; + + parent = (*p); + + cmp = memcache_compare(elem, n, key); + + p = (cmp < 0) ? &(*p)->rb_left : &(*p)->rb_right; + } + + rb_link_node(&e->rb_node, parent, p); + rb_insert_color(&e->rb_node, &cache->tree); + + DLIST_ADD(cache->mru, e); + + cache->size += element_size; + memcache_trim(cache); +} + +void memcache_add_talloc(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, void *pptr) +{ + void **ptr = (void **)pptr; + void *p; + + if (cache == NULL) { + cache = global_cache; + } + if (cache == NULL) { + return; + } + + p = talloc_move(cache, ptr); + memcache_add(cache, n, key, data_blob_const(&p, sizeof(p))); +} + +void memcache_flush(struct memcache *cache, enum memcache_number n) +{ + struct rb_node *node; + + if (cache == NULL) { + cache = global_cache; + } + if (cache == NULL) { + return; + } + + /* + * Find the smallest element of number n + */ + + node = cache->tree.rb_node; + if (node == NULL) { + return; + } + + /* + * First, find *any* element of number n + */ + + while (true) { + struct memcache_element *elem = memcache_node2elem(node); + struct rb_node *next; + + if ((int)elem->n == (int)n) { + break; + } + + if ((int)elem->n < (int)n) { + next = node->rb_right; + } + else { + next = node->rb_left; + } + if (next == NULL) { + break; + } + node = next; + } + + /* + * Then, find the leftmost element with number n + */ + + while (true) { + struct rb_node *prev = rb_prev(node); + struct memcache_element *elem; + + if (prev == NULL) { + break; + } + elem = memcache_node2elem(prev); + if ((int)elem->n != (int)n) { + break; + } + node = prev; + } + + while (node != NULL) { + struct memcache_element *e = memcache_node2elem(node); + struct rb_node *next = rb_next(node); + + if (e->n != n) { + break; + } + + memcache_delete_element(cache, e); + node = next; + } +} diff --git a/lib/util/memcache.h b/lib/util/memcache.h new file mode 100644 index 0000000..11e5971 --- /dev/null +++ b/lib/util/memcache.h @@ -0,0 +1,110 @@ +/* + Unix SMB/CIFS implementation. + In-memory cache + Copyright (C) Volker Lendecke 2007-2008 + + 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 . +*/ + +#ifndef __MEMCACHE_H__ +#define __MEMCACHE_H__ + +struct memcache; + +/* + * A memcache can store different subkeys with overlapping keys, the + * memcache_number becomes part of the key. Feel free to add caches of your + * own here. + * + * If you add talloc type caches, also note this in the switch statement in + * memcache_is_talloc(). + */ + +enum memcache_number { + STAT_CACHE, + GETWD_CACHE, + GETPWNAM_CACHE, /* talloc */ + MANGLE_HASH2_CACHE, + PDB_GETPWSID_CACHE, /* talloc */ + SINGLETON_CACHE_TALLOC, /* talloc */ + SINGLETON_CACHE, + SMB1_SEARCH_OFFSET_MAP +}; + +/* + * Create a memcache structure. max_size is in bytes, if you set it 0 it will + * not forget anything. + */ + +struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size); + +/* + * If you set this global memcache, use it as the default cache when NULL is + * passed to the memcache functions below. This is a workaround for many + * situations where passing the cache everywhere would be a big hassle. + */ + +void memcache_set_global(struct memcache *cache); + +/* + * Add a data blob to the cache + */ + +void memcache_add(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, DATA_BLOB value); + +/* + * Add a talloc object to the cache. The difference to memcache_add() is that + * when the objects is to be discared, talloc_free is called for it. Also + * talloc_move() ownership of the object to the cache. + * + * Please note that the current implementation has a fixed relationship + * between what cache subtypes store talloc objects and which ones store plain + * blobs. We can fix this, but for now we don't have a mixed use of blobs vs + * talloc objects in the cache types. + */ + +void memcache_add_talloc(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, void *ptr); + +/* + * Delete an object from the cache + */ + +void memcache_delete(struct memcache *cache, enum memcache_number n, + DATA_BLOB key); + +/* + * Look up an object from the cache. Memory still belongs to the cache, so + * make a copy of it if needed. + */ + +bool memcache_lookup(struct memcache *cache, enum memcache_number n, + DATA_BLOB key, DATA_BLOB *value); + +/* + * Look up an object from the cache. Memory still belongs to the cache, so + * make a copy of it if needed. + */ + +void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n, + DATA_BLOB key); + +/* + * Flush a complete cache subset. + */ + +void memcache_flush(struct memcache *cache, enum memcache_number n); + +#endif diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 5087116..f161f96 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/source3/auth/token_util.c b/source3/auth/token_util.c index be44ce9..039387f 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/memcache.h b/source3/include/memcache.h deleted file mode 100644 index 11e5971..0000000 --- a/source3/include/memcache.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - Unix SMB/CIFS implementation. - In-memory cache - Copyright (C) Volker Lendecke 2007-2008 - - 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 . -*/ - -#ifndef __MEMCACHE_H__ -#define __MEMCACHE_H__ - -struct memcache; - -/* - * A memcache can store different subkeys with overlapping keys, the - * memcache_number becomes part of the key. Feel free to add caches of your - * own here. - * - * If you add talloc type caches, also note this in the switch statement in - * memcache_is_talloc(). - */ - -enum memcache_number { - STAT_CACHE, - GETWD_CACHE, - GETPWNAM_CACHE, /* talloc */ - MANGLE_HASH2_CACHE, - PDB_GETPWSID_CACHE, /* talloc */ - SINGLETON_CACHE_TALLOC, /* talloc */ - SINGLETON_CACHE, - SMB1_SEARCH_OFFSET_MAP -}; - -/* - * Create a memcache structure. max_size is in bytes, if you set it 0 it will - * not forget anything. - */ - -struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size); - -/* - * If you set this global memcache, use it as the default cache when NULL is - * passed to the memcache functions below. This is a workaround for many - * situations where passing the cache everywhere would be a big hassle. - */ - -void memcache_set_global(struct memcache *cache); - -/* - * Add a data blob to the cache - */ - -void memcache_add(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, DATA_BLOB value); - -/* - * Add a talloc object to the cache. The difference to memcache_add() is that - * when the objects is to be discared, talloc_free is called for it. Also - * talloc_move() ownership of the object to the cache. - * - * Please note that the current implementation has a fixed relationship - * between what cache subtypes store talloc objects and which ones store plain - * blobs. We can fix this, but for now we don't have a mixed use of blobs vs - * talloc objects in the cache types. - */ - -void memcache_add_talloc(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, void *ptr); - -/* - * Delete an object from the cache - */ - -void memcache_delete(struct memcache *cache, enum memcache_number n, - DATA_BLOB key); - -/* - * Look up an object from the cache. Memory still belongs to the cache, so - * make a copy of it if needed. - */ - -bool memcache_lookup(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, DATA_BLOB *value); - -/* - * Look up an object from the cache. Memory still belongs to the cache, so - * make a copy of it if needed. - */ - -void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n, - DATA_BLOB key); - -/* - * Flush a complete cache subset. - */ - -void memcache_flush(struct memcache *cache, enum memcache_number n); - -#endif diff --git a/source3/lib/access.c b/source3/lib/access.c index 044c079..b664dc8 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 e6e3457..3a703ae 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/memcache.c b/source3/lib/memcache.c deleted file mode 100644 index 50e59fc..0000000 --- a/source3/lib/memcache.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - Unix SMB/CIFS implementation. - In-memory cache - Copyright (C) Volker Lendecke 2007 - - 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 . -*/ - -#include "replace.h" -#include -#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; - -struct memcache_element { - struct rb_node rb_node; - struct memcache_element *prev, *next; - size_t keylength, valuelength; - uint8_t n; /* This is really an enum, but save memory */ - char data[1]; /* placeholder for offsetof */ -}; - -struct memcache { - struct memcache_element *mru; - struct rb_root tree; - size_t size; - size_t max_size; -}; - -static void memcache_element_parse(struct memcache_element *e, - DATA_BLOB *key, DATA_BLOB *value); - -static bool memcache_is_talloc(enum memcache_number n) -{ - bool result; - - switch (n) { - case GETPWNAM_CACHE: - case PDB_GETPWSID_CACHE: - case SINGLETON_CACHE_TALLOC: - result = true; - break; - default: - result = false; - break; - } - - return result; -} - -static int memcache_destructor(struct memcache *cache) { - struct memcache_element *e, *next; - - for (e = cache->mru; e != NULL; e = next) { - next = e->next; - TALLOC_FREE(e); - } - return 0; -} - -struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size) -{ - struct memcache *result; - - result = talloc_zero(mem_ctx, struct memcache); - if (result == NULL) { - return NULL; - } - result->max_size = max_size; - talloc_set_destructor(result, memcache_destructor); - return result; -} - -void memcache_set_global(struct memcache *cache) -{ - TALLOC_FREE(global_cache); - global_cache = cache; -} - -static struct memcache_element *memcache_node2elem(struct rb_node *node) -{ - return (struct memcache_element *) - ((char *)node - offsetof(struct memcache_element, rb_node)); -} - -static void memcache_element_parse(struct memcache_element *e, - DATA_BLOB *key, DATA_BLOB *value) -{ - key->data = ((uint8_t *)e) + offsetof(struct memcache_element, data); - key->length = e->keylength; - value->data = key->data + e->keylength; - value->length = e->valuelength; -} - -static size_t memcache_element_size(size_t key_length, size_t value_length) -{ - return sizeof(struct memcache_element) - 1 + key_length + value_length; -} - -static int memcache_compare(struct memcache_element *e, enum memcache_number n, - DATA_BLOB key) -{ - DATA_BLOB this_key, this_value; - - if ((int)e->n < (int)n) return 1; - if ((int)e->n > (int)n) return -1; - - if (e->keylength < key.length) return 1; - if (e->keylength > key.length) return -1; - - memcache_element_parse(e, &this_key, &this_value); - return memcmp(this_key.data, key.data, key.length); -} - -static struct memcache_element *memcache_find( - struct memcache *cache, enum memcache_number n, DATA_BLOB key) -{ - struct rb_node *node; - - node = cache->tree.rb_node; - - while (node != NULL) { - struct memcache_element *elem = memcache_node2elem(node); - int cmp; - - cmp = memcache_compare(elem, n, key); - if (cmp == 0) { - return elem; - } - node = (cmp < 0) ? node->rb_left : node->rb_right; - } - - return NULL; -} - -bool memcache_lookup(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, DATA_BLOB *value) -{ - struct memcache_element *e; - - if (cache == NULL) { - cache = global_cache; - } - if (cache == NULL) { - return false; - } - - e = memcache_find(cache, n, key); - if (e == NULL) { - return false; - } - - if (cache->size != 0) { - DLIST_PROMOTE(cache->mru, e); - } - - memcache_element_parse(e, &key, value); - return true; -} - -void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n, - DATA_BLOB key) -{ - DATA_BLOB value; - void *result; - - if (!memcache_lookup(cache, n, key, &value)) { - return NULL; - } - - if (value.length != sizeof(result)) { - return NULL; - } - - memcpy(&result, value.data, sizeof(result)); - - return result; -} - -static void memcache_delete_element(struct memcache *cache, - struct memcache_element *e) -{ - rb_erase(&e->rb_node, &cache->tree); - - DLIST_REMOVE(cache->mru, e); - - if (memcache_is_talloc(e->n)) { - DATA_BLOB cache_key, cache_value; - void *ptr; - - memcache_element_parse(e, &cache_key, &cache_value); - SMB_ASSERT(cache_value.length == sizeof(ptr)); - memcpy(&ptr, cache_value.data, sizeof(ptr)); - TALLOC_FREE(ptr); - } - - cache->size -= memcache_element_size(e->keylength, e->valuelength); - - TALLOC_FREE(e); -} - -static void memcache_trim(struct memcache *cache) -{ - if (cache->max_size == 0) { - return; - } - - while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) { - memcache_delete_element(cache, DLIST_TAIL(cache->mru)); - } -} - -void memcache_delete(struct memcache *cache, enum memcache_number n, - DATA_BLOB key) -{ - struct memcache_element *e; - - if (cache == NULL) { - cache = global_cache; - } - if (cache == NULL) { - return; - } - - e = memcache_find(cache, n, key); - if (e == NULL) { - return; - } - - memcache_delete_element(cache, e); -} - -void memcache_add(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, DATA_BLOB value) -{ - struct memcache_element *e; - struct rb_node **p; - struct rb_node *parent; - DATA_BLOB cache_key, cache_value; - size_t element_size; - - if (cache == NULL) { - cache = global_cache; - } - if (cache == NULL) { - return; - } - - if (key.length == 0) { - return; - } - - e = memcache_find(cache, n, key); - - if (e != NULL) { - memcache_element_parse(e, &cache_key, &cache_value); - - if (value.length <= cache_value.length) { - if (memcache_is_talloc(e->n)) { - void *ptr; - SMB_ASSERT(cache_value.length == sizeof(ptr)); - memcpy(&ptr, cache_value.data, sizeof(ptr)); - TALLOC_FREE(ptr); - } - /* - * We can reuse the existing record - */ - memcpy(cache_value.data, value.data, value.length); - e->valuelength = value.length; - return; - } - - memcache_delete_element(cache, e); - } - - element_size = memcache_element_size(key.length, value.length); - - e = talloc_size(cache, element_size); - if (e == NULL) { - DEBUG(0, ("talloc failed\n")); - return; - } - talloc_set_type(e, struct memcache_element); - - e->n = n; - e->keylength = key.length; - e->valuelength = value.length; - - memcache_element_parse(e, &cache_key, &cache_value); - memcpy(cache_key.data, key.data, key.length); - memcpy(cache_value.data, value.data, value.length); - - parent = NULL; - p = &cache->tree.rb_node; - - while (*p) { - struct memcache_element *elem = memcache_node2elem(*p); - int cmp; - - parent = (*p); - - cmp = memcache_compare(elem, n, key); - - p = (cmp < 0) ? &(*p)->rb_left : &(*p)->rb_right; - } - - rb_link_node(&e->rb_node, parent, p); - rb_insert_color(&e->rb_node, &cache->tree); - - DLIST_ADD(cache->mru, e); - - cache->size += element_size; - memcache_trim(cache); -} - -void memcache_add_talloc(struct memcache *cache, enum memcache_number n, - DATA_BLOB key, void *pptr) -{ - void **ptr = (void **)pptr; - void *p; - - if (cache == NULL) { - cache = global_cache; - } - if (cache == NULL) { - return; - } - - p = talloc_move(cache, ptr); - memcache_add(cache, n, key, data_blob_const(&p, sizeof(p))); -} - -void memcache_flush(struct memcache *cache, enum memcache_number n) -{ - struct rb_node *node; - - if (cache == NULL) { - cache = global_cache; - } - if (cache == NULL) { - return; - } - - /* - * Find the smallest element of number n - */ - - node = cache->tree.rb_node; - if (node == NULL) { - return; - } - - /* - * First, find *any* element of number n - */ - - while (true) { - struct memcache_element *elem = memcache_node2elem(node); - struct rb_node *next; - - if ((int)elem->n == (int)n) { - break; - } - - if ((int)elem->n < (int)n) { - next = node->rb_right; - } - else { - next = node->rb_left; - } - if (next == NULL) { - break; - } - node = next; - } - - /* - * Then, find the leftmost element with number n - */ - - while (true) { - struct rb_node *prev = rb_prev(node); - struct memcache_element *elem; - - if (prev == NULL) { - break; - } - elem = memcache_node2elem(prev); - if ((int)elem->n != (int)n) { - break; - } - node = prev; - } - - while (node != NULL) { - struct memcache_element *e = memcache_node2elem(node); - struct rb_node *next = rb_next(node); - - if (e->n != n) { - break; - } - - memcache_delete_element(cache, e); - node = next; - } -} diff --git a/source3/lib/username.c b/source3/lib/username.c index 665fbb4..d44db75 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 54286b3..22ba764 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/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 6ec6ce8..e4d41c4 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 ea67e2f..d9e7bb5 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/smbd/dir.c b/source3/smbd/dir.c index 1be5daa..3c3f662 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/globals.c b/source3/smbd/globals.c index 3eb65a1..e03c7c4 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/mangle_hash2.c b/source3/smbd/mangle_hash2.c index c2910f8..ac1f4b0 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/server.c b/source3/smbd/server.c index 9e249d1..918fb88 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" diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index 92010c2..2f3b067 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 49609d0..4a0588e 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 5002887..2e66912 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/wscript_build b/source3/wscript_build index d4f999a..9461b05 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) -- 1.9.1 From 1769c3c82ef70a8dc863bd8454491f610672650e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 14:20:58 +0200 Subject: [PATCH 8/9] s4:rpc_server/netlogon: keep a global challenge table Some clients call netr_ServerReqChallenge() and netr_ServerAuthenticate3() on different connections. This works against Windows DCs as they have a global challenge table. A VMware provisioning task for Windows VMs seemy to rely on this behavior. As a fallback we're storing the challenge in a global memcache with a fixed size. This should allow these strange clients to work against a Samba AD DC. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10723 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (similar to commit 321ebc99b5a00f82265aee741a48aa84b214d6e8) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 91 +++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b3b9989..70239a4 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, -- 1.9.1 From 38128fc0b5b2dfa3329097100cdd57f8e51ce6b8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 16:05:12 +0200 Subject: [PATCH 9/9] s4:torture/rpc: add rpc.netlogon.ServerReqChallengeGlobal This demonstrates that the challenge table should be global. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10723 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Sat Jul 19 12:51:39 CEST 2014 on sn-devel-104 (cherry picked from commit d90f3323ee001080645dcd25da8b8ce1367b1377) --- source4/torture/rpc/netlogon.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 666f60c..7569117 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -1103,6 +1103,78 @@ static bool test_invalidAuthenticate2(struct torture_context *tctx, 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) @@ -3943,6 +4015,7 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx) 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); -- 1.9.1