summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Potter <tpot@samba.org>2002-08-16 00:25:48 +0000
committerTim Potter <tpot@samba.org>2002-08-16 00:25:48 +0000
commit88d321becdcff10f52a629946fb300d158fcc2fa (patch)
tree520edef8ca504853959f756e086dc0cd80044291
parent298f956eaf7cbd362be8494f315a49d126a2c0ea (diff)
downloadsamba-88d321becdcff10f52a629946fb300d158fcc2fa.tar.gz
samba-88d321becdcff10f52a629946fb300d158fcc2fa.tar.bz2
samba-88d321becdcff10f52a629946fb300d158fcc2fa.zip
Merge of netbios namecache code from APPLIANCE_HEAD.
Tridge suggested a generic caching mechanism for Samba to avoid the proliferation of little cache files hanging around limpet like in the locks directory. Someone should probably implement this at some stage. (This used to be commit dad31483b3bd1790356ef1e40ac62624a403bce8)
-rw-r--r--source3/Makefile.in2
-rw-r--r--source3/lib/util_str.c12
-rw-r--r--source3/libsmb/namecache.c252
-rw-r--r--source3/libsmb/namequery.c28
-rw-r--r--source3/nsswitch/winbindd.c2
-rw-r--r--source3/param/loadparm.c6
-rw-r--r--source3/smbd/server.c2
7 files changed, 299 insertions, 5 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index b96ce8b143..696a80c412 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -166,7 +166,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \
- $(RPC_PARSE_OBJ1)
+ libsmb/namecache.o $(RPC_PARSE_OBJ1)
LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index 9dc80c89db..3b5ceb2217 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -212,6 +212,18 @@ int strwicmp(const char *psz1, const char *psz2)
}
+/* Convert a string to upper case, but don't modify it */
+
+char *strupper_static(char *s)
+{
+ static pstring str;
+
+ pstrcpy(str, s);
+ strupper(str);
+
+ return str;
+}
+
/*******************************************************************
convert a string to "normal" form
********************************************************************/
diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c
new file mode 100644
index 0000000000..fc09d8eac2
--- /dev/null
+++ b/source3/libsmb/namecache.c
@@ -0,0 +1,252 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBIOS name cache module.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static BOOL done_namecache_init;
+static BOOL enable_namecache;
+static TDB_CONTEXT *namecache_tdb;
+
+struct nc_value {
+ time_t expiry; /* When entry expires */
+ int count; /* Number of addresses */
+ struct in_addr ip_list[0]; /* Address list */
+};
+
+/* Initialise namecache system */
+
+void namecache_enable(void)
+{
+ /* Check if we have been here before, or name caching disabled
+ by setting the name cache timeout to zero. */
+
+ if (done_namecache_init)
+ return;
+
+ done_namecache_init = True;
+
+ if (lp_name_cache_timeout() == 0) {
+ DEBUG(5, ("namecache_init: disabling netbios name cache\n"));
+ return;
+ }
+
+ /* Open namecache tdb in read/write or readonly mode */
+
+ namecache_tdb = tdb_open_log(
+ lock_path("namecache.tdb"), 0,
+ TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
+
+ if (!namecache_tdb) {
+ DEBUG(5, ("namecache_init: could not open %s\n",
+ lock_path("namecache.tdb")));
+ return;
+ }
+
+ DEBUG(5, ("namecache_init: enabling netbios namecache, timeout %d "
+ "seconds\n", lp_name_cache_timeout()));
+
+ enable_namecache = True;
+}
+
+/* Return a key for a name and name type. The caller must free
+ retval.dptr when finished. */
+
+static TDB_DATA namecache_key(const char *name, int name_type)
+{
+ TDB_DATA retval;
+ char *keystr;
+
+ asprintf(&keystr, "%s#%02X", strupper_static(name), name_type);
+
+ retval.dsize = strlen(keystr) + 1;
+ retval.dptr = keystr;
+
+ return retval;
+}
+
+/* Return a data value for an IP list. The caller must free
+ retval.dptr when finished. */
+
+static TDB_DATA namecache_value(struct in_addr *ip_list, int num_names,
+ time_t expiry)
+{
+ TDB_DATA retval;
+ struct nc_value *value;
+ int size;
+
+ size = sizeof(struct nc_value) + sizeof(struct in_addr) *
+ num_names;
+
+ value = (struct nc_value *)malloc(size);
+
+ value->expiry = expiry;
+ value->count = num_names;
+
+ memcpy(value->ip_list, ip_list, num_names * sizeof(struct in_addr));
+
+ retval.dptr = (char *)value;
+ retval.dsize = size;
+
+ return retval;
+}
+
+/* Store a name in the name cache */
+
+void namecache_store(const char *name, int name_type,
+ int num_names, struct in_addr *ip_list)
+{
+ TDB_DATA key, value;
+ time_t expiry;
+ int i;
+
+ if (!enable_namecache)
+ return;
+
+ DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
+ num_names, num_names == 1 ? "": "es", name, name_type));
+
+ for (i = 0; i < num_names; i++)
+ DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
+ i == (num_names - 1) ? "" : ", "));
+
+ DEBUGADD(5, ("\n"));
+
+ key = namecache_key(name, name_type);
+
+ /* Cache pdc location or dc lists for only a little while
+ otherwise if we lock on to a bad DC we can potentially be
+ out of action for the entire cache timeout time! */
+
+ if (name_type != 0x1b || name_type != 0x1c)
+ expiry = time(NULL) + 10;
+ else
+ expiry = time(NULL) + lp_name_cache_timeout();
+
+ value = namecache_value(ip_list, num_names, expiry);
+
+ tdb_store(namecache_tdb, key, value, TDB_REPLACE);
+
+ free(key.dptr);
+ free(value.dptr);
+}
+
+/* Look up a name in the name cache. Return a mallocated list of IP
+ addresses if the name is contained in the cache. */
+
+BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
+ int *num_names)
+{
+ TDB_DATA key, value;
+ struct nc_value *data;
+ time_t now;
+ int i;
+
+ if (!enable_namecache)
+ return False;
+
+ /* Read value */
+
+ key = namecache_key(name, name_type);
+
+ value = tdb_fetch(namecache_tdb, key);
+
+ if (!value.dptr) {
+ DEBUG(5, ("namecache_fetch: %s#%02x not found\n",
+ name, name_type));
+ goto done;
+ }
+
+ data = (struct nc_value *)value.dptr;
+
+ /* Check expiry time */
+
+ now = time(NULL);
+
+ if (now > data->expiry) {
+
+ DEBUG(5, ("namecache_fetch: entry for %s#%02x expired\n",
+ name, name_type));
+
+ tdb_delete(namecache_tdb, key);
+
+ value = tdb_null;
+
+ goto done;
+ }
+
+ if ((data->expiry - now) > lp_name_cache_timeout()) {
+
+ /* Someone may have changed the system time on us */
+
+ DEBUG(5, ("namecache_fetch: entry for %s#%02x has bad expiry\n",
+ name, name_type));
+
+ tdb_delete(namecache_tdb, key);
+
+ value = tdb_null;
+
+ goto done;
+ }
+
+ /* Extract and return namelist */
+
+ *ip_list = (struct in_addr *)malloc(
+ sizeof(struct in_addr) * data->count);
+
+ memcpy(*ip_list, data->ip_list, sizeof(struct in_addr) *
+ data->count);
+
+ *num_names = data->count;
+
+ DEBUG(5, ("namecache_fetch: returning %d address%s for %s#%02x: ",
+ *num_names, *num_names == 1 ? "" : "es", name, name_type));
+
+ for (i = 0; i < *num_names; i++)
+ DEBUGADD(5, ("%s%s", inet_ntoa((*ip_list)[i]),
+ i == (*num_names - 1) ? "" : ", "));
+
+ DEBUGADD(5, ("\n"));
+
+done:
+ SAFE_FREE(key.dptr);
+ SAFE_FREE(value.dptr);
+
+ return value.dsize > 0;
+}
+
+/* Flush all names from the name cache */
+
+void namecache_flush(void)
+{
+ int result;
+
+ if (!namecache_tdb)
+ return;
+
+ result = tdb_traverse(namecache_tdb, tdb_traverse_delete_fn, NULL);
+
+ if (result == -1)
+ DEBUG(5, ("namecache_flush: error deleting cache entries\n"));
+ else
+ DEBUG(5, ("namecache_flush: deleted %d cache entr%s\n",
+ result, result == 1 ? "y" : "ies"));
+}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 3382ce4f4a..40a353fa8b 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -783,7 +783,7 @@ static BOOL resolve_hosts(const char *name,
*********************************************************/
static BOOL internal_resolve_name(const char *name, int name_type,
- struct in_addr **return_iplist, int *return_count)
+ struct in_addr **return_iplist, int *return_count)
{
pstring name_resolve_list;
fstring tok;
@@ -816,6 +816,15 @@ static BOOL internal_resolve_name(const char *name, int name_type,
return True;
}
+ /* Check netbios name cache */
+
+ if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+
+ /* This could be a negative response */
+
+ return (*return_count > 0);
+ }
+
pstrcpy(name_resolve_list, lp_name_resolve_order());
ptr = name_resolve_list;
if (!ptr || !*ptr)
@@ -823,9 +832,16 @@ static BOOL internal_resolve_name(const char *name, int name_type,
while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
if((strequal(tok, "host") || strequal(tok, "hosts"))) {
- if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
- result = True;
- goto done;
+ if (name_type == 0x20) {
+ if (resolve_hosts(name, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ } else {
+
+ /* Store negative lookup result */
+
+ namecache_store(name, name_type, 0, NULL);
+ }
}
} else if(strequal( tok, "lmhosts")) {
if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
@@ -897,6 +913,10 @@ static BOOL internal_resolve_name(const char *name, int name_type,
*return_iplist = nodupes_iplist;
*return_count = nodupes_count;
}
+
+ /* Save in name cache */
+
+ namecache_store(name, name_type, *return_count, *return_iplist);
/* Display some debugging info */
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index 047ea1accc..256c0203c0 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -691,6 +691,8 @@ int winbind_setup_common(void)
}
+ namecache_enable(); /* Enable netbios namecache */
+
/* Get list of domains we look up requests for. This includes the
domain which we are a member of as well as any trusted
domains. */
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 0967134b9b..9e4ce615e8 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -260,6 +260,7 @@ typedef struct
BOOL bUnixExtensions;
BOOL bDisableNetbios;
int restrict_anonymous;
+ int name_cache_timeout;
}
global;
@@ -838,6 +839,8 @@ static struct parm_struct parm_table[] = {
{"hostname lookups", P_BOOL, P_GLOBAL, &Globals.bHostnameLookups, NULL, NULL, 0},
{"write cache size", P_INTEGER, P_LOCAL, &sDefault.iWriteCacheSize, NULL, NULL, FLAG_SHARE},
+ {"name cache timeout", P_INTEGER, P_GLOBAL, &Globals.name_cache_timeout, NULL, NULL, 0},
+
{"Printing Options", P_SEP, P_SEPARATOR},
{"total print jobs", P_INTEGER, P_GLOBAL, &Globals.iTotalPrintJobs, NULL, NULL, FLAG_PRINT},
@@ -1375,6 +1378,8 @@ static void init_globals(void)
Globals.bWinbindEnumGroups = True;
Globals.bWinbindUseDefaultDomain = False;
+ Globals.name_cache_timeout = 660; /* In seconds */
+
Globals.bUseSpnego = True;
string_set(&Globals.smb_ports, SMB_PORTS);
@@ -1740,6 +1745,7 @@ FN_LOCAL_CHAR(lp_magicchar, magic_char)
FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
FN_GLOBAL_BOOL(lp_hide_local_users, &Globals.bHideLocalUsers)
FN_GLOBAL_BOOL(lp_algorithmic_rid_base, &Globals.bAlgorithmicRidBase)
+FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
typedef struct _param_opt_struct param_opt_struct;
struct _param_opt_struct {
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 45295896e8..41b55b9622 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -881,6 +881,8 @@ static void usage(char *pname)
* everything after this point is run after the fork()
*/
+ namecache_enable();
+
if (!locking_init(0))
exit(1);