Exemple #1
0
/**
 * Read the whole persistent cache into memory.
 */
static G_GNUC_COLD void
sha1_read_cache(void)
{
	FILE *f;
	file_path_t fp[1];
	bool truncated = FALSE;

	g_return_if_fail(settings_config_dir());

	file_path_set(fp, settings_config_dir(), "sha1_cache");
	f = file_config_open_read("SHA-1 cache", fp, G_N_ELEMENTS(fp));
	if (f) {
		for (;;) {
			char buffer[4096];

			if (NULL == fgets(buffer, sizeof buffer, f))
				break;

			if (!file_line_chomp_tail(buffer, sizeof buffer, NULL)) {
				truncated = TRUE;
			} else if (truncated) {
				truncated = FALSE;
			} else {
				parse_and_append_cache_entry(buffer);
			}
		}
		fclose(f);
		dump_cache(TRUE);
	}
}
Exemple #2
0
G_GNUC_COLD void
tls_global_init(void)
{
    static const struct {
        const char * const name;
        const int major;
        const int minor;
    } f = {
        "tls", 1, 0
    };
    char *cert_file, *key_file;

#if !defined(REMAP_ZALLOC) && !defined(TRACK_MALLOC) && !defined(TRACK_ZALLOC)
    gnutls_global_set_mem_functions(halloc, halloc, NULL, hrealloc, hfree);
#endif

    if (gnutls_global_init()) {
        g_error("gnutls_global_init() failed");
    }

#ifdef USE_TLS_CUSTOM_IO
    gnutls_global_set_log_level(9);
    gnutls_global_set_log_function(tls_log_function);
#endif	/* USE_TLS_CUSTOM_IO */

    get_dh_params();
    gnutls_certificate_allocate_credentials(&cert_cred);

    key_file = make_pathname(settings_config_dir(), "key.pem");
    cert_file = make_pathname(settings_config_dir(), "cert.pem");

    if (file_exists(key_file) && file_exists(cert_file)) {
        int ret;

        ret = gnutls_certificate_set_x509_key_file(cert_cred,
                cert_file, key_file, GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
            g_warning("gnutls_certificate_set_x509_key_file() failed: %s",
                      gnutls_strerror(ret));
        } else {
            gnutls_certificate_set_dh_params(cert_cred, get_dh_params());
        }
    }
    HFREE_NULL(key_file);
    HFREE_NULL(cert_file);

    header_features_add(FEATURES_CONNECTIONS, f.name, f.major, f.minor);
    header_features_add(FEATURES_G2_CONNECTIONS, f.name, f.major, f.minor);
    header_features_add(FEATURES_DOWNLOADS, f.name, f.major, f.minor);
    header_features_add(FEATURES_UPLOADS, f.name, f.major, f.minor);
}
Exemple #3
0
/**
 * Loads the spam.txt into memory.
 *
 * The selected file will then be monitored and a reloading will occur
 * shortly after a modification.
 */
static void
spam_retrieve(void)
{
	file_path_t fp[4];
	FILE *f;
	int idx;
	char *tmp;
	unsigned length = 0;

	file_path_set(&fp[length++], settings_config_dir(), spam_text_file);
	file_path_set(&fp[length++], PRIVLIB_EXP, spam_text_file);

#ifndef OFFICIAL_BUILD
	file_path_set(&fp[length++], PACKAGE_EXTRA_SOURCE_DIR, spam_text_file);
#endif	/* !OFFICIAL_BUILD */

	tmp = get_folder_path(PRIVLIB_PATH, NULL);
	if (tmp != NULL)
		file_path_set(&fp[length++], tmp, spam_text_file);

	g_assert(length <= G_N_ELEMENTS(fp));

	f = file_config_open_read_norename_chosen(spam_what, fp, length, &idx);
	if (f != NULL) {
		spam_retrieve_from_file(f, fp[idx].dir, fp[idx].name);
		fclose(f);
	}

	HFREE_NULL(tmp);
}
Exemple #4
0
/**
 * Initialize node stability caching.
 */
G_GNUC_COLD void
stable_init(void)
{
    dbstore_kv_t kv = { KUID_RAW_SIZE, NULL, sizeof(struct lifedata), 0 };
    dbstore_packing_t packing =
    { serialize_lifedata, deserialize_lifedata, NULL };

    g_assert(NULL == db_lifedata);
    g_assert(NULL == stable_sync_ev);
    g_assert(NULL == stable_prune_ev);

    /* Legacy: remove after 0.97 -- RAM, 2011-05-03 */
    dbstore_move(settings_config_dir(), settings_dht_db_dir(), db_stable_base);

    db_lifedata = dbstore_open(db_stable_what, settings_dht_db_dir(),
                               db_stable_base, kv, packing, STABLE_DB_CACHE_SIZE, kuid_hash, kuid_eq,
                               GNET_PROPERTY(dht_storage_in_memory));

    dbmw_set_map_cache(db_lifedata, STABLE_MAP_CACHE_SIZE);
    stable_prune_old();

    stable_sync_ev = cq_periodic_main_add(STABLE_SYNC_PERIOD,
                                          stable_sync, NULL);

    stable_prune_ev = cq_periodic_main_add(STABLE_PRUNE_PERIOD,
                                           stable_periodic_prune, NULL);
}
Exemple #5
0
/**
 * Initialize RX dumping.
 *
 * @return TRUE if initialized.
 */
static gboolean
dump_initialize(struct dump *dump)
{
	char *pathname;

	if (dump->initialized)
		return TRUE;

	pathname = make_pathname(settings_config_dir(), dump->filename);
	dump->fd = file_open_missing(pathname, O_WRONLY | O_APPEND | O_NONBLOCK);
	HFREE_NULL(pathname);

	/*
	 * If the dump "file" is actually a named pipe, we'd block quickly
	 * if there was no reader.  So set the file as non-blocking and
	 * we'll disable dumping as soon as we can't write all the data
	 * we want.
	 */

	if (dump->fd < 0) {
		g_warning("can't open %s -- disabling dumping", dump->filename);
		dump_disable(dump);
		return FALSE;
	}

	fd_set_nonblocking(dump->fd);

	dump->slist = slist_new();
	dump->fill = 0;
	dump->initialized = TRUE;

	return TRUE;
}
Exemple #6
0
/**
 * Initialize security token caching.
 */
G_GNUC_COLD void
tcache_init(void)
{
	dbstore_kv_t kv = { KUID_RAW_SIZE, NULL, sizeof(struct tokdata),
		sizeof(struct tokdata) + MAX_INT_VAL(uint8) };
	dbstore_packing_t packing =
		{ serialize_tokdata, deserialize_tokdata, free_tokdata };

	g_assert(NULL == db_tokdata);
	g_assert(NULL == tcache_prune_ev);

	/* Legacy: remove after 0.97 -- RAM, 2011-05-03 */
	dbstore_move(settings_config_dir(), settings_dht_db_dir(), db_tcache_base);

	db_tokdata = dbstore_create(db_tcache_what, settings_dht_db_dir(),
		db_tcache_base, kv, packing, TOK_DB_CACHE_SIZE, kuid_hash, kuid_eq,
		GNET_PROPERTY(dht_storage_in_memory));

	dbmw_set_map_cache(db_tokdata, TOK_MAP_CACHE_SIZE);
	dbmw_set_debugging(db_tokdata, &tcache_dbmw_dbg);

	token_life = MIN(TOK_LIFE, token_lifetime());

	if (GNET_PROPERTY(dht_tcache_debug))
		g_debug("DHT cached token lifetime set to %u secs",
			(unsigned) token_life);

	tcache_prune_ev = cq_periodic_main_add(TCACHE_PRUNE_PERIOD,
		tcache_periodic_prune, NULL);
}
Exemple #7
0
/**
 * Dump the whole in-memory cache onto disk.
 */
static void
dump_cache(bool force)
{
	FILE *f;
	file_path_t fp;

	if (!force && !cache_dirty)
		return;
	
	file_path_set(&fp, settings_config_dir(), "sha1_cache");
	f = file_config_open_write("SHA-1 cache", &fp);
	if (f) {
		struct dump_cache_context ctx;
		
		fputs(sha1_persistent_cache_file_header, f);
		ctx.f = f;
		ctx.forced = force;
		hikset_foreach(sha1_cache, dump_cache_one_entry, &ctx);
		if (file_config_close(f, &fp)) {
			cache_dirty = FALSE;
		}
	}

	/*
	 * Update the timestamp even on failure to avoid that we retry this
	 * too frequently.
	 */
	cache_dumped = tm_time();
}
Exemple #8
0
/**
 * Add an entry to the persistent cache.
 */
static void
add_persistent_cache_entry(const char *filename, filesize_t size,
	time_t mtime, const struct sha1 *sha1, const struct tth *tth)
{
	char *pathname;
	FILE *f;

	pathname = make_pathname(settings_config_dir(), "sha1_cache");
	f = file_fopen(pathname, "a");
	if (f) {
		filestat_t sb;

		/*
		 * If we're adding the very first entry (file empty), then emit header.
		 */

		if (fstat(fileno(f), &sb)) {
			g_warning("%s(): could not stat \"%s\": %m", G_STRFUNC, pathname);
		} else {
			if (0 == sb.st_size) {
				fputs(sha1_persistent_cache_file_header, f);
			}
			cache_entry_print(f, filename, sha1, tth, size, mtime);
		}
		fclose(f);
	} else {
		g_warning("%s(): could not open \"%s\": %m", G_STRFUNC, pathname);
	}
	HFREE_NULL(pathname);
}
Exemple #9
0
static const char *
tth_cache_directory(void)
{
	static char *directory;

	if (!directory) {
		directory = make_pathname(settings_config_dir(), "tth_cache");
	}
	return NOT_LEAKING(directory);
}
Exemple #10
0
/**
 * Loads the geo-ip.txt into memory.
 *
 * Choosing the first file we find among the several places we look at,
 * typically:
 *
 *		-# ~/.gtk-gnutella/geo-ip.txt
 *		-# /usr/share/gtk-gnutella/geo-ip.txt
 *		-# /home/src/gtk-gnutella/geo-ip.txt
 *
 * The selected file will then be monitored and a reloading will occur
 * shortly after a modification.
 */
static void
gip_retrieve(unsigned n)
{
	FILE *f;
	int idx;
	char *filename;
	file_path_t fp[4];
	unsigned length = 0;
	char *tmp;
	
	file_path_set(&fp[length++], settings_config_dir(), gip_source[n].file);
	
	tmp = get_folder_path(PRIVLIB_PATH, NULL);
	if (tmp != NULL)
		file_path_set(&fp[length++], tmp, gip_source[n].file);
	
	file_path_set(&fp[length++], PRIVLIB_EXP, gip_source[n].file);
#ifndef OFFICIAL_BUILD
	file_path_set(&fp[length++], PACKAGE_EXTRA_SOURCE_DIR, gip_source[n].file);
#endif

	g_assert(length <= G_N_ELEMENTS(fp));

	f = file_config_open_read_norename_chosen(gip_source[n].what,
			fp, length, &idx);

	if (NULL == f)
	   goto done;

	filename = make_pathname(fp[idx].dir, fp[idx].name);
	watcher_register(filename, gip_changed, uint_to_pointer(n));
	HFREE_NULL(filename);

	gip_load(f, n);
	fclose(f);

done:
	HFREE_NULL(tmp);
}
Exemple #11
0
/**
 * Save upload statistics to file.
 */
static void
upload_stats_dump_history(void)
{
	FILE *out;
	file_path_t fp;

	/* open file for writing */
	file_path_set(&fp, settings_config_dir(), ul_stats_file);
	out = file_config_open_write(ul_stats_what, &fp);

	if (NULL == out)
		return;

	file_config_preamble(out, "Upload statistics");

	fputs(
		"#\n"
		"# Format is:\n"
		"#    File basename <TAB> size <TAB> attempts <TAB> completed\n"
		"#        <TAB> bytes_sent-high <TAB> bytes_sent-low\n"
		"#        <TAB> time of last request <TAB> time of last served chunk\n"
		"#        <TAB> SHA1 (\"*\" if unknown)\n"
		"#\n"
		"\n",
		out
	);

	/*
	 * Don't check this sooner so that the file is cleared, if the user
	 * cleared the history.
	 */
	if (upload_stats_list) {
		/* for each element in uploads_stats_list, write out to hist file */
		hash_list_foreach(upload_stats_list, upload_stats_dump_item, out);
	}

	file_config_close(out, &fp);
	dirty = FALSE;
}
Exemple #12
0
/**
 * Loads the bogons.txt into memory.
 *
 * Choosing the first file we find among the several places we look at,
 * typically:
 *
 *	-# ~/.gtk-gnutella/bogons.txt
 *	-# /usr/share/gtk-gnutella/bogons.txt
 *	-# PACKAGE_EXTRA_SOURCE_DIR/bogons.txt
 *
 * The selected file will then be monitored and a reloading will occur
 * shortly after a modification.
 */
static G_GNUC_COLD void
bogons_retrieve(void)
{
	FILE *f;
	int idx;
	char *filename;
	file_path_t fp[4];
	unsigned length = 0;	
	char *tmp;

	file_path_set(&fp[length++], settings_config_dir(), bogons_file);
	tmp = get_folder_path(PRIVLIB_PATH, NULL);
	if (tmp != NULL)
		file_path_set(&fp[length++], tmp, bogons_file);
	
	file_path_set(&fp[length++], PRIVLIB_EXP, bogons_file);
#ifndef OFFICIAL_BUILD
	file_path_set(&fp[length++], PACKAGE_EXTRA_SOURCE_DIR, bogons_file);
#endif

	g_assert(length <= G_N_ELEMENTS(fp));

	f = file_config_open_read_norename_chosen(bogons_what, fp, length, &idx);

	if (NULL == f)
	   goto done;

	filename = make_pathname(fp[idx].dir, fp[idx].name);
	watcher_register(filename, bogons_changed, NULL);
	HFREE_NULL(filename);

	bogons_load(f);
	fclose(f);

done:
	HFREE_NULL(tmp);
}
Exemple #13
0
/**
 * Store known GWC URLs.
 * They are normally saved in ~/.gtk-gnutella/gwcache.
 */
static void
gwc_store(void)
{
    FILE *out;
    int i;
    int j;
    file_path_t fp;

    file_path_set(&fp, settings_config_dir(), gwc_file);
    out = file_config_open_write(gwc_what, &fp);
    if (!out)
        return;

    file_config_preamble(out, "Gnutella web cache URLs");

    /*
     * Start dumping with the next slot we'll supersede, so that the oldest
     * entries are at the top: when the cache is full, we'll loop over at
     * retrieve time and will start superseding the oldest entries.
     */

    i = gwc_url_slot + 1;
    if (i >= MAX_GWC_URLS)
        i = 0;

    for (j = 0; j < MAX_GWC_URLS; j++) {
        const char *url = gwc_url[i].url;

        i = (i + 1) % MAX_GWC_URLS;
        if (url == NULL)
            continue;
        fprintf(out, "%s\n", url);
    }

    if (file_config_close(out, &fp))
        gwc_file_dirty = FALSE;
}
/**
 * Loads the whitelist into memory.
 */
static void G_COLD
whitelist_retrieve(void)
{
	char line[1024];
	FILE *f;
	filestat_t st;
	unsigned linenum = 0;
	file_path_t fp[1];

	whitelist_generation++;

	file_path_set(fp, settings_config_dir(), whitelist_file);
	f = file_config_open_read_norename("Host Whitelist", fp, N_ITEMS(fp));
	if (!f)
		return;

	if (fstat(fileno(f), &st)) {
		g_warning("%s(): fstat() failed: %m", G_STRFUNC);
		fclose(f);
		return;
	}

    while (fgets(line, sizeof line, f)) {
		pslist_t *sl_addr, *sl;
		const char *endptr, *start;
		host_addr_t addr;
    	uint16 port;
		uint8 bits;
		bool item_ok;
		bool use_tls;
		char *hname;

        linenum++;

		if (!file_line_chomp_tail(line, sizeof line, NULL)) {
			g_warning("%s(): line %u too long, aborting", G_STRFUNC, linenum);
			break;
		}

        if (file_line_is_skipable(line))
			continue;

		sl_addr = NULL;
		addr = zero_host_addr;
		endptr = NULL;
		hname = NULL;

		endptr = is_strprefix(line, "tls:");
		if (endptr) {
			use_tls = TRUE;
			start = endptr;
		} else {
			use_tls = FALSE;
			start = line;
		}

		port = 0;
		if (string_to_host_addr_port(start, &endptr, &addr, &port)) {
       		sl_addr = name_to_host_addr(host_addr_to_string(addr),
							settings_dns_net());
		} else if (string_to_host_or_addr(start, &endptr, &addr)) {
			uchar c = *endptr;

			switch (c) {
			case '\0':
			case ':':
			case '/':
				break;
			default:
				if (!is_ascii_space(c))
					endptr = NULL;
			}

			if (!endptr) {
				g_warning("%s(): line %d: "
					"expected a hostname or IP address \"%s\"",
					G_STRFUNC, linenum, line);
				continue;
			}

			/* Terminate the string for name_to_host_addr() */
			hname = h_strndup(start, endptr - start);
		} else {
            g_warning("%s(): line %d: expected hostname or IP address \"%s\"",
				G_STRFUNC, linenum, line);
			continue;
		}

       	g_assert(sl_addr != NULL || hname != NULL);
		g_assert(NULL != endptr);
		bits = 0;
		item_ok = TRUE;

		/*
		 * When an explicit address is given (no hostname) and with no
		 * port, one can suffix the address with bits to indicate a CIDR
		 * range of whitelisted addresses.
		 */

		if (0 == port) {
			/* Ignore trailing items separated by a space */
			while ('\0' != *endptr && !is_ascii_space(*endptr)) {
				uchar c = *endptr++;

				if (':' == c) {
					int error;
					uint32 v;

					if (0 != port) {
						g_warning("%s(): line %d: multiple colons after host",
							G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}

					v = parse_uint32(endptr, &endptr, 10, &error);
					port = (error || v > 0xffff) ? 0 : v;
					if (0 == port) {
						g_warning("%s(): line %d: "
							"invalid port value after host",
							G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}
				} else if ('/' == c) {
					const char *ep;
					uint32 mask;

					if (0 != bits) {
						g_warning("%s(): line %d: "
							"multiple slashes after host", G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}

					if (string_to_ip_strict(endptr, &mask, &ep)) {
						if (!host_addr_is_ipv4(addr)) {
							g_warning("%s(): line %d: "
								"IPv4 netmask after non-IPv4 address",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}
						endptr = ep;

						if (0 == (bits = netmask_to_cidr(mask))) {
							g_warning("%s(): line %d: "
								"IPv4 netmask after non-IPv4 address",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}

					} else {
						int error;
						uint32 v;

						v = parse_uint32(endptr, &endptr, 10, &error);
						if (
							error ||
							0 == v ||
							(v > 32 && host_addr_is_ipv4(addr)) ||
							(v > 128 && host_addr_is_ipv6(addr))
						) {
							g_warning("%s(): line %d: "
								"invalid numeric netmask after host",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}
						bits = v;
					}
				} else {
					g_warning("%s(): line %d: "
						"unexpected character after host", G_STRFUNC, linenum);
					item_ok = FALSE;
					break;
				}
			}
		}

		if (item_ok) {
			struct whitelist *item;
			if (hname) {
				item = whitelist_hostname_create(use_tls, hname, port);
				whitelist_dns_resolve(item, FALSE);
			} else {
				PSLIST_FOREACH(sl_addr, sl) {
					host_addr_t *aptr = sl->data;
					g_assert(aptr != NULL);
					item = whitelist_addr_create(use_tls, *aptr, port, bits);
					whitelist_add(item);
				}
			}
		} else {
Exemple #15
0
const char *
guc_settings_config_dir(void)
{
    return settings_config_dir();
}
Exemple #16
0
G_GNUC_COLD void
upload_stats_load_history(void)
{
	FILE *upload_stats_file;
	file_path_t fp;
	char line[FILENAME_MAX + 64];
	guint lineno = 0;

	gcu_upload_stats_gui_freeze();
	
	file_path_set(&fp, settings_config_dir(), ul_stats_file);

	/* open file for reading */
	upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1);
	if (upload_stats_file == NULL)
		goto done;

	/* parse, insert names into ul_stats_clist */
	while (fgets(line, sizeof(line), upload_stats_file)) {
		static const struct ul_stats zero_item;
		struct ul_stats item;
		struct sha1 sha1_buf;
		const char *p;
		size_t i;

		lineno++;
		if (line[0] == '#' || line[0] == '\n')
			continue;

		p = strchr(line, '\t');
		if (NULL == p)
			goto corrupted;

		line[p - line] = '\0';		/* line is now the URL-escaped file name */
		p++;

		/* URL-unescape in-place */
		if (!url_unescape(line, TRUE))
			goto corrupted;

		item = zero_item;
		item.pathname = line;

		for (i = 0; i < 8; i++) {
			guint64 v;
			int error;
			const char *endptr;

			p = skip_ascii_spaces(p);

			/* SVN versions up to 15322 had only 6 fields in the history */
			if (5 == i && '\0' == *p)
				break;

			switch (i) {
			case 7:
				/* We have a SHA1 or '*' if none known */
				if ('*' != *p) {
					size_t len = clamp_strlen(p, SHA1_BASE32_SIZE);
					
					error = !parse_base32_sha1(p, len, &sha1_buf);
					item.sha1 = error ? NULL : &sha1_buf;
				} else {
					error = FALSE;
				}
				p = skip_ascii_non_spaces(p);
				v = 0;
				break;
			default:
				v = parse_uint64(p, &endptr, 10, &error);
				p = deconstify_gchar(endptr);
			}

			if (error || !is_ascii_space(*endptr))
				goto corrupted;

			switch (i) {
			case 0: item.size = v; break;
			case 1: item.attempts = v; break;
			case 2: item.complete = v; break;
			case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break;
			case 4: item.bytes_sent |= (guint32) v; break;
			case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0);
			case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); 
			case 7: break;	/* Already stored above */
			default:
				g_assert_not_reached();
				goto corrupted;
			}
		}

		/* 
		 * We store the filenames UTF-8 encoded but the file might have been
		 * edited or corrupted.
		 */
		if (is_absolute_path(item.pathname)) {
			item.filename = lazy_filename_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC);
		} else {
			item.filename = lazy_unknown_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC, NULL);
		}

		if (upload_stats_find(NULL, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else if (upload_stats_find(item.sha1, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else {
			upload_stats_add(item.pathname, item.size, item.filename,
				item.attempts, item.complete, item.bytes_sent,
				item.rtime, item.dtime, item.sha1);
		}
		continue;

	corrupted:
		g_warning("upload statistics file corrupted at line %u.", lineno);
	}

	/* close file */
	fclose(upload_stats_file);

done:
	gcu_upload_stats_gui_thaw();
	return;
}