Blame src/psl.c

Packit Service dcb6c2
/*
Packit Service dcb6c2
 * Copyright(c) 2014-2018 Tim Ruehsen
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Permission is hereby granted, free of charge, to any person obtaining a
Packit Service dcb6c2
 * copy of this software and associated documentation files (the "Software"),
Packit Service dcb6c2
 * to deal in the Software without restriction, including without limitation
Packit Service dcb6c2
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
Packit Service dcb6c2
 * and/or sell copies of the Software, and to permit persons to whom the
Packit Service dcb6c2
 * Software is furnished to do so, subject to the following conditions:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * The above copyright notice and this permission notice shall be included in
Packit Service dcb6c2
 * all copies or substantial portions of the Software.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service dcb6c2
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service dcb6c2
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit Service dcb6c2
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service dcb6c2
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Service dcb6c2
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Packit Service dcb6c2
 * DEALINGS IN THE SOFTWARE.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This file is part of libpsl.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Public Suffix List routines
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Changelog
Packit Service dcb6c2
 * 19.03.2014  Tim Ruehsen  created from libmget/cookie.c
Packit Service dcb6c2
 *
Packit Service dcb6c2
 */
Packit Service dcb6c2
Packit Service dcb6c2
#if HAVE_CONFIG_H
Packit Service dcb6c2
# include <config.h>
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
Packit Service dcb6c2
#       define _GCC_VERSION_AT_LEAST(major, minor) ((__GNUC__ > (major)) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
Packit Service dcb6c2
#else
Packit Service dcb6c2
#       define _GCC_VERSION_AT_LEAST(major, minor) 0
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#if _GCC_VERSION_AT_LEAST(2,95)
Packit Service dcb6c2
#  define _UNUSED __attribute__ ((unused))
Packit Service dcb6c2
#else
Packit Service dcb6c2
#  define _UNUSED
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#if ENABLE_NLS != 0
Packit Service dcb6c2
#	include <libintl.h>
Packit Service dcb6c2
#	define _(STRING) gettext(STRING)
Packit Service dcb6c2
#else
Packit Service dcb6c2
#	define _(STRING) STRING
Packit Service dcb6c2
#	define ngettext(STRING1,STRING2,N) STRING2
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#include <sys/types.h>
Packit Service dcb6c2
#include <sys/stat.h>
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef _WIN32
Packit Service dcb6c2
/* This is for Windows Vista and later, for inet_pton() */
Packit Service dcb6c2
# define _WIN32_WINNT 0x0600
Packit Service dcb6c2
Packit Service dcb6c2
# include <winsock2.h>
Packit Service dcb6c2
# include <ws2tcpip.h>
Packit Service dcb6c2
#else
Packit Service dcb6c2
# include <sys/socket.h>
Packit Service dcb6c2
# include <netinet/in.h>
Packit Service dcb6c2
# include <unistd.h>
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#include <stdio.h>
Packit Service dcb6c2
#include <stdlib.h>
Packit Service dcb6c2
#include <string.h>
Packit Service dcb6c2
#include <ctype.h>
Packit Service dcb6c2
#include <time.h>
Packit Service dcb6c2
#include <errno.h>
Packit Service dcb6c2
#include <limits.h> /* for UINT_MAX */
Packit Service dcb6c2
Packit Service dcb6c2
#ifndef _WIN32
Packit Service dcb6c2
# include <langinfo.h>
Packit Service dcb6c2
# include <arpa/inet.h>
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef HAVE_ALLOCA_H
Packit Service dcb6c2
#	include <alloca.h>
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef WITH_LIBICU
Packit Service dcb6c2
#	include <unicode/uversion.h>
Packit Service dcb6c2
#	include <unicode/ustring.h>
Packit Service dcb6c2
#	include <unicode/uidna.h>
Packit Service dcb6c2
#	include <unicode/ucnv.h>
Packit Service dcb6c2
#elif defined(WITH_LIBIDN2)
Packit Service dcb6c2
#	include <iconv.h>
Packit Service dcb6c2
#	include <idn2.h>
Packit Service dcb6c2
#	include <unicase.h>
Packit Service dcb6c2
#	include <unistr.h>
Packit Service dcb6c2
#elif defined(WITH_LIBIDN)
Packit Service dcb6c2
#	include <iconv.h>
Packit Service dcb6c2
#	include <stringprep.h>
Packit Service dcb6c2
#	include <idna.h>
Packit Service dcb6c2
#	include <unicase.h>
Packit Service dcb6c2
#	include <unistr.h>
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#ifndef WINICONV_CONST
Packit Service dcb6c2
#  define WINICONV_CONST
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
#include <libpsl.h>
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * SECTION:libpsl
Packit Service dcb6c2
 * @short_description: Public Suffix List library functions
Packit Service dcb6c2
 * @title: libpsl
Packit Service dcb6c2
 * @stability: Stable
Packit Service dcb6c2
 * @include: libpsl.h
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * [Public Suffix List](https://publicsuffix.org/) library functions.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 */
Packit Service dcb6c2
Packit Service dcb6c2
#define countof(a) (sizeof(a)/sizeof(*(a)))
Packit Service dcb6c2
Packit Service dcb6c2
#define _PSL_FLAG_EXCEPTION (1<<0)
Packit Service dcb6c2
#define _PSL_FLAG_WILDCARD  (1<<1)
Packit Service dcb6c2
#define _PSL_FLAG_ICANN     (1<<2) /* entry of ICANN section */
Packit Service dcb6c2
#define _PSL_FLAG_PRIVATE   (1<<3) /* entry of PRIVATE section */
Packit Service dcb6c2
#define _PSL_FLAG_PLAIN     (1<<4) /* just used for PSL syntax checking */
Packit Service dcb6c2
Packit Service dcb6c2
typedef struct {
Packit Service dcb6c2
	char
Packit Service dcb6c2
		label_buf[48];
Packit Service dcb6c2
	const char *
Packit Service dcb6c2
		label;
Packit Service dcb6c2
	unsigned short
Packit Service dcb6c2
		length;
Packit Service dcb6c2
	unsigned char
Packit Service dcb6c2
		nlabels, /* number of labels */
Packit Service dcb6c2
		flags;
Packit Service dcb6c2
} _psl_entry_t;
Packit Service dcb6c2
Packit Service dcb6c2
/* stripped down version libmget vector routines */
Packit Service dcb6c2
typedef struct {
Packit Service dcb6c2
	int
Packit Service dcb6c2
		(*cmp)(const _psl_entry_t **, const _psl_entry_t **); /* comparison function */
Packit Service dcb6c2
	_psl_entry_t
Packit Service dcb6c2
		**entry; /* pointer to array of pointers to elements */
Packit Service dcb6c2
	int
Packit Service dcb6c2
		max,     /* allocated elements */
Packit Service dcb6c2
		cur;     /* number of elements in use */
Packit Service dcb6c2
} _psl_vector_t;
Packit Service dcb6c2
Packit Service dcb6c2
struct _psl_ctx_st {
Packit Service dcb6c2
	_psl_vector_t
Packit Service dcb6c2
		*suffixes;
Packit Service dcb6c2
	unsigned char
Packit Service dcb6c2
		*dafsa;
Packit Service dcb6c2
	size_t
Packit Service dcb6c2
		dafsa_size;
Packit Service dcb6c2
	int
Packit Service dcb6c2
		nsuffixes,
Packit Service dcb6c2
		nexceptions,
Packit Service dcb6c2
		nwildcards;
Packit Service dcb6c2
	unsigned
Packit Service dcb6c2
		utf8 : 1; /* 1: data contains UTF-8 + punycode encoded rules */
Packit Service dcb6c2
};
Packit Service dcb6c2
Packit Service dcb6c2
/* include the PSL data generated by psl-make-dafsa */
Packit Service dcb6c2
#if defined(BUILTIN_GENERATOR_LIBICU) || defined(BUILTIN_GENERATOR_LIBIDN2) || defined(BUILTIN_GENERATOR_LIBIDN)
Packit Service dcb6c2
#include "suffixes_dafsa.c"
Packit Service dcb6c2
#else
Packit Service dcb6c2
static const unsigned char kDafsa[] = "";
Packit Service dcb6c2
static time_t _psl_file_time = 0;
Packit Service dcb6c2
static int _psl_nsuffixes = 0;
Packit Service dcb6c2
static int _psl_nexceptions = 0;
Packit Service dcb6c2
static int _psl_nwildcards = 0;
Packit Service dcb6c2
static const char _psl_sha1_checksum[] = "";
Packit Service dcb6c2
static const char _psl_filename[] = "";
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
/* references to these PSLs will result in lookups to built-in data */
Packit Service dcb6c2
static const psl_ctx_t
Packit Service dcb6c2
	_builtin_psl;
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef PSL_DISTFILE
Packit Service dcb6c2
static const char _psl_dist_filename[] = PSL_DISTFILE;
Packit Service dcb6c2
#else
Packit Service dcb6c2
static const char _psl_dist_filename[] = "";
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
static _psl_vector_t *_vector_alloc(int max, int (*cmp)(const _psl_entry_t **, const _psl_entry_t **))
Packit Service dcb6c2
{
Packit Service dcb6c2
	_psl_vector_t *v;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!(v = calloc(1, sizeof(_psl_vector_t))))
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!(v->entry = malloc(max * sizeof(_psl_entry_t *)))) {
Packit Service dcb6c2
		free(v);
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	v->max = max;
Packit Service dcb6c2
	v->cmp = cmp;
Packit Service dcb6c2
	return v;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static void _vector_free(_psl_vector_t **v)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (v && *v) {
Packit Service dcb6c2
		if ((*v)->entry) {
Packit Service dcb6c2
			int it;
Packit Service dcb6c2
Packit Service dcb6c2
			for (it = 0; it < (*v)->cur; it++)
Packit Service dcb6c2
				free((*v)->entry[it]);
Packit Service dcb6c2
Packit Service dcb6c2
			free((*v)->entry);
Packit Service dcb6c2
		}
Packit Service dcb6c2
		free(*v);
Packit Service dcb6c2
	}
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static _psl_entry_t *_vector_get(const _psl_vector_t *v, int pos)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (pos < 0 || !v || pos >= v->cur) return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	return v->entry[pos];
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* the entries must be sorted by */
Packit Service dcb6c2
static int _vector_find(const _psl_vector_t *v, const _psl_entry_t *elem)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (v) {
Packit Service dcb6c2
		int l, r, m;
Packit Service dcb6c2
		int res;
Packit Service dcb6c2
Packit Service dcb6c2
		/* binary search for element (exact match) */
Packit Service dcb6c2
		for (l = 0, r = v->cur - 1; l <= r;) {
Packit Service dcb6c2
			m = (l + r) / 2;
Packit Service dcb6c2
			if ((res = v->cmp(&elem, (const _psl_entry_t **)&(v->entry[m]))) > 0) l = m + 1;
Packit Service dcb6c2
			else if (res < 0) r = m - 1;
Packit Service dcb6c2
			else return m;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return -1; /* not found */
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _vector_add(_psl_vector_t *v, const _psl_entry_t *elem)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (v) {
Packit Service dcb6c2
		void *elemp;
Packit Service dcb6c2
Packit Service dcb6c2
		if (!(elemp = malloc(sizeof(_psl_entry_t))))
Packit Service dcb6c2
			return -1;
Packit Service dcb6c2
Packit Service dcb6c2
		memcpy(elemp, elem, sizeof(_psl_entry_t));
Packit Service dcb6c2
Packit Service dcb6c2
		if (v->max == v->cur) {
Packit Service dcb6c2
			void *m = realloc(v->entry, (v->max *= 2) * sizeof(_psl_entry_t *));
Packit Service dcb6c2
Packit Service dcb6c2
			if (m)
Packit Service dcb6c2
				v->entry = m;
Packit Service dcb6c2
			else {
Packit Service dcb6c2
				free(elemp);
Packit Service dcb6c2
				return -1;
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		v->entry[v->cur++] = elemp;
Packit Service dcb6c2
		return v->cur - 1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return -1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static void _vector_sort(_psl_vector_t *v)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (v && v->cmp)
Packit Service dcb6c2
		qsort(v->entry, v->cur, sizeof(_psl_vector_t **), (int(*)(const void *, const void *))v->cmp);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* by this kind of sorting, we can easily see if a domain matches or not */
Packit Service dcb6c2
static int _suffix_compare(const _psl_entry_t *s1, const _psl_entry_t *s2)
Packit Service dcb6c2
{
Packit Service dcb6c2
	int n;
Packit Service dcb6c2
Packit Service dcb6c2
	if ((n = s2->nlabels - s1->nlabels))
Packit Service dcb6c2
		return n; /* most labels first */
Packit Service dcb6c2
Packit Service dcb6c2
	if ((n = s1->length - s2->length))
Packit Service dcb6c2
		return n;  /* shorter rules first */
Packit Service dcb6c2
Packit Service dcb6c2
	return strcmp(s1->label ? s1->label : s1->label_buf, s2->label ? s2->label : s2->label_buf);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* needed to sort array of pointers, given to qsort() */
Packit Service dcb6c2
static int _suffix_compare_array(const _psl_entry_t **s1, const _psl_entry_t **s2)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return _suffix_compare(*s1, *s2);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _suffix_init(_psl_entry_t *suffix, const char *rule, size_t length)
Packit Service dcb6c2
{
Packit Service dcb6c2
	const char *src;
Packit Service dcb6c2
	char *dst;
Packit Service dcb6c2
Packit Service dcb6c2
	suffix->label = suffix->label_buf;
Packit Service dcb6c2
Packit Service dcb6c2
	if (length >= sizeof(suffix->label_buf) - 1) {
Packit Service dcb6c2
		suffix->nlabels = 0;
Packit Service dcb6c2
		/* fprintf(stderr, _("Suffix rule too long (%zd, ignored): %s\n"), length, rule); */
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	suffix->length = (unsigned char)length;
Packit Service dcb6c2
Packit Service dcb6c2
	suffix->nlabels = 1;
Packit Service dcb6c2
Packit Service dcb6c2
	for (dst = suffix->label_buf, src = rule; *src;) {
Packit Service dcb6c2
		if (*src == '.')
Packit Service dcb6c2
			suffix->nlabels++;
Packit Service dcb6c2
		*dst++ = *src++;
Packit Service dcb6c2
	}
Packit Service dcb6c2
	*dst = 0;
Packit Service dcb6c2
Packit Service dcb6c2
	return 0;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
#if !defined(WITH_LIBIDN) && !defined(WITH_LIBIDN2) && !defined(WITH_LIBICU)
Packit Service dcb6c2
/*
Packit Service dcb6c2
 * When configured without runtime IDNA support (./configure --disable-runtime), we need a pure ASCII
Packit Service dcb6c2
 * representation of non-ASCII characters in labels as found in UTF-8 domain names.
Packit Service dcb6c2
 * This is because the current DAFSA format used may only hold character values [21..127].
Packit Service dcb6c2
 *
Packit Service dcb6c2
  Code copied from http://www.nicemice.net/idn/punycode-spec.gz on
Packit Service dcb6c2
  2011-01-04 with SHA-1 a966a8017f6be579d74a50a226accc7607c40133
Packit Service dcb6c2
  labeled punycode-spec 1.0.3 (2006-Mar-24-Thu).  It is modified for
Packit Service dcb6c2
  libpsl by Tim Rühsen.  License on the original code:
Packit Service dcb6c2
Packit Service dcb6c2
  punycode-spec 1.0.3 (2006-Mar-23-Thu)
Packit Service dcb6c2
  http://www.nicemice.net/idn/
Packit Service dcb6c2
  Adam M. Costello
Packit Service dcb6c2
  http://www.nicemice.net/amc/
Packit Service dcb6c2
Packit Service dcb6c2
  B. Disclaimer and license
Packit Service dcb6c2
Packit Service dcb6c2
    Regarding this entire document or any portion of it (including
Packit Service dcb6c2
    the pseudocode and C code), the author makes no guarantees and
Packit Service dcb6c2
    is not responsible for any damage resulting from its use.  The
Packit Service dcb6c2
    author grants irrevocable permission to anyone to use, modify,
Packit Service dcb6c2
    and distribute it in any way that does not diminish the rights
Packit Service dcb6c2
    of anyone else to use, modify, and distribute it, provided that
Packit Service dcb6c2
    redistributed derivative works do not contain misleading author or
Packit Service dcb6c2
    version information.  Derivative works need not be licensed under
Packit Service dcb6c2
    similar terms.
Packit Service dcb6c2
Packit Service dcb6c2
  C. Punycode sample implementation
Packit Service dcb6c2
Packit Service dcb6c2
  punycode-sample.c 2.0.0 (2004-Mar-21-Sun)
Packit Service dcb6c2
  http://www.nicemice.net/idn/
Packit Service dcb6c2
  Adam M. Costello
Packit Service dcb6c2
  http://www.nicemice.net/amc/
Packit Service dcb6c2
Packit Service dcb6c2
  This is ANSI C code (C89) implementing Punycode 1.0.x.
Packit Service dcb6c2
 */
Packit Service dcb6c2
enum punycode_status {
Packit Service dcb6c2
	punycode_success = 0,
Packit Service dcb6c2
	punycode_bad_input = 1, /* Input is invalid.                       */
Packit Service dcb6c2
	punycode_big_output = 2, /* Output would exceed the space provided. */
Packit Service dcb6c2
	punycode_overflow = 3 /* Wider integers needed to process input. */
Packit Service dcb6c2
};
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef PUNYCODE_UINT
Packit Service dcb6c2
	typedef PUNYCODE_UINT punycode_uint;
Packit Service dcb6c2
#elif UINT_MAX >= (1 << 26) - 1
Packit Service dcb6c2
	typedef unsigned int punycode_uint;
Packit Service dcb6c2
#else
Packit Service dcb6c2
	typedef unsigned long punycode_uint;
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
/*** Bootstring parameters for Punycode ***/
Packit Service dcb6c2
enum {
Packit Service dcb6c2
	base = 36, tmin = 1, tmax = 26, skew = 38, damp = 700,
Packit Service dcb6c2
	initial_bias = 72, initial_n = 0x80, delimiter = 0x2D
Packit Service dcb6c2
};
Packit Service dcb6c2
Packit Service dcb6c2
static char encode_digit(punycode_uint d)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return d + 22 + 75 * (d < 26);
Packit Service dcb6c2
	/*  0..25 map to ASCII a..z or A..Z */
Packit Service dcb6c2
	/* 26..35 map to ASCII 0..9         */
Packit Service dcb6c2
}
Packit Service dcb6c2
#define flagged(bcp) ((punycode_uint)(bcp) - 65 < 26)
Packit Service dcb6c2
static const punycode_uint maxint = -1;
Packit Service dcb6c2
Packit Service dcb6c2
static punycode_uint adapt(punycode_uint delta, punycode_uint numpoints, int firsttime)
Packit Service dcb6c2
{
Packit Service dcb6c2
	punycode_uint k;
Packit Service dcb6c2
Packit Service dcb6c2
	delta = firsttime ? delta / damp : delta >> 1;
Packit Service dcb6c2
	/* delta >> 1 is a faster way of doing delta / 2 */
Packit Service dcb6c2
	delta += delta / numpoints;
Packit Service dcb6c2
Packit Service dcb6c2
	for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) {
Packit Service dcb6c2
		delta /= base - tmin;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return k + (base - tmin + 1) * delta / (delta + skew);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static enum punycode_status punycode_encode(
Packit Service dcb6c2
	size_t input_length_orig,
Packit Service dcb6c2
	const punycode_uint input[],
Packit Service dcb6c2
	size_t *output_length,
Packit Service dcb6c2
	char output[])
Packit Service dcb6c2
{
Packit Service dcb6c2
	punycode_uint input_length, n, delta, h, b, bias, j, m, q, k, t;
Packit Service dcb6c2
	size_t out, max_out;
Packit Service dcb6c2
Packit Service dcb6c2
	/* The Punycode spec assumes that the input length is the same type */
Packit Service dcb6c2
	/* of integer as a code point, so we need to convert the size_t to  */
Packit Service dcb6c2
	/* a punycode_uint, which could overflow.                           */
Packit Service dcb6c2
Packit Service dcb6c2
	if (input_length_orig > maxint)
Packit Service dcb6c2
		return punycode_overflow;
Packit Service dcb6c2
Packit Service dcb6c2
	input_length = (punycode_uint) input_length_orig;
Packit Service dcb6c2
Packit Service dcb6c2
	/* Initialize the state: */
Packit Service dcb6c2
Packit Service dcb6c2
	n = initial_n;
Packit Service dcb6c2
	delta = 0;
Packit Service dcb6c2
	out = 0;
Packit Service dcb6c2
	max_out = *output_length;
Packit Service dcb6c2
	bias = initial_bias;
Packit Service dcb6c2
Packit Service dcb6c2
	/* Handle the basic code points: */
Packit Service dcb6c2
	for (j = 0; j < input_length; ++j) {
Packit Service dcb6c2
		if (input[j] < 0x80) {
Packit Service dcb6c2
			if (max_out - out < 2)
Packit Service dcb6c2
				return punycode_big_output;
Packit Service dcb6c2
			output[out++] = (char) input[j];
Packit Service dcb6c2
		}
Packit Service dcb6c2
		/* else if (input[j] < n) return punycode_bad_input; */
Packit Service dcb6c2
		/* (not needed for Punycode with unsigned code points) */
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	h = b = (punycode_uint) out;
Packit Service dcb6c2
	/* cannot overflow because out <= input_length <= maxint */
Packit Service dcb6c2
Packit Service dcb6c2
	/* h is the number of code points that have been handled, b is the  */
Packit Service dcb6c2
	/* number of basic code points, and out is the number of ASCII code */
Packit Service dcb6c2
	/* points that have been output.                                    */
Packit Service dcb6c2
Packit Service dcb6c2
	if (b > 0)
Packit Service dcb6c2
		output[out++] = delimiter;
Packit Service dcb6c2
Packit Service dcb6c2
	/* Main encoding loop: */
Packit Service dcb6c2
Packit Service dcb6c2
	while (h < input_length) {
Packit Service dcb6c2
		/* All non-basic code points < n have been     */
Packit Service dcb6c2
		/* handled already.  Find the next larger one: */
Packit Service dcb6c2
Packit Service dcb6c2
		for (m = maxint, j = 0; j < input_length; ++j) {
Packit Service dcb6c2
			/* if (basic(input[j])) continue; */
Packit Service dcb6c2
			/* (not needed for Punycode) */
Packit Service dcb6c2
			if (input[j] >= n && input[j] < m)
Packit Service dcb6c2
				m = input[j];
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		/* Increase delta enough to advance the decoder's    */
Packit Service dcb6c2
		/* <n,i> state to <m,0>, but guard against overflow: */
Packit Service dcb6c2
Packit Service dcb6c2
		if (m - n > (maxint - delta) / (h + 1))
Packit Service dcb6c2
			return punycode_overflow;
Packit Service dcb6c2
		delta += (m - n) * (h + 1);
Packit Service dcb6c2
		n = m;
Packit Service dcb6c2
Packit Service dcb6c2
		for (j = 0; j < input_length; ++j) {
Packit Service dcb6c2
			/* Punycode does not need to check whether input[j] is basic: */
Packit Service dcb6c2
			if (input[j] < n /* || basic(input[j]) */) {
Packit Service dcb6c2
				if (++delta == 0)
Packit Service dcb6c2
					return punycode_overflow;
Packit Service dcb6c2
			}
Packit Service dcb6c2
Packit Service dcb6c2
			if (input[j] == n) {
Packit Service dcb6c2
				/* Represent delta as a generalized variable-length integer: */
Packit Service dcb6c2
Packit Service dcb6c2
				for (q = delta, k = base;; k += base) {
Packit Service dcb6c2
					if (out >= max_out)
Packit Service dcb6c2
						return punycode_big_output;
Packit Service dcb6c2
					t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
Packit Service dcb6c2
						k >= bias + tmax ? tmax : k - bias;
Packit Service dcb6c2
					if (q < t)
Packit Service dcb6c2
						break;
Packit Service dcb6c2
					output[out++] = encode_digit(t + (q - t) % (base - t));
Packit Service dcb6c2
					q = (q - t) / (base - t);
Packit Service dcb6c2
				}
Packit Service dcb6c2
Packit Service dcb6c2
				output[out++] = encode_digit(q);
Packit Service dcb6c2
				bias = adapt(delta, h + 1, h == b);
Packit Service dcb6c2
				delta = 0;
Packit Service dcb6c2
				++h;
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		++delta, ++n;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	*output_length = out;
Packit Service dcb6c2
	return punycode_success;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static ssize_t _utf8_to_utf32(const char *in, size_t inlen, punycode_uint *out, size_t outlen)
Packit Service dcb6c2
{
Packit Service dcb6c2
	size_t n = 0;
Packit Service dcb6c2
	const unsigned char *s = (void *)in;
Packit Service dcb6c2
	const unsigned char *e = (void *)(in + inlen);
Packit Service dcb6c2
Packit Service dcb6c2
	if (!outlen)
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
Packit Service dcb6c2
	outlen--;
Packit Service dcb6c2
Packit Service dcb6c2
	while (n < outlen) {
Packit Service dcb6c2
		size_t inleft = e - s;
Packit Service dcb6c2
Packit Service dcb6c2
		if (inleft >= 1 && (*s & 0x80) == 0) { /* 0xxxxxxx ASCII char */
Packit Service dcb6c2
			out[n++] = *s;
Packit Service dcb6c2
			s++;
Packit Service dcb6c2
		} else if (inleft >= 2 && (*s & 0xE0) == 0xC0) /* 110xxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80)
Packit Service dcb6c2
				return -1;
Packit Service dcb6c2
			out[n++] = ((*s & 0x1F) << 6) | (s[1] & 0x3F);
Packit Service dcb6c2
			s += 2;
Packit Service dcb6c2
		} else if (inleft >= 3 && (*s & 0xF0) == 0xE0) /* 1110xxxx 10xxxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80)
Packit Service dcb6c2
				return -1;
Packit Service dcb6c2
			out[n++] = ((*s & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
Packit Service dcb6c2
			s += 3;
Packit Service dcb6c2
		} else if (inleft >= 4 && (*s & 0xF8) == 0xF0) /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80 || (s[3] & 0xC0) != 0x80)
Packit Service dcb6c2
				return -1;
Packit Service dcb6c2
			out[n++] = ((*s & 0x07) << 18) | ((s[1] & 0x3F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
Packit Service dcb6c2
			s += 4;
Packit Service dcb6c2
		} else if (!inleft) {
Packit Service dcb6c2
			break;
Packit Service dcb6c2
		} else
Packit Service dcb6c2
			return -1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return n;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _mem_is_ascii(const char *s, size_t n)
Packit Service dcb6c2
{
Packit Service dcb6c2
	for (; n; n--) /* 'while(n--)' generates unsigned integer overflow on n = 0 */
Packit Service dcb6c2
		if (*((unsigned char *)s++) >= 128)
Packit Service dcb6c2
			return 0;
Packit Service dcb6c2
Packit Service dcb6c2
	return 1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _domain_to_punycode(const char *domain, char *out, size_t outsize)
Packit Service dcb6c2
{
Packit Service dcb6c2
	size_t outlen = 0, labellen;
Packit Service dcb6c2
	punycode_uint input[256];
Packit Service dcb6c2
	const char *label, *e;
Packit Service dcb6c2
Packit Service dcb6c2
	for (e = label = domain; e; label = e + 1) {
Packit Service dcb6c2
		e = strchr(label, '.');
Packit Service dcb6c2
		labellen = e ? (size_t) (e - label) : strlen(label);
Packit Service dcb6c2
		/* printf("s=%s inlen=%zd\n", label, labellen); */
Packit Service dcb6c2
Packit Service dcb6c2
		if (_mem_is_ascii(label, labellen)) {
Packit Service dcb6c2
			if (outlen + labellen + (e != NULL) >= outsize)
Packit Service dcb6c2
				return 1;
Packit Service dcb6c2
Packit Service dcb6c2
			/* printf("outlen=%zd labellen=%zd\n", outlen, labellen); */
Packit Service dcb6c2
			memcpy(out + outlen, label, labellen);
Packit Service dcb6c2
			outlen += labellen;
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			ssize_t inputlen = 0;
Packit Service dcb6c2
Packit Service dcb6c2
			if (outlen + labellen + (e != NULL) + 4 >= outsize)
Packit Service dcb6c2
				return 1;
Packit Service dcb6c2
Packit Service dcb6c2
			if ((inputlen = _utf8_to_utf32(label, labellen, input, countof(input))) < 0)
Packit Service dcb6c2
				return 1;
Packit Service dcb6c2
Packit Service dcb6c2
			memcpy(out + outlen, "xn--", 4);
Packit Service dcb6c2
			outlen += 4;
Packit Service dcb6c2
Packit Service dcb6c2
			labellen = outsize - outlen;
Packit Service dcb6c2
			/* printf("n=%zd space_left=%zd\n", n, labellen); */
Packit Service dcb6c2
			if (punycode_encode(inputlen, input, &labellen, out + outlen))
Packit Service dcb6c2
				return 1;
Packit Service dcb6c2
			outlen += labellen;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		if (e)
Packit Service dcb6c2
			out[outlen++] = '.';
Packit Service dcb6c2
		out[outlen] = 0;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return 0;
Packit Service dcb6c2
}
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
static int _isspace_ascii(const char c)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _str_is_ascii(const char *s)
Packit Service dcb6c2
{
Packit Service dcb6c2
	while (*s && *((unsigned char *)s) < 128) s++;
Packit Service dcb6c2
Packit Service dcb6c2
	return !*s;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
#if defined(WITH_LIBIDN)
Packit Service dcb6c2
/*
Packit Service dcb6c2
 * Work around a libidn <= 1.30 vulnerability.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * The function checks for a valid UTF-8 character sequence before
Packit Service dcb6c2
 * passing it to idna_to_ascii_8z().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * [1] https://lists.gnu.org/archive/html/help-libidn/2015-05/msg00002.html
Packit Service dcb6c2
 * [2] https://lists.gnu.org/archive/html/bug-wget/2015-06/msg00002.html
Packit Service dcb6c2
 * [3] https://curl.haxx.se/mail/lib-2015-06/0143.html
Packit Service dcb6c2
 */
Packit Service dcb6c2
static int _utf8_is_valid(const char *utf8)
Packit Service dcb6c2
{
Packit Service dcb6c2
	const unsigned char *s = (const unsigned char *) utf8;
Packit Service dcb6c2
Packit Service dcb6c2
	while (*s) {
Packit Service dcb6c2
		if ((*s & 0x80) == 0) /* 0xxxxxxx ASCII char */
Packit Service dcb6c2
			s++;
Packit Service dcb6c2
		else if ((*s & 0xE0) == 0xC0) /* 110xxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80)
Packit Service dcb6c2
				return 0;
Packit Service dcb6c2
			s += 2;
Packit Service dcb6c2
		} else if ((*s & 0xF0) == 0xE0) /* 1110xxxx 10xxxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80)
Packit Service dcb6c2
				return 0;
Packit Service dcb6c2
			s += 3;
Packit Service dcb6c2
		} else if ((*s & 0xF8) == 0xF0) /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ {
Packit Service dcb6c2
			if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80 || (s[3] & 0xC0) != 0x80)
Packit Service dcb6c2
				return 0;
Packit Service dcb6c2
			s += 4;
Packit Service dcb6c2
		} else
Packit Service dcb6c2
			return 0;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return 1;
Packit Service dcb6c2
}
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
typedef void *_psl_idna_t;
Packit Service dcb6c2
Packit Service dcb6c2
static _psl_idna_t *_psl_idna_open(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
#if defined(WITH_LIBICU)
Packit Service dcb6c2
	UErrorCode status = 0;
Packit Service dcb6c2
	return (void *)uidna_openUTS46(UIDNA_USE_STD3_RULES | UIDNA_NONTRANSITIONAL_TO_ASCII, &status);
Packit Service dcb6c2
#endif
Packit Service dcb6c2
	return NULL;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static void _psl_idna_close(_psl_idna_t *idna _UNUSED)
Packit Service dcb6c2
{
Packit Service dcb6c2
#if defined(WITH_LIBICU)
Packit Service dcb6c2
	if (idna)
Packit Service dcb6c2
		uidna_close((UIDNA *)idna);
Packit Service dcb6c2
#endif
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static int _psl_idna_toASCII(_psl_idna_t *idna _UNUSED, const char *utf8, char **ascii)
Packit Service dcb6c2
{
Packit Service dcb6c2
	int ret = -1;
Packit Service dcb6c2
Packit Service dcb6c2
#if defined(WITH_LIBICU)
Packit Service dcb6c2
	/* IDNA2008 UTS#46 punycode conversion */
Packit Service dcb6c2
	if (idna) {
Packit Service dcb6c2
		char lookupname_buf[128] = "", *lookupname = lookupname_buf;
Packit Service dcb6c2
		UErrorCode status = 0;
Packit Service dcb6c2
		UIDNAInfo info = UIDNA_INFO_INITIALIZER;
Packit Service dcb6c2
		UChar utf16_dst[128], utf16_src_buf[128];
Packit Service dcb6c2
		UChar *utf16_src = utf16_src_buf;
Packit Service dcb6c2
		int32_t utf16_src_length, bytes_written;
Packit Service dcb6c2
		int32_t utf16_dst_length;
Packit Service dcb6c2
Packit Service dcb6c2
		u_strFromUTF8(utf16_src, countof(utf16_src_buf), &utf16_src_length, utf8, -1, &status);
Packit Service dcb6c2
		if (!U_SUCCESS(status)) goto cleanup; /* UTF-8 to UTF-16 conversion failed */
Packit Service dcb6c2
Packit Service dcb6c2
		if (utf16_src_length >= (int) countof(utf16_src_buf)) {
Packit Service dcb6c2
			utf16_src = malloc((utf16_src_length + 1) * sizeof(UChar));
Packit Service dcb6c2
			if (!utf16_src) goto cleanup;
Packit Service dcb6c2
Packit Service dcb6c2
			u_strFromUTF8(utf16_src, utf16_src_length, NULL, utf8, -1, &status);
Packit Service dcb6c2
			if (!U_SUCCESS(status)) goto cleanup; /* UTF-8 to UTF-16 conversion failed */
Packit Service dcb6c2
Packit Service dcb6c2
			utf16_src[utf16_src_length] = 0; /* u_strFromUTF8() doesn't 0-terminate if dest is filled up */
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		utf16_dst_length = uidna_nameToASCII((UIDNA *)idna, utf16_src, utf16_src_length, utf16_dst, countof(utf16_dst), &info, &status);
Packit Service dcb6c2
		if (!U_SUCCESS(status)) goto cleanup; /* to ASCII conversion failed */
Packit Service dcb6c2
Packit Service dcb6c2
		u_strToUTF8(lookupname, sizeof(lookupname_buf), &bytes_written, utf16_dst, utf16_dst_length, &status);
Packit Service dcb6c2
		if (!U_SUCCESS(status)) goto cleanup; /* UTF-16 to UTF-8 conversion failed */
Packit Service dcb6c2
Packit Service dcb6c2
		if (bytes_written >= (int) sizeof(lookupname_buf)) {
Packit Service dcb6c2
			lookupname = malloc(bytes_written + 1);
Packit Service dcb6c2
			if (!lookupname) goto cleanup;
Packit Service dcb6c2
Packit Service dcb6c2
			u_strToUTF8(lookupname, bytes_written, NULL, utf16_dst, utf16_dst_length, &status);
Packit Service dcb6c2
			if (!U_SUCCESS(status)) goto cleanup; /* UTF-16 to UTF-8 conversion failed */
Packit Service dcb6c2
Packit Service dcb6c2
			lookupname[bytes_written] = 0; /* u_strToUTF8() doesn't 0-terminate if dest is filled up */
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			if (!(lookupname = strdup(lookupname)))
Packit Service dcb6c2
				goto cleanup;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		if (ascii) {
Packit Service dcb6c2
			*ascii = lookupname;
Packit Service dcb6c2
			lookupname = NULL;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		ret = 0;
Packit Service dcb6c2
Packit Service dcb6c2
cleanup:
Packit Service dcb6c2
		if (lookupname != lookupname_buf)
Packit Service dcb6c2
			free(lookupname);
Packit Service dcb6c2
		if (utf16_src != utf16_src_buf)
Packit Service dcb6c2
			free(utf16_src);
Packit Service dcb6c2
	}
Packit Service dcb6c2
#elif defined(WITH_LIBIDN2)
Packit Service dcb6c2
#if IDN2_VERSION_NUMBER >= 0x00140000
Packit Service dcb6c2
	int rc;
Packit Service dcb6c2
Packit Service dcb6c2
	/* IDN2_TRANSITIONAL automatically converts to lowercase
Packit Service dcb6c2
	 * IDN2_NFC_INPUT converts to NFC before toASCII conversion
Packit Service dcb6c2
	 * Since IDN2_TRANSITIONAL implicitly does NFC conversion, we don't need
Packit Service dcb6c2
	 * the additional IDN2_NFC_INPUT. But just for the unlikely case that the linked
Packit Service dcb6c2
	 * library is not matching the headers when building and it doesn't support TR46,
Packit Service dcb6c2
	 * we provide IDN2_NFC_INPUT. */
Packit Service dcb6c2
Packit Service dcb6c2
	if ((rc = idn2_lookup_u8((uint8_t *)utf8, (uint8_t **)ascii, IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL)) == IDN2_OK)
Packit Service dcb6c2
		ret = 0;
Packit Service dcb6c2
	/* else
Packit Service dcb6c2
		fprintf(stderr, "toASCII(%s) failed (%d): %s\n", lower, rc, idn2_strerror(rc)); */
Packit Service dcb6c2
#else
Packit Service dcb6c2
	int rc;
Packit Service dcb6c2
	uint8_t *lower;
Packit Service dcb6c2
	size_t len = u8_strlen((uint8_t *)utf8) + 1;
Packit Service dcb6c2
Packit Service dcb6c2
	/* we need a conversion to lowercase */
Packit Service dcb6c2
	if (!(lower = u8_tolower((uint8_t *)utf8, len, 0, UNINORM_NFKC, NULL, &len))) {
Packit Service dcb6c2
		/* fprintf(stderr, "u8_tolower(%s) failed (%d)\n", utf8, errno); */
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	if ((rc = idn2_lookup_u8(lower, (uint8_t **)ascii, 0)) == IDN2_OK) {
Packit Service dcb6c2
		ret = 0;
Packit Service dcb6c2
	} /* else
Packit Service dcb6c2
		fprintf(stderr, "toASCII(%s) failed (%d): %s\n", lower, rc, idn2_strerror(rc)); */
Packit Service dcb6c2
Packit Service dcb6c2
	free(lower);
Packit Service dcb6c2
#endif
Packit Service dcb6c2
#elif defined(WITH_LIBIDN)
Packit Service dcb6c2
	int rc;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!_utf8_is_valid(utf8)) {
Packit Service dcb6c2
		/* fprintf(_(stderr, "Invalid UTF-8 sequence not converted: '%s'\n"), utf8); */
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	/* idna_to_ascii_8z() automatically converts UTF-8 to lowercase */
Packit Service dcb6c2
Packit Service dcb6c2
	if ((rc = idna_to_ascii_8z(utf8, ascii, IDNA_USE_STD3_ASCII_RULES)) == IDNA_SUCCESS) {
Packit Service dcb6c2
		ret = 0;
Packit Service dcb6c2
	} /* else
Packit Service dcb6c2
		fprintf(_(stderr, "toASCII failed (%d): %s\n"), rc, idna_strerror(rc)); */
Packit Service dcb6c2
#else
Packit Service dcb6c2
	char lookupname[128];
Packit Service dcb6c2
Packit Service dcb6c2
	if (_domain_to_punycode(utf8, lookupname, sizeof(lookupname)) == 0) {
Packit Service dcb6c2
		if (ascii)
Packit Service dcb6c2
			if ((*ascii = strdup(lookupname)))
Packit Service dcb6c2
				ret = 0;
Packit Service dcb6c2
	}
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
	return ret;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
static void _add_punycode_if_needed(_psl_idna_t *idna, _psl_vector_t *v, _psl_entry_t *e)
Packit Service dcb6c2
{
Packit Service dcb6c2
	char *lookupname;
Packit Service dcb6c2
Packit Service dcb6c2
	if (_str_is_ascii(e->label_buf))
Packit Service dcb6c2
		return;
Packit Service dcb6c2
Packit Service dcb6c2
	if (_psl_idna_toASCII(idna, e->label_buf, &lookupname) == 0) {
Packit Service dcb6c2
		if (strcmp(e->label_buf, lookupname)) {
Packit Service dcb6c2
			_psl_entry_t suffix, *suffixp;
Packit Service dcb6c2
Packit Service dcb6c2
			/* fprintf(stderr, "toASCII '%s' -> '%s'\n", e->label_buf, lookupname); */
Packit Service dcb6c2
			if (_suffix_init(&suffix, lookupname, strlen(lookupname)) == 0) {
Packit Service dcb6c2
				suffix.flags = e->flags;
Packit Service dcb6c2
				if ((suffixp = _vector_get(v, _vector_add(v, &suffix))))
Packit Service dcb6c2
					suffixp->label = suffixp->label_buf; /* set label to changed address */
Packit Service dcb6c2
			}
Packit Service dcb6c2
		} /* else ignore */
Packit Service dcb6c2
Packit Service dcb6c2
		free(lookupname);
Packit Service dcb6c2
	}
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* prototypes */
Packit Service dcb6c2
int LookupStringInFixedSet(const unsigned char* graph, size_t length, const char* key, size_t key_length);
Packit Service dcb6c2
int GetUtfMode(const unsigned char *graph, size_t length);
Packit Service dcb6c2
Packit Service dcb6c2
static int _psl_is_public_suffix(const psl_ctx_t *psl, const char *domain, int type)
Packit Service dcb6c2
{
Packit Service dcb6c2
	_psl_entry_t suffix;
Packit Service dcb6c2
	const char *p;
Packit Service dcb6c2
	char *punycode = NULL;
Packit Service dcb6c2
	int need_conversion = 0;
Packit Service dcb6c2
Packit Service dcb6c2
	/* this function should be called without leading dots, just make sure */
Packit Service dcb6c2
	if (*domain == '.')
Packit Service dcb6c2
		domain++;
Packit Service dcb6c2
Packit Service dcb6c2
	suffix.nlabels = 1;
Packit Service dcb6c2
Packit Service dcb6c2
	for (p = domain; *p; p++) {
Packit Service dcb6c2
		if (*p == '.')
Packit Service dcb6c2
			suffix.nlabels++;
Packit Service dcb6c2
		else if (*((unsigned char *)p) >= 128)
Packit Service dcb6c2
			need_conversion = 1; /* in case domain is non-ascii we need a toASCII conversion */
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	if (suffix.nlabels == 1) {
Packit Service dcb6c2
		/* TLD, this is the prevailing '*' match. If type excludes the '*' rule, continue.
Packit Service dcb6c2
		 */
Packit Service dcb6c2
		if (!(type & PSL_TYPE_NO_STAR_RULE))
Packit Service dcb6c2
			return 1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	type &= ~PSL_TYPE_NO_STAR_RULE;
Packit Service dcb6c2
Packit Service dcb6c2
	if (psl->utf8 || psl == &_builtin_psl)
Packit Service dcb6c2
		need_conversion = 0;
Packit Service dcb6c2
Packit Service dcb6c2
#if defined(WITH_LIBIDN) || defined(WITH_LIBIDN2) || defined(WITH_LIBICU)
Packit Service dcb6c2
	if (psl == &_builtin_psl)
Packit Service dcb6c2
		need_conversion = 0;
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
	if (need_conversion) {
Packit Service dcb6c2
		_psl_idna_t *idna = _psl_idna_open();
Packit Service dcb6c2
Packit Service dcb6c2
		if (_psl_idna_toASCII(idna, domain, &punycode) == 0) {
Packit Service dcb6c2
			suffix.label = punycode;
Packit Service dcb6c2
			suffix.length = strlen(punycode);
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			/* fallback */
Packit Service dcb6c2
Packit Service dcb6c2
			suffix.label = domain;
Packit Service dcb6c2
			suffix.length = p - suffix.label;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		_psl_idna_close(idna);
Packit Service dcb6c2
	} else {
Packit Service dcb6c2
		suffix.label = domain;
Packit Service dcb6c2
		suffix.length = p - suffix.label;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	if (psl == &_builtin_psl || psl->dafsa) {
Packit Service dcb6c2
		size_t dafsa_size = psl == &_builtin_psl ? sizeof(kDafsa) : psl->dafsa_size;
Packit Service dcb6c2
		const unsigned char *dafsa = psl == &_builtin_psl ? kDafsa : psl->dafsa;
Packit Service dcb6c2
		int rc = LookupStringInFixedSet(dafsa, dafsa_size, suffix.label, suffix.length);
Packit Service dcb6c2
		if (rc != -1) {
Packit Service dcb6c2
			/* check for correct rule type */
Packit Service dcb6c2
			if (type == PSL_TYPE_ICANN && !(rc & _PSL_FLAG_ICANN))
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
			else if (type == PSL_TYPE_PRIVATE && !(rc & _PSL_FLAG_PRIVATE))
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
			if (rc & _PSL_FLAG_EXCEPTION)
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
			/* wildcard *.foo.bar implicitly make foo.bar a public suffix */
Packit Service dcb6c2
			/* definitely a match, no matter if the found rule is a wildcard or not */
Packit Service dcb6c2
			goto suffix_yes;
Packit Service dcb6c2
		}
Packit Service dcb6c2
		if ((suffix.label = strchr(suffix.label, '.'))) {
Packit Service dcb6c2
			suffix.label++;
Packit Service dcb6c2
			suffix.length = strlen(suffix.label);
Packit Service dcb6c2
			suffix.nlabels--;
Packit Service dcb6c2
Packit Service dcb6c2
			rc = LookupStringInFixedSet(dafsa, dafsa_size, suffix.label, suffix.length);
Packit Service dcb6c2
			if (rc != -1) {
Packit Service dcb6c2
				/* check for correct rule type */
Packit Service dcb6c2
				if (type == PSL_TYPE_ICANN && !(rc & _PSL_FLAG_ICANN))
Packit Service dcb6c2
					goto suffix_no;
Packit Service dcb6c2
				else if (type == PSL_TYPE_PRIVATE && !(rc & _PSL_FLAG_PRIVATE))
Packit Service dcb6c2
					goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
				if (rc & _PSL_FLAG_WILDCARD)
Packit Service dcb6c2
					goto suffix_yes;
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
	} else {
Packit Service dcb6c2
		_psl_entry_t *rule = _vector_get(psl->suffixes, 0);
Packit Service dcb6c2
Packit Service dcb6c2
		if (!rule || rule->nlabels < suffix.nlabels - 1)
Packit Service dcb6c2
			goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
		rule = _vector_get(psl->suffixes, _vector_find(psl->suffixes, &suffix));
Packit Service dcb6c2
Packit Service dcb6c2
		if (rule) {
Packit Service dcb6c2
			/* check for correct rule type */
Packit Service dcb6c2
			if (type == PSL_TYPE_ICANN && !(rule->flags & _PSL_FLAG_ICANN))
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
			else if (type == PSL_TYPE_PRIVATE && !(rule->flags & _PSL_FLAG_PRIVATE))
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
			if (rule->flags & _PSL_FLAG_EXCEPTION)
Packit Service dcb6c2
				goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
			/* wildcard *.foo.bar implicitly make foo.bar a public suffix */
Packit Service dcb6c2
			/* definitely a match, no matter if the found rule is a wildcard or not */
Packit Service dcb6c2
			goto suffix_yes;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		if ((suffix.label = strchr(suffix.label, '.'))) {
Packit Service dcb6c2
			int pos;
Packit Service dcb6c2
Packit Service dcb6c2
			suffix.label++;
Packit Service dcb6c2
			suffix.length = strlen(suffix.label);
Packit Service dcb6c2
			suffix.nlabels--;
Packit Service dcb6c2
Packit Service dcb6c2
			rule = _vector_get(psl->suffixes, (pos = _vector_find(psl->suffixes, &suffix)));
Packit Service dcb6c2
Packit Service dcb6c2
			if (rule) {
Packit Service dcb6c2
				/* check for correct rule type */
Packit Service dcb6c2
				if (type == PSL_TYPE_ICANN && !(rule->flags & _PSL_FLAG_ICANN))
Packit Service dcb6c2
					goto suffix_no;
Packit Service dcb6c2
				else if (type == PSL_TYPE_PRIVATE && !(rule->flags & _PSL_FLAG_PRIVATE))
Packit Service dcb6c2
					goto suffix_no;
Packit Service dcb6c2
Packit Service dcb6c2
				if (rule->flags & _PSL_FLAG_WILDCARD)
Packit Service dcb6c2
					goto suffix_yes;
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
suffix_no:
Packit Service dcb6c2
	if (punycode)
Packit Service dcb6c2
		free(punycode);
Packit Service dcb6c2
	return 0;
Packit Service dcb6c2
Packit Service dcb6c2
suffix_yes:
Packit Service dcb6c2
	if (punycode)
Packit Service dcb6c2
		free(punycode);
Packit Service dcb6c2
	return 1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_is_public_suffix:
Packit Service dcb6c2
 * @psl: PSL context
Packit Service dcb6c2
 * @domain: Domain string
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function checks if @domain is a public suffix by the means of the
Packit Service dcb6c2
 * [Mozilla Public Suffix List](https://publicsuffix.org).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * For cookie domain checking see psl_is_cookie_domain_acceptable().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * International @domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode).
Packit Service dcb6c2
 * Other encodings likely result in incorrect return values.
Packit Service dcb6c2
 * Use helper function psl_str_to_utf8lower() for normalization @domain.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @psl is a context returned by either psl_load_file(), psl_load_fp() or
Packit Service dcb6c2
 * psl_builtin().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: 1 if domain is a public suffix, 0 if not.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_is_public_suffix(const psl_ctx_t *psl, const char *domain)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (!psl || !domain)
Packit Service dcb6c2
		return 1;
Packit Service dcb6c2
Packit Service dcb6c2
	return _psl_is_public_suffix(psl, domain, PSL_TYPE_ANY);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_is_public_suffix2:
Packit Service dcb6c2
 * @psl: PSL context
Packit Service dcb6c2
 * @domain: Domain string
Packit Service dcb6c2
 * @type: Domain type
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function checks if @domain is a public suffix by the means of the
Packit Service dcb6c2
 * [Mozilla Public Suffix List](https://publicsuffix.org).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @type specifies the PSL section where to perform the lookup. Valid values are
Packit Service dcb6c2
 * %PSL_TYPE_PRIVATE, %PSL_TYPE_ICANN, %PSL_TYPE_NO_STAR_RULE, and %PSL_TYPE_ANY.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * %PSL_TYPE_NO_STAR_RULE switches of the 'prevailing star rule' (see
Packit Service dcb6c2
 * [List](https://publicsuffix.org/list) under 'Algorithm' 2.).
Packit Service dcb6c2
 * Applying the flag means that TLDs not explicitly listed in the PSL are *not* treated as public suffixes.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * International @domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode).
Packit Service dcb6c2
 * Other encodings likely result in incorrect return values.
Packit Service dcb6c2
 * Use helper function psl_str_to_utf8lower() for normalization @domain.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @psl is a context returned by either psl_load_file(), psl_load_fp() or
Packit Service dcb6c2
 * psl_builtin().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: 1 if domain is a public suffix, 0 if not.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_is_public_suffix2(const psl_ctx_t *psl, const char *domain, int type)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (!psl || !domain)
Packit Service dcb6c2
		return 1;
Packit Service dcb6c2
Packit Service dcb6c2
	return _psl_is_public_suffix(psl, domain, type);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_unregistrable_domain:
Packit Service dcb6c2
 * @psl: PSL context
Packit Service dcb6c2
 * @domain: Domain string
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function finds the longest public suffix part of @domain by the means
Packit Service dcb6c2
 * of the [Mozilla Public Suffix List](https://publicsuffix.org).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * International @domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode).
Packit Service dcb6c2
 * Other encodings likely result in incorrect return values.
Packit Service dcb6c2
 * Use helper function psl_str_to_utf8lower() for normalization @domain.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @psl is a context returned by either psl_load_file(), psl_load_fp() or
Packit Service dcb6c2
 * psl_builtin().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to longest public suffix part of @domain or %NULL if @domain
Packit Service dcb6c2
 * does not contain a public suffix (or if @psl is %NULL).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
const char *psl_unregistrable_domain(const psl_ctx_t *psl, const char *domain)
Packit Service dcb6c2
{
Packit Service dcb6c2
	int nlabels = 0;
Packit Service dcb6c2
	const char *p;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!psl || !domain)
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	/*
Packit Service dcb6c2
	 * In the main loop we introduce a O(N^2) behavior to avoid code duplication.
Packit Service dcb6c2
	 * To avoid nasty CPU hogging, we limit the lookup to max. 8 domain labels to the right.
Packit Service dcb6c2
	 */
Packit Service dcb6c2
	for (p = domain + strlen(domain) - 1; p >= domain; p--) {
Packit Service dcb6c2
		if (*p == '.' && ++nlabels > 8) {
Packit Service dcb6c2
			domain = p + 1;
Packit Service dcb6c2
			break;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	/*
Packit Service dcb6c2
	 *  We check from left to right to catch special PSL entries like 'forgot.his.name':
Packit Service dcb6c2
	 *   'forgot.his.name' and 'name' are in the PSL while 'his.name' is not.
Packit Service dcb6c2
	 */
Packit Service dcb6c2
Packit Service dcb6c2
	while (!_psl_is_public_suffix(psl, domain, 0)) {
Packit Service dcb6c2
		if ((domain = strchr(domain, '.')))
Packit Service dcb6c2
			domain++;
Packit Service dcb6c2
		else
Packit Service dcb6c2
			break; /* prevent endless loop if psl_is_public_suffix() is broken. */
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return domain;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_registrable_domain:
Packit Service dcb6c2
 * @psl: PSL context
Packit Service dcb6c2
 * @domain: Domain string
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function finds the shortest private suffix part of @domain by the means
Packit Service dcb6c2
 * of the [Mozilla Public Suffix List](https://publicsuffix.org).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * International @domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode).
Packit Service dcb6c2
 * Other encodings likely result in incorrect return values.
Packit Service dcb6c2
 * Use helper function psl_str_to_utf8lower() for normalization @domain.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @psl is a context returned by either psl_load_file(), psl_load_fp() or
Packit Service dcb6c2
 * psl_builtin().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to shortest private suffix part of @domain or %NULL if @domain
Packit Service dcb6c2
 * does not contain a private suffix (or if @psl is %NULL).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
const char *psl_registrable_domain(const psl_ctx_t *psl, const char *domain)
Packit Service dcb6c2
{
Packit Service dcb6c2
	const char *p, *regdom = NULL;
Packit Service dcb6c2
	int nlabels = 0;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!psl || !domain || *domain == '.')
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	/*
Packit Service dcb6c2
	 * In the main loop we introduce a O(N^2) behavior to avoid code duplication.
Packit Service dcb6c2
	 * To avoid nasty CPU hogging, we limit the lookup to max. 8 domain labels to the right.
Packit Service dcb6c2
	 */
Packit Service dcb6c2
	for (p = domain + strlen(domain) - 1; p >= domain; p--) {
Packit Service dcb6c2
		if (*p == '.' && ++nlabels > 8) {
Packit Service dcb6c2
			domain = p + 1;
Packit Service dcb6c2
			break;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	/*
Packit Service dcb6c2
	 *  We check from left to right to catch special PSL entries like 'forgot.his.name':
Packit Service dcb6c2
	 *   'forgot.his.name' and 'name' are in the PSL while 'his.name' is not.
Packit Service dcb6c2
	 */
Packit Service dcb6c2
Packit Service dcb6c2
	while (!_psl_is_public_suffix(psl, domain, 0)) {
Packit Service dcb6c2
		if ((p = strchr(domain, '.'))) {
Packit Service dcb6c2
			regdom = domain;
Packit Service dcb6c2
			domain = p + 1;
Packit Service dcb6c2
		} else
Packit Service dcb6c2
			break; /* prevent endless loop if psl_is_public_suffix() is broken. */
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return regdom;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_load_file:
Packit Service dcb6c2
 * @fname: Name of PSL file
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function loads the public suffixes file named @fname.
Packit Service dcb6c2
 * To free the allocated resources, call psl_free().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * The suffixes are expected to be UTF-8 encoded (lowercase + NFKC) if they are international.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to a PSL context or %NULL on failure.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
psl_ctx_t *psl_load_file(const char *fname)
Packit Service dcb6c2
{
Packit Service dcb6c2
	FILE *fp;
Packit Service dcb6c2
	psl_ctx_t *psl = NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!fname)
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	if ((fp = fopen(fname, "r"))) {
Packit Service dcb6c2
		psl = psl_load_fp(fp);
Packit Service dcb6c2
		fclose(fp);
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return psl;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_load_fp:
Packit Service dcb6c2
 * @fp: FILE pointer
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function loads the public suffixes from a FILE pointer.
Packit Service dcb6c2
 * To free the allocated resources, call psl_free().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * The suffixes are expected to be UTF-8 encoded (lowercase + NFKC) if they are international.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to a PSL context or %NULL on failure.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
psl_ctx_t *psl_load_fp(FILE *fp)
Packit Service dcb6c2
{
Packit Service dcb6c2
	psl_ctx_t *psl;
Packit Service dcb6c2
	_psl_entry_t suffix, *suffixp;
Packit Service dcb6c2
	char buf[256], *linep, *p;
Packit Service dcb6c2
	int type = 0, is_dafsa;
Packit Service dcb6c2
	_psl_idna_t *idna;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!fp)
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!(psl = calloc(1, sizeof(psl_ctx_t))))
Packit Service dcb6c2
		return NULL;
Packit Service dcb6c2
Packit Service dcb6c2
	/* read first line to allow ASCII / DAFSA detection */
Packit Service dcb6c2
	if (!(linep = fgets(buf, sizeof(buf) - 1, fp)))
Packit Service dcb6c2
		goto fail;
Packit Service dcb6c2
Packit Service dcb6c2
	is_dafsa = strlen(buf) == 16 && !strncmp(buf, ".DAFSA@PSL_", 11);
Packit Service dcb6c2
Packit Service dcb6c2
	if (is_dafsa) {
Packit Service dcb6c2
		void *m;
Packit Service dcb6c2
		size_t size = 65536, n, len = 0;
Packit Service dcb6c2
		int version = atoi(buf + 11);
Packit Service dcb6c2
Packit Service dcb6c2
		if (version != 0)
Packit Service dcb6c2
			goto fail;
Packit Service dcb6c2
Packit Service dcb6c2
		if (!(psl->dafsa = malloc(size)))
Packit Service dcb6c2
			goto fail;
Packit Service dcb6c2
Packit Service dcb6c2
		memcpy(psl->dafsa, buf, len);
Packit Service dcb6c2
Packit Service dcb6c2
		while ((n = fread(psl->dafsa + len, 1, size - len, fp)) > 0) {
Packit Service dcb6c2
			len += n;
Packit Service dcb6c2
			if (len >= size) {
Packit Service dcb6c2
				if (!(m = realloc(psl->dafsa, size *= 2)))
Packit Service dcb6c2
					goto fail;
Packit Service dcb6c2
				psl->dafsa = m;
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		/* release unused memory */
Packit Service dcb6c2
		if ((m = realloc(psl->dafsa, len)))
Packit Service dcb6c2
			psl->dafsa = m;
Packit Service dcb6c2
		else if (!len)
Packit Service dcb6c2
			psl->dafsa = NULL; /* realloc() just free'd psl->dafsa */
Packit Service dcb6c2
Packit Service dcb6c2
		psl->dafsa_size = len;
Packit Service dcb6c2
		psl->utf8 = !!GetUtfMode(psl->dafsa, len);
Packit Service dcb6c2
Packit Service dcb6c2
		return psl;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	idna = _psl_idna_open();
Packit Service dcb6c2
Packit Service dcb6c2
	/*
Packit Service dcb6c2
	 *  as of 02.11.2012, the list at https://publicsuffix.org/list/ contains ~6000 rules and 40 exceptions.
Packit Service dcb6c2
	 *  as of 19.02.2014, the list at https://publicsuffix.org/list/ contains ~6500 rules and 19 exceptions.
Packit Service dcb6c2
	 */
Packit Service dcb6c2
	psl->suffixes = _vector_alloc(8*1024, _suffix_compare_array);
Packit Service dcb6c2
	psl->utf8 = 1; /* we put UTF-8 and punycode rules in the lookup vector */
Packit Service dcb6c2
Packit Service dcb6c2
	do {
Packit Service dcb6c2
		while (_isspace_ascii(*linep)) linep++; /* ignore leading whitespace */
Packit Service dcb6c2
		if (!*linep) continue; /* skip empty lines */
Packit Service dcb6c2
Packit Service dcb6c2
		if (*linep == '/' && linep[1] == '/') {
Packit Service dcb6c2
			if (!type) {
Packit Service dcb6c2
				if (strstr(linep + 2, "===BEGIN ICANN DOMAINS==="))
Packit Service dcb6c2
					type = _PSL_FLAG_ICANN;
Packit Service dcb6c2
				else if (!type && strstr(linep + 2, "===BEGIN PRIVATE DOMAINS==="))
Packit Service dcb6c2
					type = _PSL_FLAG_PRIVATE;
Packit Service dcb6c2
			}
Packit Service dcb6c2
			else if (type == _PSL_FLAG_ICANN && strstr(linep + 2, "===END ICANN DOMAINS==="))
Packit Service dcb6c2
				type = 0;
Packit Service dcb6c2
			else if (type == _PSL_FLAG_PRIVATE && strstr(linep + 2, "===END PRIVATE DOMAINS==="))
Packit Service dcb6c2
				type = 0;
Packit Service dcb6c2
Packit Service dcb6c2
			continue; /* skip comments */
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		/* parse suffix rule */
Packit Service dcb6c2
		for (p = linep; *linep && !_isspace_ascii(*linep);) linep++;
Packit Service dcb6c2
		*linep = 0;
Packit Service dcb6c2
Packit Service dcb6c2
		if (*p == '!') {
Packit Service dcb6c2
			p++;
Packit Service dcb6c2
			suffix.flags = _PSL_FLAG_EXCEPTION | type;
Packit Service dcb6c2
			psl->nexceptions++;
Packit Service dcb6c2
		} else if (*p == '*') {
Packit Service dcb6c2
			if (*++p != '.') {
Packit Service dcb6c2
				/* fprintf(stderr, _("Unsupported kind of rule (ignored): %s\n"), p - 1); */
Packit Service dcb6c2
				continue;
Packit Service dcb6c2
			}
Packit Service dcb6c2
			p++;
Packit Service dcb6c2
			/* wildcard *.foo.bar implicitly make foo.bar a public suffix */
Packit Service dcb6c2
			suffix.flags = _PSL_FLAG_WILDCARD | _PSL_FLAG_PLAIN | type;
Packit Service dcb6c2
			psl->nwildcards++;
Packit Service dcb6c2
			psl->nsuffixes++;
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			suffix.flags = _PSL_FLAG_PLAIN | type;
Packit Service dcb6c2
			psl->nsuffixes++;
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		if (_suffix_init(&suffix, p, linep - p) == 0) {
Packit Service dcb6c2
			int index;
Packit Service dcb6c2
Packit Service dcb6c2
			if ((index = _vector_find(psl->suffixes, &suffix)) >= 0) {
Packit Service dcb6c2
				/* Found existing entry:
Packit Service dcb6c2
				 * Combination of exception and plain rule is ambiguous
Packit Service dcb6c2
				 * !foo.bar
Packit Service dcb6c2
				 * foo.bar
Packit Service dcb6c2
				 *
Packit Service dcb6c2
				 * Allowed:
Packit Service dcb6c2
				 * !foo.bar + *.foo.bar
Packit Service dcb6c2
				 * foo.bar + *.foo.bar
Packit Service dcb6c2
				 *
Packit Service dcb6c2
				 * We do not check here, let's do it later.
Packit Service dcb6c2
				 */
Packit Service dcb6c2
Packit Service dcb6c2
				suffixp = _vector_get(psl->suffixes, index);
Packit Service dcb6c2
				suffixp->flags |= suffix.flags;
Packit Service dcb6c2
			} else {
Packit Service dcb6c2
				/* New entry */
Packit Service dcb6c2
				suffixp = _vector_get(psl->suffixes, _vector_add(psl->suffixes, &suffix));
Packit Service dcb6c2
			}
Packit Service dcb6c2
Packit Service dcb6c2
			if (suffixp) {
Packit Service dcb6c2
				suffixp->label = suffixp->label_buf; /* set label to changed address */
Packit Service dcb6c2
				_add_punycode_if_needed(idna, psl->suffixes, suffixp);
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
	} while ((linep = fgets(buf, sizeof(buf), fp)));
Packit Service dcb6c2
Packit Service dcb6c2
	_vector_sort(psl->suffixes);
Packit Service dcb6c2
Packit Service dcb6c2
	_psl_idna_close(idna);
Packit Service dcb6c2
Packit Service dcb6c2
	return psl;
Packit Service dcb6c2
Packit Service dcb6c2
fail:
Packit Service dcb6c2
	psl_free(psl);
Packit Service dcb6c2
	return NULL;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_free:
Packit Service dcb6c2
 * @psl: PSL context pointer
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function frees the the PSL context that has been retrieved via
Packit Service dcb6c2
 * psl_load_fp() or psl_load_file().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
void psl_free(psl_ctx_t *psl)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (psl && psl != &_builtin_psl) {
Packit Service dcb6c2
		_vector_free(&psl->suffixes);
Packit Service dcb6c2
		free(psl->dafsa);
Packit Service dcb6c2
		free(psl);
Packit Service dcb6c2
	}
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_builtin:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns the PSL context that has been generated and built in at compile-time.
Packit Service dcb6c2
 * You don't have to free the returned context explicitly.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * The builtin data also contains punycode entries, one for each international domain name.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the generation of built-in data has been disabled during compilation, %NULL will be returned.
Packit Service dcb6c2
 * When using the builtin psl context, you can provide UTF-8 (lowercase + NFKC) or ASCII/ACE (punycode)
Packit Service dcb6c2
 * representations of domains to functions like psl_is_public_suffix().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to the built in PSL data or NULL if this data is not available.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
const psl_ctx_t *psl_builtin(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
#if defined(BUILTIN_GENERATOR_LIBICU) || defined(BUILTIN_GENERATOR_LIBIDN2) || defined(BUILTIN_GENERATOR_LIBIDN)
Packit Service dcb6c2
	return &_builtin_psl;
Packit Service dcb6c2
#else
Packit Service dcb6c2
	return NULL;
Packit Service dcb6c2
#endif
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_suffix_count:
Packit Service dcb6c2
 * @psl: PSL context pointer
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns number of public suffixes maintained by @psl.
Packit Service dcb6c2
 * The number of exceptions within the Public Suffix List are not included.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the information is not available, the return value is -1 (since 0.19).
Packit Service dcb6c2
 * This is the case with DAFSA blobs or if @psl is NULL.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Number of public suffixes entries in PSL context or -1 if this information is not available.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_suffix_count(const psl_ctx_t *psl)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (psl == &_builtin_psl)
Packit Service dcb6c2
		return _psl_nsuffixes;
Packit Service dcb6c2
	else if (psl)
Packit Service dcb6c2
		return psl->dafsa ? -1 : psl->nsuffixes;
Packit Service dcb6c2
	else
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_suffix_exception_count:
Packit Service dcb6c2
 * @psl: PSL context pointer
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns number of public suffix exceptions maintained by @psl.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the information is not available, the return value is -1 (since 0.19).
Packit Service dcb6c2
 * This is the case with DAFSA blobs or if @psl is NULL.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Number of public suffix exceptions in PSL context or -1 if this information is not available.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_suffix_exception_count(const psl_ctx_t *psl)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (psl == &_builtin_psl)
Packit Service dcb6c2
		return _psl_nexceptions;
Packit Service dcb6c2
	else if (psl)
Packit Service dcb6c2
		return psl->dafsa ? -1 : psl->nexceptions;
Packit Service dcb6c2
	else
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_suffix_wildcard_count:
Packit Service dcb6c2
 * @psl: PSL context pointer
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns number of public suffix wildcards maintained by @psl.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the information is not available, the return value is -1 (since 0.19).
Packit Service dcb6c2
 * This is the case with DAFSA blobs or if @psl is NULL.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Number of public suffix wildcards in PSL context or -1 if this information is not available.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.10.0
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_suffix_wildcard_count(const psl_ctx_t *psl)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (psl == &_builtin_psl)
Packit Service dcb6c2
		return _psl_nwildcards;
Packit Service dcb6c2
	else if (psl)
Packit Service dcb6c2
		return psl->dafsa ? -1 : psl->nwildcards;
Packit Service dcb6c2
	else
Packit Service dcb6c2
		return -1;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_builtin_file_time:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns the mtime of the Public Suffix List file that has been built in.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the generation of built-in data has been disabled during compilation, 0 will be returned.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: time_t value or 0.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
time_t psl_builtin_file_time(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return _psl_file_time;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_builtin_sha1sum:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns the SHA1 checksum of the Public Suffix List file that has been built in.
Packit Service dcb6c2
 * The returned string is in lowercase hex encoding, e.g. "2af1e9e3044eda0678bb05949d7cca2f769901d8".
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the generation of built-in data has been disabled during compilation, an empty string will be returned.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: String containing SHA1 checksum or an empty string.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
const char *psl_builtin_sha1sum(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return _psl_sha1_checksum;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_builtin_filename:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns the file name of the Public Suffix List file that has been built in.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the generation of built-in data has been disabled during compilation, an empty string will be returned.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: String containing the PSL file name or an empty string.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
const char *psl_builtin_filename(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return _psl_filename;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_builtin_outdated:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function checks if the built-in data is older than the file it has been created from.
Packit Service dcb6c2
 * If it is, it might be a good idea for the application to reload the PSL.
Packit Service dcb6c2
 * The mtime is taken as reference.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If the PSL file does not exist, it is assumed that the built-in data is not outdated.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: 1 if the built-in is outdated, 0 otherwise.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.10.0
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_builtin_outdated(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
	struct stat st;
Packit Service dcb6c2
Packit Service dcb6c2
	if (stat(_psl_filename, &st) == 0 && st.st_mtime > _psl_file_time)
Packit Service dcb6c2
		return 1;
Packit Service dcb6c2
Packit Service dcb6c2
	return 0;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_dist_filename:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function returns the file name of the distribution/system PSL data file.
Packit Service dcb6c2
 * This file will be considered by psl_latest().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Return the filename that is set by ./configure --with-psl-distfile, or an empty string.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: String containing a PSL file name or an empty string.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.16
Packit Service dcb6c2
 */
Packit Service dcb6c2
const char *psl_dist_filename(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
	return _psl_dist_filename;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_get_version:
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Get libpsl version.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: String containing version of libpsl.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.2.5
Packit Service dcb6c2
 **/
Packit Service dcb6c2
const char *psl_get_version(void)
Packit Service dcb6c2
{
Packit Service dcb6c2
#ifdef WITH_LIBICU
Packit Service dcb6c2
	return PACKAGE_VERSION " (+libicu/" U_ICU_VERSION ")";
Packit Service dcb6c2
#elif defined(WITH_LIBIDN2)
Packit Service dcb6c2
	return PACKAGE_VERSION " (+libidn2/" IDN2_VERSION ")";
Packit Service dcb6c2
#elif defined(WITH_LIBIDN)
Packit Service dcb6c2
	return PACKAGE_VERSION " (+libidn/" STRINGPREP_VERSION ")";
Packit Service dcb6c2
#else
Packit Service dcb6c2
	return PACKAGE_VERSION " (no IDNA support)";
Packit Service dcb6c2
#endif
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_check_version_number:
Packit Service dcb6c2
 * @version: Version number (hex) to check against.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Check the given version number is at minimum the current library version number.
Packit Service dcb6c2
 * The version number must be a hexadecimal number like 0x000a01 (V0.10.1).
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Returns the library version number if the given version number is at least
Packit Service dcb6c2
 * the version of the library, else return 0; If the argument is 0, the function returns
Packit Service dcb6c2
 * the library version number without performing a check.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.11.0
Packit Service dcb6c2
 **/
Packit Service dcb6c2
int psl_check_version_number(int version)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (version) {
Packit Service dcb6c2
		int major = version >> 16;
Packit Service dcb6c2
		int minor = (version >> 8) & 0xFF;
Packit Service dcb6c2
		int patch = version & 0xFF;
Packit Service dcb6c2
Packit Service dcb6c2
		if (major < PSL_VERSION_MAJOR
Packit Service dcb6c2
			|| (major == PSL_VERSION_MAJOR && minor < PSL_VERSION_MINOR)
Packit Service dcb6c2
			|| (major == PSL_VERSION_MAJOR && minor == PSL_VERSION_MINOR && patch < PSL_VERSION_PATCH))
Packit Service dcb6c2
		{
Packit Service dcb6c2
			return 0;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return PSL_VERSION_NUMBER;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* return whether hostname is an IP address or not */
Packit Service dcb6c2
static int _isip(const char *hostname)
Packit Service dcb6c2
{
Packit Service dcb6c2
	struct in_addr addr;
Packit Service dcb6c2
	struct in6_addr addr6;
Packit Service dcb6c2
Packit Service dcb6c2
	return inet_pton(AF_INET, hostname, &addr) || inet_pton(AF_INET6, hostname, &addr6);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_is_cookie_domain_acceptable:
Packit Service dcb6c2
 * @psl: PSL context pointer
Packit Service dcb6c2
 * @hostname: The request hostname.
Packit Service dcb6c2
 * @cookie_domain: The domain value from a cookie
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This helper function checks whether @cookie_domain is an acceptable cookie domain value for the request
Packit Service dcb6c2
 * @hostname.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * For international domain names both, @hostname and @cookie_domain, have to be either in UTF-8 (lowercase + NFKC)
Packit Service dcb6c2
 * or in ASCII/ACE (punycode) format. Other encodings or mixing UTF-8 and punycode likely result in incorrect return values.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Use helper function psl_str_to_utf8lower() for normalization of @hostname and @cookie_domain.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Examples:
Packit Service dcb6c2
 * 1. Cookie domain 'example.com' would be acceptable for hostname 'www.example.com',
Packit Service dcb6c2
 * but '.com' or 'com' would NOT be acceptable since 'com' is a public suffix.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * 2. Cookie domain 'his.name' would be acceptable for hostname 'remember.his.name',
Packit Service dcb6c2
 *  but NOT for 'forgot.his.name' since 'forgot.his.name' is a public suffix.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: 1 if acceptable, 0 if not acceptable.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.1
Packit Service dcb6c2
 */
Packit Service dcb6c2
int psl_is_cookie_domain_acceptable(const psl_ctx_t *psl, const char *hostname, const char *cookie_domain)
Packit Service dcb6c2
{
Packit Service dcb6c2
	const char *p;
Packit Service dcb6c2
	size_t hostname_length, cookie_domain_length;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!psl || !hostname || !cookie_domain)
Packit Service dcb6c2
		return 0;
Packit Service dcb6c2
Packit Service dcb6c2
	while (*cookie_domain == '.')
Packit Service dcb6c2
		cookie_domain++;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!strcmp(hostname, cookie_domain))
Packit Service dcb6c2
		return 1; /* an exact match is acceptable (and pretty common) */
Packit Service dcb6c2
Packit Service dcb6c2
	if (_isip(hostname))
Packit Service dcb6c2
		return 0; /* Hostname is an IP address and these must match fully (RFC 6265, 5.1.3) */
Packit Service dcb6c2
Packit Service dcb6c2
	cookie_domain_length = strlen(cookie_domain);
Packit Service dcb6c2
	hostname_length = strlen(hostname);
Packit Service dcb6c2
Packit Service dcb6c2
	if (cookie_domain_length >= hostname_length)
Packit Service dcb6c2
		return 0; /* cookie_domain is too long */
Packit Service dcb6c2
Packit Service dcb6c2
	p = hostname + hostname_length - cookie_domain_length;
Packit Service dcb6c2
	if (!strcmp(p, cookie_domain) && p[-1] == '.') {
Packit Service dcb6c2
		/* OK, cookie_domain matches, but it must be longer than the longest public suffix in 'hostname' */
Packit Service dcb6c2
Packit Service dcb6c2
		if (!(p = psl_unregistrable_domain(psl, hostname)))
Packit Service dcb6c2
			return 1;
Packit Service dcb6c2
Packit Service dcb6c2
		if (cookie_domain_length > strlen(p))
Packit Service dcb6c2
			return 1;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return 0;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_free_string:
Packit Service dcb6c2
 * @str: pointer to lowercase string returned by psl_str_to_utf8lower()
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function free()'s the memory allocated by psl_str_to_utf8lower() when
Packit Service dcb6c2
 * returning a lowercase string
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.19
Packit Service dcb6c2
 */
Packit Service dcb6c2
void psl_free_string(char *str)
Packit Service dcb6c2
{
Packit Service dcb6c2
	if (str)
Packit Service dcb6c2
		free(str);
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_str_to_utf8lower:
Packit Service dcb6c2
 * @str: string to convert
Packit Service dcb6c2
 * @encoding: charset encoding of @str, e.g. 'iso-8859-1' or %NULL
Packit Service dcb6c2
 * @locale: locale of @str for to lowercase conversion, e.g. 'de' or %NULL
Packit Service dcb6c2
 * @lower: return value containing the converted string
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This helper function converts a string to UTF-8 lowercase + NFKC representation.
Packit Service dcb6c2
 * Lowercase + NFKC UTF-8 is needed as input to the domain checking functions.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * @lower stays unchanged on error.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * When returning PSL_SUCCESS, the return value 'lower' must be freed after usage.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: psl_error_t value.
Packit Service dcb6c2
 *   PSL_SUCCESS: Success
Packit Service dcb6c2
 *   PSL_ERR_INVALID_ARG: @str is a %NULL value.
Packit Service dcb6c2
 *   PSL_ERR_CONVERTER: Failed to open the unicode converter with name @encoding
Packit Service dcb6c2
 *   PSL_ERR_TO_UTF16: Failed to convert @str to unicode
Packit Service dcb6c2
 *   PSL_ERR_TO_LOWER: Failed to convert unicode to lowercase
Packit Service dcb6c2
 *   PSL_ERR_TO_UTF8: Failed to convert unicode to UTF-8
Packit Service dcb6c2
 *   PSL_ERR_NO_MEM: Failed to allocate memory
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.4
Packit Service dcb6c2
 */
Packit Service dcb6c2
psl_error_t psl_str_to_utf8lower(const char *str, const char *encoding _UNUSED, const char *locale _UNUSED, char **lower)
Packit Service dcb6c2
{
Packit Service dcb6c2
	int ret = PSL_ERR_INVALID_ARG;
Packit Service dcb6c2
Packit Service dcb6c2
	if (!str)
Packit Service dcb6c2
		return PSL_ERR_INVALID_ARG;
Packit Service dcb6c2
Packit Service dcb6c2
	/* shortcut to avoid costly conversion */
Packit Service dcb6c2
	if (_str_is_ascii(str)) {
Packit Service dcb6c2
		if (lower) {
Packit Service dcb6c2
			char *p, *tmp;
Packit Service dcb6c2
Packit Service dcb6c2
			if (!(tmp = strdup(str)))
Packit Service dcb6c2
				return PSL_ERR_NO_MEM;
Packit Service dcb6c2
Packit Service dcb6c2
			*lower = tmp;
Packit Service dcb6c2
Packit Service dcb6c2
			/* convert ASCII string to lowercase */
Packit Service dcb6c2
			for (p = *lower; *p; p++)
Packit Service dcb6c2
				if (isupper(*p))
Packit Service dcb6c2
					*p = tolower(*p);
Packit Service dcb6c2
		}
Packit Service dcb6c2
		return PSL_SUCCESS;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
#ifdef WITH_LIBICU
Packit Service dcb6c2
	do {
Packit Service dcb6c2
	size_t str_length = strlen(str);
Packit Service dcb6c2
	UErrorCode status = 0;
Packit Service dcb6c2
	UChar *utf16_dst, *utf16_lower;
Packit Service dcb6c2
	int32_t utf16_dst_length;
Packit Service dcb6c2
	char *utf8_lower;
Packit Service dcb6c2
	UConverter *uconv;
Packit Service dcb6c2
Packit Service dcb6c2
	if (str_length < 256) {
Packit Service dcb6c2
		/* C89 allocation */
Packit Service dcb6c2
		utf16_dst   = alloca(sizeof(UChar) * (str_length * 2 + 1));
Packit Service dcb6c2
		utf16_lower = alloca(sizeof(UChar) * (str_length * 2 + 1));
Packit Service dcb6c2
		utf8_lower  = alloca(str_length * 6 + 1);
Packit Service dcb6c2
	} else {
Packit Service dcb6c2
		utf16_dst   = malloc(sizeof(UChar) * (str_length * 2 + 1));
Packit Service dcb6c2
		utf16_lower = malloc(sizeof(UChar) * (str_length * 2 + 1));
Packit Service dcb6c2
		utf8_lower  = malloc(str_length * 6 + 1);
Packit Service dcb6c2
Packit Service dcb6c2
		if (!utf16_dst || !utf16_lower || !utf8_lower) {
Packit Service dcb6c2
			ret = PSL_ERR_NO_MEM;
Packit Service dcb6c2
			goto out;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	uconv = ucnv_open(encoding, &status);
Packit Service dcb6c2
	if (U_SUCCESS(status)) {
Packit Service dcb6c2
		utf16_dst_length = ucnv_toUChars(uconv, utf16_dst, str_length * 2 + 1, str, str_length, &status);
Packit Service dcb6c2
		ucnv_close(uconv);
Packit Service dcb6c2
Packit Service dcb6c2
		if (U_SUCCESS(status)) {
Packit Service dcb6c2
			int32_t utf16_lower_length = u_strToLower(utf16_lower, str_length * 2 + 1, utf16_dst, utf16_dst_length, locale, &status);
Packit Service dcb6c2
			if (U_SUCCESS(status)) {
Packit Service dcb6c2
				u_strToUTF8(utf8_lower, str_length * 6 + 1, NULL, utf16_lower, utf16_lower_length, &status);
Packit Service dcb6c2
				if (U_SUCCESS(status)) {
Packit Service dcb6c2
					ret = PSL_SUCCESS;
Packit Service dcb6c2
					if (lower) {
Packit Service dcb6c2
						char *tmp = strdup(utf8_lower);
Packit Service dcb6c2
Packit Service dcb6c2
						if (tmp)
Packit Service dcb6c2
							*lower = tmp;
Packit Service dcb6c2
						else
Packit Service dcb6c2
							ret = PSL_ERR_NO_MEM;
Packit Service dcb6c2
					}
Packit Service dcb6c2
				} else {
Packit Service dcb6c2
					ret = PSL_ERR_TO_UTF8;
Packit Service dcb6c2
					/* fprintf(stderr, "Failed to convert UTF-16 to UTF-8 (status %d)\n", status); */
Packit Service dcb6c2
				}
Packit Service dcb6c2
			} else {
Packit Service dcb6c2
				ret = PSL_ERR_TO_LOWER;
Packit Service dcb6c2
				/* fprintf(stderr, "Failed to convert UTF-16 to lowercase (status %d)\n", status); */
Packit Service dcb6c2
			}
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			ret = PSL_ERR_TO_UTF16;
Packit Service dcb6c2
			/* fprintf(stderr, "Failed to convert string to UTF-16 (status %d)\n", status); */
Packit Service dcb6c2
		}
Packit Service dcb6c2
	} else {
Packit Service dcb6c2
		ret = PSL_ERR_CONVERTER;
Packit Service dcb6c2
		/* fprintf(stderr, "Failed to open converter for '%s' (status %d)\n", encoding, status); */
Packit Service dcb6c2
	}
Packit Service dcb6c2
out:
Packit Service dcb6c2
	if (str_length >= 256) {
Packit Service dcb6c2
		free(utf16_dst);
Packit Service dcb6c2
		free(utf16_lower);
Packit Service dcb6c2
		free(utf8_lower);
Packit Service dcb6c2
	}
Packit Service dcb6c2
	} while (0);
Packit Service dcb6c2
#elif defined(WITH_LIBIDN2) || defined(WITH_LIBIDN)
Packit Service dcb6c2
	do {
Packit Service dcb6c2
		/* find out local charset encoding */
Packit Service dcb6c2
		if (!encoding) {
Packit Service dcb6c2
#ifdef HAVE_NL_LANGINFO
Packit Service dcb6c2
			encoding = nl_langinfo(CODESET);
Packit Service dcb6c2
#elif defined _WIN32
Packit Service dcb6c2
			static char buf[16];
Packit Service dcb6c2
			snprintf(buf, sizeof(buf), "CP%u", GetACP());
Packit Service dcb6c2
			encoding = buf;
Packit Service dcb6c2
#endif
Packit Service dcb6c2
			if (!encoding || !*encoding)
Packit Service dcb6c2
				encoding = "ASCII";
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
		/* convert to UTF-8 */
Packit Service dcb6c2
		if (strcasecmp(encoding, "utf-8")) {
Packit Service dcb6c2
			iconv_t cd = iconv_open("utf-8", encoding);
Packit Service dcb6c2
Packit Service dcb6c2
			if (cd != (iconv_t)-1) {
Packit Service dcb6c2
				char *tmp = (char *)str; /* iconv won't change where str points to, but changes tmp itself */
Packit Service dcb6c2
				size_t tmp_len = strlen(str) + 1;
Packit Service dcb6c2
				size_t dst_len = tmp_len * 6, dst_len_tmp = dst_len;
Packit Service dcb6c2
				char *dst = malloc(dst_len + 1), *dst_tmp = dst;
Packit Service dcb6c2
Packit Service dcb6c2
				if (!dst) {
Packit Service dcb6c2
					ret = PSL_ERR_NO_MEM;
Packit Service dcb6c2
				}
Packit Service dcb6c2
				else if (iconv(cd, (WINICONV_CONST char **)&tmp, &tmp_len, &dst_tmp, &dst_len_tmp) != (size_t)-1
Packit Service dcb6c2
					&& iconv(cd, NULL, NULL, &dst_tmp, &dst_len_tmp) != (size_t)-1)
Packit Service dcb6c2
				{
Packit Service dcb6c2
					/* start size for u8_tolower internal memory allocation.
Packit Service dcb6c2
					 * u8_tolower() does not terminate the result string. we have 0 byte included in above tmp_len
Packit Service dcb6c2
					 * and thus in len. */
Packit Service dcb6c2
					size_t len = dst_len - dst_len_tmp;
Packit Service dcb6c2
Packit Service dcb6c2
					if ((tmp = (char *)u8_tolower((uint8_t *)dst, len, 0, UNINORM_NFKC, NULL, &len))) {
Packit Service dcb6c2
						ret = PSL_SUCCESS;
Packit Service dcb6c2
						if (lower) {
Packit Service dcb6c2
							*lower = tmp;
Packit Service dcb6c2
							tmp = NULL;
Packit Service dcb6c2
						} else
Packit Service dcb6c2
							free(tmp);
Packit Service dcb6c2
					} else {
Packit Service dcb6c2
						ret = PSL_ERR_TO_LOWER;
Packit Service dcb6c2
						/* fprintf(stderr, "Failed to convert UTF-8 to lowercase (errno %d)\n", errno); */
Packit Service dcb6c2
					}
Packit Service dcb6c2
				} else {
Packit Service dcb6c2
					ret = PSL_ERR_TO_UTF8;
Packit Service dcb6c2
					/* fprintf(stderr, "Failed to convert '%s' string into '%s' (%d)\n", src_encoding, dst_encoding, errno); */
Packit Service dcb6c2
				}
Packit Service dcb6c2
Packit Service dcb6c2
				free(dst);
Packit Service dcb6c2
				iconv_close(cd);
Packit Service dcb6c2
			} else {
Packit Service dcb6c2
				ret = PSL_ERR_TO_UTF8;
Packit Service dcb6c2
				/* fprintf(stderr, "Failed to prepare encoding '%s' into '%s' (%d)\n", src_encoding, dst_encoding, errno); */
Packit Service dcb6c2
			}
Packit Service dcb6c2
		} else {
Packit Service dcb6c2
			/* we need a conversion to lowercase */
Packit Service dcb6c2
			uint8_t *tmp;
Packit Service dcb6c2
Packit Service dcb6c2
			/* start size for u8_tolower internal memory allocation.
Packit Service dcb6c2
			 * u8_tolower() does not terminate the result string, so include terminating 0 byte in len. */
Packit Service dcb6c2
			size_t len = u8_strlen((uint8_t *)str) + 1;
Packit Service dcb6c2
Packit Service dcb6c2
			if ((tmp = u8_tolower((uint8_t *)str, len, 0, UNINORM_NFKC, NULL, &len))) {
Packit Service dcb6c2
				ret = PSL_SUCCESS;
Packit Service dcb6c2
				if (lower) {
Packit Service dcb6c2
					*lower = (char*)tmp;
Packit Service dcb6c2
					tmp = NULL;
Packit Service dcb6c2
				} else
Packit Service dcb6c2
					free(tmp);
Packit Service dcb6c2
			} else {
Packit Service dcb6c2
				ret = PSL_ERR_TO_LOWER;
Packit Service dcb6c2
				/* fprintf(stderr, "Failed to convert UTF-8 to lowercase (errno %d)\n", errno); */
Packit Service dcb6c2
			}
Packit Service dcb6c2
		}
Packit Service dcb6c2
Packit Service dcb6c2
	} while (0);
Packit Service dcb6c2
#endif
Packit Service dcb6c2
Packit Service dcb6c2
	return ret;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/* if file is newer than the builtin data, insert it reverse sorted by mtime */
Packit Service dcb6c2
static int _insert_file(const char *fname, const char **psl_fname, time_t *psl_mtime, int n)
Packit Service dcb6c2
{
Packit Service dcb6c2
	struct stat st;
Packit Service dcb6c2
	int it;
Packit Service dcb6c2
Packit Service dcb6c2
	if (fname && *fname && stat(fname, &st) == 0 && st.st_mtime > _psl_file_time) {
Packit Service dcb6c2
		/* add file name and mtime to end of array */
Packit Service dcb6c2
		psl_fname[n] = fname;
Packit Service dcb6c2
		psl_mtime[n++] = st.st_mtime;
Packit Service dcb6c2
Packit Service dcb6c2
		/* move the new entry to it's correct position */
Packit Service dcb6c2
		for (it = n - 2; it >= 0 && st.st_mtime > psl_mtime[it]; it--) {
Packit Service dcb6c2
			psl_fname[it + 1] = psl_fname[it];
Packit Service dcb6c2
			psl_mtime[it + 1] = psl_mtime[it];
Packit Service dcb6c2
			psl_fname[it] = fname;
Packit Service dcb6c2
			psl_mtime[it] = st.st_mtime;
Packit Service dcb6c2
		}
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	return n;
Packit Service dcb6c2
}
Packit Service dcb6c2
Packit Service dcb6c2
/**
Packit Service dcb6c2
 * psl_latest:
Packit Service dcb6c2
 * @fname: Name of PSL file or %NULL
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * This function loads the the latest available PSL data from either
Packit Service dcb6c2
 * - @fname (application specific filename, may be %NULL)
Packit Service dcb6c2
 * - location specified during built-time (filename from ./configure --with-psl-distfile)
Packit Service dcb6c2
 * - built-in PSL data (generated from ./configure --with-psl-file)
Packit Service dcb6c2
 * - location of built-in data (filename from ./configure --with-psl-file)
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * If none of the above is available, the function returns %NULL.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * To free the allocated resources, call psl_free().
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Returns: Pointer to a PSL context or %NULL on failure.
Packit Service dcb6c2
 *
Packit Service dcb6c2
 * Since: 0.16
Packit Service dcb6c2
 */
Packit Service dcb6c2
psl_ctx_t *psl_latest(const char *fname)
Packit Service dcb6c2
{
Packit Service dcb6c2
	psl_ctx_t *psl;
Packit Service dcb6c2
	const char *psl_fname[3];
Packit Service dcb6c2
	time_t psl_mtime[3];
Packit Service dcb6c2
	int it, ntimes;
Packit Service dcb6c2
Packit Service dcb6c2
	psl_fname[0] = NULL; /* silence gcc 6.2 false warning */
Packit Service dcb6c2
Packit Service dcb6c2
	/* create array of PSL files reverse sorted by mtime (latest first) */
Packit Service dcb6c2
	ntimes = _insert_file(fname, psl_fname, psl_mtime, 0);
Packit Service dcb6c2
	ntimes = _insert_file(_psl_dist_filename, psl_fname, psl_mtime, ntimes);
Packit Service dcb6c2
	ntimes = _insert_file(_psl_filename, psl_fname, psl_mtime, ntimes);
Packit Service dcb6c2
Packit Service dcb6c2
	/* load PSL data from the latest file, falling back to the second recent, ... */
Packit Service dcb6c2
	for (psl = NULL, it = 0; it < ntimes; it++) {
Packit Service dcb6c2
		if (psl_mtime[it] > _psl_file_time)
Packit Service dcb6c2
			if ((psl = psl_load_file(psl_fname[it])))
Packit Service dcb6c2
				break;
Packit Service dcb6c2
	}
Packit Service dcb6c2
Packit Service dcb6c2
	/* if file loading failed or there is no file newer than the builtin data,
Packit Service dcb6c2
	 * then return the builtin data. */
Packit Service dcb6c2
	return psl ? psl : (psl_ctx_t *) psl_builtin();
Packit Service dcb6c2
}