diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/lib/util_str.c | 12 | ||||
-rw-r--r-- | source3/libsmb/namecache.c | 252 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 28 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.c | 2 | ||||
-rw-r--r-- | source3/param/loadparm.c | 6 | ||||
-rw-r--r-- | source3/smbd/server.c | 2 |
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); |