Skip to content
Snippets Groups Projects
common.c 27.2 KiB
Newer Older
	}
	if (word == NULL)
		goto ferr;
	while ((word = fetch_read_word(f)) != NULL) {
		if (strcmp(word, "login") == 0) {
			if ((word = fetch_read_word(f)) == NULL)
				goto ferr;
			if (snprintf(url->user, sizeof(url->user),
				"%s", word) > (int)sizeof(url->user)) {
				fetch_info("login name in .netrc is too long");
				url->user[0] = '\0';
			}
		} else if (strcmp(word, "password") == 0) {
			if ((word = fetch_read_word(f)) == NULL)
				goto ferr;
			if (snprintf(url->pwd, sizeof(url->pwd),
				"%s", word) > (int)sizeof(url->pwd)) {
				fetch_info("password in .netrc is too long");
				url->pwd[0] = '\0';
			}
		} else if (strcmp(word, "account") == 0) {
			if ((word = fetch_read_word(f)) == NULL)
				goto ferr;
			/* XXX not supported! */
		} else {
			break;
		}
	}
	fclose(f);
	return (0);
 ferr:
	fclose(f);
	return (-1);
}

#define MAX_ADDRESS_BYTES	sizeof(struct in6_addr)
#define MAX_ADDRESS_STRING	(4*8+1)
#define MAX_CIDR_STRING		(MAX_ADDRESS_STRING+4)

static size_t host_to_address(uint8_t *buf, size_t buf_len, const char *host, size_t len)
{
	char tmp[MAX_ADDRESS_STRING];

	if (len >= sizeof tmp) return 0;
	if (buf_len < sizeof(struct in6_addr)) return 0;

	/* Make zero terminated copy of the hostname */
	memcpy(tmp, host, len);
	tmp[len] = 0;

	if (inet_pton(AF_INET, tmp, (struct in_addr *) buf))
		return sizeof(struct in_addr);
	if (inet_pton(AF_INET6, tmp, (struct in6_addr *) buf))
		return sizeof(struct in6_addr);
	return 0;
}

static int bitcmp(const uint8_t *a, const uint8_t *b, int len)
{
	int bytes, bits, mask, r;

	bytes = len / 8;
	bits  = len % 8;
	if (bytes != 0) {
		r = memcmp(a, b, bytes);
		if (r != 0) return r;
	}
	if (bits != 0) {
		mask = (0xff << (8 - bits)) & 0xff;
		return ((int) (a[bytes] & mask)) - ((int) (b[bytes] & mask));
	}
	return 0;
}

static int cidr_match(const uint8_t *addr, size_t addr_len, const char *cidr, size_t cidr_len)
{
	const char *slash;
	uint8_t cidr_addr[MAX_ADDRESS_BYTES];
	size_t cidr_addrlen;
	long bits;

	if (!addr_len || cidr_len > MAX_CIDR_STRING) return 0;
	slash = memchr(cidr, '/', cidr_len);
	if (!slash) return 0;
	bits = strtol(slash + 1, NULL, 10);
	if (!bits || bits > 128) return 0;

	cidr_addrlen = host_to_address(cidr_addr, sizeof cidr_addr, cidr, slash - cidr);
	if (cidr_addrlen != addr_len || bits > addr_len*8) return 0;
	return bitcmp(cidr_addr, addr, bits) == 0;
}

/*
 * The no_proxy environment variable specifies a set of domains for
 * which the proxy should not be consulted; the contents is a comma-,
 * or space-separated list of domain names.  A single asterisk will
 * override all proxy variables and no transactions will be proxied
 * (for compatability with lynx and curl, see the discussion at
 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
 */
int
fetch_no_proxy_match(const char *host)
{
	const char *no_proxy, *p, *q;
	uint8_t addr[MAX_ADDRESS_BYTES];
	size_t h_len, d_len, addr_len;

	if ((no_proxy = getenv("NO_PROXY")) == NULL &&
	    (no_proxy = getenv("no_proxy")) == NULL)
		return (0);

	/* asterisk matches any hostname */
	if (strcmp(no_proxy, "*") == 0)
		return (1);

	h_len = strlen(host);
	addr_len = host_to_address(addr, sizeof addr, host, h_len);
	p = no_proxy;
	do {
		/* position p at the beginning of a domain suffix */
		while (*p == ',' || isspace((unsigned char)*p))
			p++;

		/* position q at the first separator character */
		for (q = p; *q; ++q)
			if (*q == ',' || isspace((unsigned char)*q))
				break;

		d_len = q - p;
		if (d_len > 0 && h_len >= d_len &&
		    strncasecmp(host + h_len - d_len,
			p, d_len) == 0) {
			/* domain name matches */
			return (1);
		}

		if (cidr_match(addr, addr_len, p, d_len)) {
			return (1);
		}

		p = q + 1;
	} while (*q);

	return (0);
}

struct fetchIO {
	void *io_cookie;
	ssize_t (*io_read)(void *, void *, size_t);
	ssize_t (*io_write)(void *, const void *, size_t);
	void (*io_close)(void *);
};

void
fetchIO_close(fetchIO *f)
{
	if (f->io_close != NULL)
		(*f->io_close)(f->io_cookie);

	free(f);
}

fetchIO *
fetchIO_unopen(void *io_cookie, ssize_t (*io_read)(void *, void *, size_t),
    ssize_t (*io_write)(void *, const void *, size_t),
    void (*io_close)(void *))
{
	fetchIO *f;

	f = malloc(sizeof(*f));
	if (f == NULL)
		return f;

	f->io_cookie = io_cookie;
	f->io_read = io_read;
	f->io_write = io_write;
	f->io_close = io_close;

	return f;
}

ssize_t
fetchIO_read(fetchIO *f, void *buf, size_t len)
{
	if (f->io_read == NULL)
		return EBADF;
	return (*f->io_read)(f->io_cookie, buf, len);
}

ssize_t
fetchIO_write(fetchIO *f, const void *buf, size_t len)
{
	if (f->io_read == NULL)
		return EBADF;
	return (*f->io_write)(f->io_cookie, buf, len);
}