diff options
| -rw-r--r-- | source3/Makefile.in | 5 | ||||
| -rw-r--r-- | source3/lib/gencache.c | 319 | ||||
| -rw-r--r-- | source3/utils/net.c | 1 | ||||
| -rw-r--r-- | source3/utils/net_cache.c | 328 | ||||
| -rw-r--r-- | source3/utils/net_help.c | 1 | 
5 files changed, 652 insertions, 2 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 3578b93020..0a28937fc9 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -140,7 +140,7 @@ LIB_OBJ = lib/charcnv.o lib/debug.o lib/fault.o \  	  lib/md5.o lib/hmacmd5.o lib/iconv.o lib/smbpasswd.o \  	  nsswitch/wb_client.o nsswitch/wb_common.o \  	  lib/pam_errors.o intl/lang_tdb.o lib/account_pol.o \ -	  lib/adt_tree.o lib/popt_common.o $(TDB_OBJ)  +	  lib/adt_tree.o lib/popt_common.o lib/gencache.o $(TDB_OBJ)   LIB_SMBD_OBJ = lib/system_smbd.o lib/util_smbd.o @@ -383,7 +383,8 @@ CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \  NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \  	   utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \ -	   utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o +	   utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \ +	   utils/net_cache.o  NET_OBJ = $(NET_OBJ1) $(SECRETS_OBJ) $(LIBSMB_OBJ) \  	  $(RPC_PARSE_OBJ) $(PASSDB_GET_SET_OBJ) \ diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c new file mode 100644 index 0000000000..9e2009ad4a --- /dev/null +++ b/source3/lib/gencache.c @@ -0,0 +1,319 @@ +/*  +   Unix SMB/CIFS implementation. + +   Generic, persistent and shared between processes cache mechanism for use +   by various parts of the Samba code + +   Copyright (C) Rafal Szczesniak    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" + +#undef  DBGC_CLASS +#define DBGC_CLASS DBGC_TDB + +#define TIMEOUT_LEN 12 +#define CACHE_DATA_FMT	"%12u/%s" + +static TDB_CONTEXT *cache; + +/** + * @file gencache.c + * @brief Generic, persistent and shared between processes cache mechanism + *        for use by various parts of the Samba code + * + **/ + + +/** + * Cache initialisation function. Opens cache tdb file or creates + * it if does not exist. + * + * @return true on successful initialisation of the cache or + *         false on failure + **/ + +BOOL gencache_init(void) +{ +	char* cache_fname = NULL; +	 +	/* skip file open if it's already opened */ +	if (cache) return True; + +	asprintf(&cache_fname, "%s/%s", lp_lockdir(), "gencache.tdb"); +	if (cache_fname) +		DEBUG(5, ("Opening cache file at %s\n", cache_fname)); +	else { +		DEBUG(0, ("Filename allocation failed.\n")); +		return False; +	} + +	cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, +	                     O_RDWR|O_CREAT, 0644); + +	SAFE_FREE(cache_fname); +	if (!cache) { +		DEBUG(0, ("Attempt to open the cache file has failed.\n")); +		return False; +	} +	return True; +} + + +/** + * Cache shutdown function. Closes opened cache tdb file. + * + * @return true on successful closing the cache or + *         false on failure during cache shutdown + **/ +  +BOOL gencache_shutdown(void) +{ +	/* tdb_close routine returns 0 on successful close */ +	if (!cache) return False; +	DEBUG(5, ("Closing cache file\n")); +	return tdb_close(cache) ? False : True; +} + + +/** + * Add one entry to the cache file. + * (it part of tridge's proposed API) + * + * @param key string that represents a key of this entry + * @param value text representation value being cached + * @param timeout time when the value is expired + * + * @return true when entry is successfuly stored or + *         false on the attempt's failure + **/ +  +BOOL gencache_add(const char *keystr, const char *value, time_t timeout) +{ +	int ret; +	TDB_DATA keybuf, databuf; +	char* valstr = NULL; +	 +	/* fail completely if get null pointers passed */ +	SMB_ASSERT(keystr && value); + +	if (!gencache_init()) return False; +	 +	asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value); +	keybuf.dptr = strdup(keystr); +	keybuf.dsize = strlen(keystr); +	databuf.dptr = strdup(valstr); +	databuf.dsize = strlen(valstr); +	DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout \ +	           = %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout), +	           (int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past")); +		 +	ret = tdb_store(cache, keybuf, databuf, TDB_INSERT); +	SAFE_FREE(valstr); +	SAFE_FREE(keybuf.dptr); +	SAFE_FREE(databuf.dptr); +	 +	return ret == 0 ? True : False; +} + + +/** + * Set existing entry to the cache file. + * (it part of tridge's proposed API) + * + * @param key string that represents a key of this entry + * @param value text representation value being cached + * @param timeout time when the value is expired + * + * @return true when entry is successfuly set or + *         false on the attempt's failure + **/ + +BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout) +{ +	int ret = -1; +	TDB_DATA keybuf, databuf; +	char *old_valstr, *datastr; +	time_t old_timeout; +	 +	/* fail completely if get null pointers passed */ +	SMB_ASSERT(keystr && valstr); + +	if (!gencache_init()) return False; +			 +	/*  +	 * Check whether entry exists in the cache +	 * Don't verify gencache_get exit code, since the entry may be expired +	 */	 +	gencache_get(keystr, &old_valstr, &old_timeout); +	 +	if (!(old_valstr && old_timeout)) return False; +		 +	DEBUG(10, ("Setting cache entry with key = %s; old value = %s and old timeout \ +	           = %s\n", keystr, old_valstr, ctime(&old_timeout))); + +	asprintf(&datastr, CACHE_DATA_FMT, (int)timeout, valstr); +	keybuf.dptr = strdup(keystr); +	keybuf.dsize = strlen(keystr); +	databuf.dptr = strdup(datastr); +	databuf.dsize = strlen(datastr); +	DEBUGADD(10, ("New value = %s, new timeout = %s (%d seconds %s)", valstr, +	              ctime(&timeout), (int)(timeout - time(NULL)), +	              timeout > time(NULL) ? "ahead" : "in the past")); + +		 +	ret = tdb_store(cache, keybuf, databuf, TDB_REPLACE); + +	SAFE_FREE(datastr); +	SAFE_FREE(old_valstr); +	SAFE_FREE(keybuf.dptr); +	SAFE_FREE(databuf.dptr); +	 +	return ret == 0 ? True : False; +} +  + +/** + * Delete one entry from the cache file. + * (it part of tridge's proposed API) + * + * @param key string that represents a key of this entry + * + * @return true upon successful deletion or + *         false in case of failure + **/ + +BOOL gencache_del(const char *keystr) +{ +	int ret; +	TDB_DATA keybuf; +	 +	/* fail completely if get null pointers passed */ +	SMB_ASSERT(keystr); + +	if (!gencache_init()) return False;	 +	 +	keybuf.dptr = strdup(keystr); +	keybuf.dsize = strlen(keystr); +	DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr)); +	ret = tdb_delete(cache, keybuf); +	 +	SAFE_FREE(keybuf.dptr); +	return ret == 0 ? True : False; +} + + +/** + * Get existing entry from the cache file. + * (it part of tridge's proposed API) + * + * @param key string that represents a key of this entry + * @param value buffer that is allocated and filled with the entry value + *        buffer's disposing is done outside + * @param timeout pointer to a time_t that is filled with entry's + *        timeout + * + * @return true when entry is successfuly fetched or + *         false on the failure + **/ + +BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) +{ +	TDB_DATA keybuf, databuf; + +	/* fail completely if get null pointers passed */ +	SMB_ASSERT(keystr && valstr && timeout); + +	if (!gencache_init()) return False; +	 +	keybuf.dptr = strdup(keystr); +	keybuf.dsize = strlen(keystr); +	databuf = tdb_fetch(cache, keybuf); +	 +	if (databuf.dptr) { +		char* entry_buf = strndup(databuf.dptr, databuf.dsize); +		*valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN)); +				 +		sscanf(entry_buf, CACHE_DATA_FMT, (int*)timeout, *valstr); +		SAFE_FREE(entry_buf); + +		DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, timeout = %s\n", +		           *timeout > time(NULL) ? "valid" : "expired", keystr, *valstr, +		           ctime(timeout))); +		return *timeout > time(NULL); +	} else { +		*valstr = NULL; +		timeout = NULL; +		DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr)); +		return False; +	} +} + + +/** + * Iterate through all entries which key matches to specified pattern + * + * @param fn pointer to the function that will be supplied with each single + *        matching cache entry (key, value and timeout) as an arguments + * @param keystr_pattern pattern the existing entries' keys are matched to + * + **/ + +void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout), +                      const char* keystr_pattern) +{ +	TDB_LIST_NODE *node, *first_node; +	TDB_DATA databuf; +	char *keystr = NULL, *valstr = NULL, *entry = NULL; +	time_t timeout = 0; + +	/* fail completely if get null pointers passed */ +	SMB_ASSERT(fn && keystr_pattern); + +	if (!gencache_init()) return; + +	DEBUG(5, ("Searching cache keys with pattern %s", keystr_pattern)); +	node = tdb_search_keys(cache, keystr_pattern); +	first_node = node; +	 +	while (node) { +		/* ensure null termination of the key string */ +		node->node_key.dptr[node->node_key.dsize] = '\0'; +		keystr = node->node_key.dptr; + +		/*  +		 * We don't use gencache_get function, because we need to iterate through +		 * all of the entries. Validity verification is up to fn routine. +		 */ +		databuf = tdb_fetch(cache, node->node_key); +		entry = strndup(databuf.dptr, databuf.dsize); +		valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN)); +		sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr); +		 +		DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n", +		           keystr, valstr, ctime(&timeout))); +		fn(keystr, valstr, timeout); +		 +		SAFE_FREE(valstr); +		SAFE_FREE(entry); +		node = node->next; +	} +	 +	tdb_search_list_free(first_node); +} + + diff --git a/source3/utils/net.c b/source3/utils/net.c index a3aa7adcae..e3cfc24b69 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -352,6 +352,7 @@ static struct functable net_func[] = {  	{"TIME", net_time},  	{"LOOKUP", net_lookup},  	{"JOIN", net_join}, +	{"CACHE", net_cache},  	{"HELP", net_help},  	{NULL, NULL} diff --git a/source3/utils/net_cache.c b/source3/utils/net_cache.c new file mode 100644 index 0000000000..359c06d1aa --- /dev/null +++ b/source3/utils/net_cache.c @@ -0,0 +1,328 @@ +/*  +   Samba Unix/Linux SMB client library  +   Distributed SMB/CIFS Server Management Utility  +   Copyright (C) Rafal Szczesniak    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" +#include "net.h" + +/** + * @file net_cache.c + * @brief This is part of the net tool which is basically command + *        line wrapper for gencache.c functions (mainly for testing) + * + **/ + + +/* + * These routines are used via gencache_iterate() to display the cache's contents + * (print_cache_entry) and to flush it (delete_cache_entry). + * Both of them are defined by first arg of gencache_iterate() routine. + */ +static void print_cache_entry(const char* keystr, const char* datastr, const time_t timeout) +{ +	char* timeout_str = ctime(&timeout); +	timeout_str[strlen(timeout_str) - 1] = '\0'; +	d_printf("Key: %s\t\t Value: %s\t\t Timeout: %s %s\n", keystr, datastr, +	         timeout_str, timeout > time(NULL) ? "": "(expired)"); +} + +static void delete_cache_entry(const char* keystr, const char* datastr, const time_t timeout) +{ +	if (!gencache_del(keystr)) +		d_printf("Couldn't delete entry! key = %s", keystr); +} + + +/** + * Parse text representation of timeout value + * + * @param timeout_str string containing text representation of the timeout + * @return numeric timeout of time_t type + **/ +static time_t parse_timeout(const char* timeout_str) +{ +	char sign = '\0', *number = NULL, unit = '\0'; +	int len, number_begin, number_end; +	time_t timeout; + +	/* sign detection */ +	if (timeout_str[0] == '!' || timeout_str[0] == '+') { +		sign = timeout_str[0]; +		number_begin = 1; +	} else { +		number_begin = 0; +	} +	 +	/* unit detection */ +	len = strlen(timeout_str); +	switch (timeout_str[len - 1]) { +	case 's': +	case 'm': +	case 'h': +	case 'd': +	case 'w': unit = timeout_str[len - 1]; +	} +	 +	/* number detection */ +	len = (sign) ? strlen(&timeout_str[number_begin]) : len; +	number_end = (unit) ? len - 1 : len; +	number = strndup(&timeout_str[number_begin], number_end); +	 +	/* calculate actual timeout value */ +	timeout = (time_t)atoi(number); + +	switch (unit) { +	case 'm': timeout *= 60; break; +	case 'h': timeout *= 60*60; break; +	case 'd': timeout *= 60*60*24; break; +	case 'w': timeout *= 60*60*24*7; break;  /* that's fair enough, I think :) */ +	} +	 +	switch (sign) { +	case '!': timeout = time(NULL) - timeout; break; +	case '+': +	default:  timeout += time(NULL); break; +	} +	 +	if (number) SAFE_FREE(number); +	return timeout;	 +} + + +/** + * Add an entry to the cache + *  + * @param argv key, value and timeout are passed in command line + * @return 0 on success, otherwise failure + **/ +static int net_cache_add(int argc, const char **argv) +{ +	const char *keystr, *datastr, *timeout_str; +	time_t timeout; +	 +	if (argc < 3) { +		d_printf("\nUsage: net cache add <key string> <data string> <timeout>\n"); +		return -1; +	} +	 +	keystr = argv[0]; +	datastr = argv[1]; +	timeout_str = argv[2]; +	 +	/* parse timeout given in command line */ +	timeout = parse_timeout(timeout_str); +	if (!timeout) { +		d_printf("Invalid timeout argument.\n"); +		return -1; +	} +	 +	if (gencache_add(keystr, datastr, timeout)) { +		d_printf("New cache entry stored successfully.\n"); +		gencache_shutdown(); +		return 0; +	}  + +	d_printf("Entry couldn't be added. Perhaps there's already such a key.\n"); +	gencache_shutdown(); +	return -1; +} + + +/** + * Set new value of an existing entry in the cache + *  + * @param argv key being searched and new value and timeout to set in the entry + * @return 0 on success, otherwise failure + **/ +static int net_cache_set(int argc, const char **argv) +{ +	const char *keystr, *datastr, *timeout_str; +	time_t timeout; +	 +	if (argc < 3) { +		d_printf("\nUsage: net cache set <key string> <data string> <timeout>\n"); +		return -1; +	} +	 +	keystr = argv[0]; +	datastr = argv[1]; +	timeout_str = argv[2]; +	 +	/* parse timeout given in command line */ +	timeout = parse_timeout(timeout_str); +	if (!timeout) { +		d_printf("Invalid timeout argument.\n"); +		return -1; +	} +	 +	if (gencache_set(keystr, datastr, timeout)) { +		d_printf("Cache entry set successfully.\n"); +		gencache_shutdown(); +		return 0; +	} + +	d_printf("Entry couldn't be set. Perhaps there's no such a key.\n"); +	gencache_shutdown(); +	return -1; +} + + +/** + * Delete an entry in the cache + *  + * @param argv key to delete an entry of + * @return 0 on success, otherwise failure + **/ +static int net_cache_del(int argc, const char **argv) +{ +	const char *keystr = argv[0]; +	 +	if (argc < 1) { +		d_printf("\nUsage: net cache add <key string>\n"); +		return -1; +	} +	 +	if(gencache_del(keystr)) { +		d_printf("Entry deleted.\n"); +		return 0; +	}  + +	d_printf("Couldn't delete specified entry\n"); +	return -1; +} + + +/** + * Get and display an entry from the cache + *  + * @param argv key to search an entry of + * @return 0 on success, otherwise failure + **/ +static int net_cache_get(int argc, const char **argv) +{ +	const char* keystr = argv[0]; +	char* valuestr; +	time_t timeout; + +	if (argc < 1) { +		d_printf("\nUsage: net cache get <key>\n"); +		return -1; +	} +	 +	if (gencache_get(keystr, &valuestr, &timeout)) { +		print_cache_entry(keystr, valuestr, timeout); +		return 0; +	}  + +	d_printf("Failed to find entry\n"); +	return -1; +} + + +/** + * Search an entry/entries in the cache + *  + * @param argv key pattern to match the entries to + * @return 0 on success, otherwise failure + **/ +static int net_cache_search(int argc, const char **argv) +{ +	const char* pattern; +	 +	if (argc < 1) { +		d_printf("Usage: net cache search <pattern>\n"); +		return -1; +	} +	 +	pattern = argv[0]; +	gencache_iterate(print_cache_entry, pattern); +	return 0; +} + + +/** + * List the contents of the cache + *  + * @param argv ignored in this functionailty + * @return always returns 0 + **/ +static int net_cache_list(int argc, const char **argv) +{ +	const char* pattern = "*"; +	gencache_iterate(print_cache_entry, pattern); +	gencache_shutdown(); +	return 0; +} + + +/** + * Flush the whole cache + *  + * @param argv ignored in this functionality + * @return always returns 0 + **/ +static int net_cache_flush(int argc, const char **argv) +{ +	const char* pattern = "*"; +	gencache_iterate(delete_cache_entry, pattern); +	gencache_shutdown(); +	return 0; +} + + +/** + * Short help + * + * @param argv ignored in this functionality + * @return always returns -1 + **/ +static int net_cache_usage(int argc, const char **argv) +{ +	d_printf("  net cache add \t add add new cache entry\n"); +	d_printf("  net cache set \t set new value for existing cache entry\n"); +	d_printf("  net cache del \t delete existing cache entry by key\n"); +	d_printf("  net cache flush \t delete all entries existing in the cache\n"); +	d_printf("  net cache get \t get cache entry by key\n"); +	d_printf("  net cache search \t search for entries in the cache, by given pattern\n"); +	d_printf("  net cache list \t list all cache entries (just like search for \"*\")\n"); +	return -1; +} + + +/** + * Entry point to 'net cache' subfunctionality + * + * @param argv arguments passed to further called functions + * @return whatever further functions return + **/ +int net_cache(int argc, const char **argv) +{ +	struct functable func[] = { +		{"add", net_cache_add}, +		{"set", net_cache_set}, +		{"del", net_cache_del}, +		{"get", net_cache_get}, +		{"search", net_cache_search}, +		{"list", net_cache_list}, +		{"flush", net_cache_flush}, +		{NULL, NULL} +	}; + +	return net_run_function(argc, argv, func, net_cache_usage); +} diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c index ab3eac4b43..16309c5334 100644 --- a/source3/utils/net_help.c +++ b/source3/utils/net_help.c @@ -135,6 +135,7 @@ static int net_usage(int argc, const char **argv)  		 "  net user\t\tto manage users\n"\  		 "  net group\t\tto manage groups\n"\  		 "  net join\t\tto join a domain\n"\ +		 "  net cache\t\tto operate on cache tdb file\n"\  		 "\n"\  		 "  net ads <command>\tto run ADS commands\n"\  		 "  net rap <command>\tto run RAP (pre-RPC) commands\n"\  | 
