From 271d263590e0b69b7ba0dc797a95d7984670f6c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:41:20 +0200 Subject: [PATCH 1/6] s3:lib/memcache: use uint8_t instead of uint8 Signed-off-by: Stefan Metzmacher --- 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 eee095c91e28c9edb0e5ad9b31c77be34b58220c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:48:51 +0200 Subject: [PATCH 2/6] s3:lib/memcache: make use of talloc for memcache_elements Signed-off-by: Stefan Metzmacher --- 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 994a0d63e8bfc83adf30931e9293fcfd7cbd926c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:49:48 +0200 Subject: [PATCH 3/6] s3:lib/memcache: only include the required header files We don't need the full "includes.h". Signed-off-by: Stefan Metzmacher --- 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 d5a0376..97490b9 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 145efe12ca2092ca6e56162b15eb4836fff5a4ef Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 12:58:34 +0200 Subject: [PATCH 4/6] 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 --- lib/util/memcache.c | 421 +++++++++++++++++++++++++++++++++++++++++ lib/util/memcache.h | 111 +++++++++++ lib/util/wscript_build | 2 +- source3/auth/token_util.c | 2 +- source3/include/memcache.h | 111 ----------- source3/lib/access.c | 2 +- source3/lib/gencache.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 +- 21 files changed, 549 insertions(+), 549 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..97490b9 --- /dev/null +++ b/lib/util/memcache.h @@ -0,0 +1,111 @@ +/* + 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, + GENCACHE_RAM, + 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 fe2c183..bcb7b66 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 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 8b0174f..9bb014c 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 97490b9..0000000 --- a/source3/include/memcache.h +++ /dev/null @@ -1,111 +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, - GENCACHE_RAM, - 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 a2de35c..58db722 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/gencache.c b/source3/lib/gencache.c index 0fb1fd8..3e67d9e 100644 --- a/source3/lib/gencache.c +++ b/source3/lib/gencache.c @@ -25,7 +25,7 @@ #include "system/filesys.h" #include "system/glob.h" #include "util_tdb.h" -#include "memcache.h" +#include "../lib/util/memcache.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_TDB 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 847aa33..f69d9c3 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 c5de61a..522f600 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 fa44f3e..5f24d78 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 2c82856..ed42961 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 818f778..55d7742 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 bafd493f..dd1e20a 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 "util_cluster.h" #include "printing/queue_process.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 d5390ed..3574049 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 eb3958e..ba23a85 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 6f668ba..38f0d12 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -765,7 +765,7 @@ bld.SAMBA3_SUBSYSTEM('tdb-wrap3', deps='talloc samba3-util') 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 38c36dca8f0cfde481814043e8e68d658768bcac Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 14:20:58 +0200 Subject: [PATCH 5/6] 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 --- 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 c7fed22..49eb5c3 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; @@ -100,6 +129,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); + server_flags = NETLOGON_NEG_ACCOUNT_LOCKOUT | NETLOGON_NEG_PERSISTENT_SAMREPL | NETLOGON_NEG_ARCFOUR | @@ -273,8 +353,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; } @@ -282,8 +365,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 44d99d5abd1220ecd777f52e19318d16d40f15a0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Jul 2014 16:05:12 +0200 Subject: [PATCH 6/6] 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 --- 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 90bfe7e..76135a3 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