Home | History | Annotate | Line # | Download | only in lib
license.c revision 1.10
      1  1.10    wiz /*	$NetBSD: license.c,v 1.10 2020/12/02 13:53:50 wiz Exp $	*/
      2   1.1  joerg 
      3   1.1  joerg /*-
      4   1.1  joerg  * Copyright (c) 2009 Joerg Sonnenberger <joerg (at) NetBSD.org>.
      5   1.1  joerg  * All rights reserved.
      6   1.1  joerg  *
      7   1.1  joerg  * Redistribution and use in source and binary forms, with or without
      8   1.1  joerg  * modification, are permitted provided that the following conditions
      9   1.1  joerg  * are met:
     10   1.1  joerg  *
     11   1.1  joerg  * 1. Redistributions of source code must retain the above copyright
     12   1.1  joerg  *    notice, this list of conditions and the following disclaimer.
     13   1.1  joerg  * 2. Redistributions in binary form must reproduce the above copyright
     14   1.1  joerg  *    notice, this list of conditions and the following disclaimer in
     15   1.1  joerg  *    the documentation and/or other materials provided with the
     16   1.1  joerg  *    distribution.
     17   1.1  joerg  *
     18   1.1  joerg  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19   1.1  joerg  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20   1.1  joerg  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     21   1.1  joerg  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
     22   1.1  joerg  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     23   1.1  joerg  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
     24   1.1  joerg  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25   1.1  joerg  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     26   1.1  joerg  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     27   1.1  joerg  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     28   1.1  joerg  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29   1.1  joerg  * SUCH DAMAGE.
     30   1.1  joerg  */
     31   1.1  joerg 
     32   1.1  joerg #if HAVE_CONFIG_H
     33   1.1  joerg #include "config.h"
     34   1.1  joerg #endif
     35   1.1  joerg 
     36   1.1  joerg #include <nbcompat.h>
     37   1.1  joerg 
     38   1.1  joerg #if HAVE_ERR_H
     39   1.1  joerg #include <err.h>
     40   1.1  joerg #endif
     41   1.1  joerg #include <stdlib.h>
     42   1.1  joerg #include <string.h>
     43   1.1  joerg 
     44   1.1  joerg #include "lib.h"
     45   1.1  joerg 
     46   1.1  joerg #define	HASH_SIZE	521
     47   1.1  joerg 
     48   1.1  joerg const char *default_acceptable_licenses =
     49  1.10    wiz     "afl-3.0 "
     50   1.4    wiz     "apache-1.1 apache-2.0 "
     51   1.4    wiz     "arphic-public "
     52   1.4    wiz     "artistic artistic-2.0 "
     53   1.4    wiz     "boost-license "
     54   1.4    wiz     "cc-by-sa-v3.0 "
     55   1.8  sevan     "cc-by-sa-v4.0 "
     56   1.8  sevan     "cc-by-v4.0 "
     57   1.5  joerg     "cc0-1.0-universal "
     58   1.4    wiz     "cddl-1.0 "
     59   1.5  joerg     "cecill-2.1 "
     60   1.9  joerg     "cecill-b-v1 "
     61   1.4    wiz     "cpl-1.0 "
     62   1.4    wiz     "epl-v1.0 "
     63   1.5  joerg     "eupl-v1.1 "
     64   1.5  joerg     "gfsl "
     65   1.2   adam     "gnu-fdl-v1.1 gnu-fdl-v1.2 gnu-fdl-v1.3 "
     66   1.3   tron     "gnu-gpl-v1 "
     67   1.2   adam     "gnu-gpl-v2 gnu-lgpl-v2 gnu-lgpl-v2.1 "
     68   1.1  joerg     "gnu-gpl-v3 gnu-lgpl-v3 "
     69   1.7  sevan     "happy "
     70   1.5  joerg     "hpnd "
     71   1.5  joerg     "info-zip "
     72   1.4    wiz     "ipafont "
     73   1.5  joerg     "ipl-1.0 "
     74   1.4    wiz     "isc "
     75   1.5  joerg     "lppl-1.0 lppl-1.2 lppl-1.3c "
     76   1.4    wiz     "lucent "
     77   1.4    wiz     "miros "
     78   1.4    wiz     "mit "
     79   1.4    wiz     "mpl-1.0 mpl-1.1 mpl-2.0 "
     80   1.4    wiz     "mplusfont "
     81   1.4    wiz     "ofl-v1.0 ofl-v1.1 "
     82   1.5  joerg     "openssl "
     83   1.2   adam     "original-bsd modified-bsd 2-clause-bsd "
     84   1.8  sevan     "osl "
     85   1.5  joerg     "paratype "
     86   1.4    wiz     "php "
     87   1.4    wiz     "png-license "
     88   1.2   adam     "postgresql-license "
     89   1.4    wiz     "public-domain "
     90   1.4    wiz     "python-software-foundation "
     91   1.4    wiz     "qpl-v1.0 "
     92   1.5  joerg     "sgi-free-software-b-v2.0 "
     93   1.5  joerg     "sissl-1.1 "
     94   1.4    wiz     "sleepycat-public "
     95   1.5  joerg     "unicode "
     96   1.4    wiz     "unlicense "
     97   1.5  joerg     "vera-ttf-license "
     98   1.5  joerg     "w3c "
     99   1.4    wiz     "x11 "
    100   1.3   tron     "zlib "
    101   1.6   maya     "zpl-2.0 zpl-2.1 "
    102   1.6   maya     "zsh";
    103   1.1  joerg 
    104   1.1  joerg #ifdef DEBUG
    105   1.1  joerg static size_t hash_collisions;
    106   1.1  joerg #endif
    107   1.1  joerg 
    108   1.1  joerg static char **license_hash[HASH_SIZE];
    109   1.1  joerg static const char license_spaces[] = " \t\n";
    110   1.2   adam static const char license_chars[] =
    111   1.2   adam     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
    112   1.1  joerg 
    113   1.1  joerg static size_t
    114   1.1  joerg hash_license(const char *license, size_t len)
    115   1.1  joerg {
    116   1.1  joerg 	size_t hash;
    117   1.1  joerg 
    118   1.1  joerg 	for (hash = 0; *license && len; ++license, --len)
    119   1.1  joerg 		hash = *license + hash * 32;
    120   1.1  joerg 	return hash % HASH_SIZE;
    121   1.1  joerg }
    122   1.1  joerg 
    123   1.1  joerg static void
    124   1.1  joerg add_license_internal(const char *license, size_t len)
    125   1.1  joerg {
    126   1.1  joerg 	char *new_license;
    127   1.1  joerg 	size_t slot, i;
    128   1.1  joerg 
    129   1.1  joerg 	slot = hash_license(license, len);
    130   1.1  joerg 
    131   1.1  joerg 	new_license = malloc(len + 1);
    132   1.1  joerg 	memcpy(new_license, license, len);
    133   1.1  joerg 	new_license[len] = '\0';
    134   1.1  joerg 
    135   1.1  joerg 	if (license_hash[slot] == NULL) {
    136   1.1  joerg 		license_hash[slot] = calloc(sizeof(char *), 2);
    137   1.1  joerg 		license_hash[slot][0] = new_license;
    138   1.1  joerg 	} else {
    139   1.1  joerg 		for (i = 0; license_hash[slot][i]; ++i) {
    140   1.1  joerg 			if (!memcmp(license_hash[slot][i], license, len) &&
    141   1.1  joerg 			    license_hash[slot][i][len] == '\0') {
    142   1.1  joerg 				free(new_license);
    143   1.1  joerg 				return;
    144   1.1  joerg 			}
    145   1.1  joerg 		}
    146   1.1  joerg 
    147   1.1  joerg #ifdef DEBUG
    148   1.1  joerg 		++hash_collisions;
    149   1.1  joerg #endif
    150   1.1  joerg 
    151   1.1  joerg 		license_hash[slot] = realloc(license_hash[slot],
    152   1.1  joerg 		    sizeof(char *) * (i + 2));
    153   1.1  joerg 		license_hash[slot][i] = new_license;
    154   1.1  joerg 		license_hash[slot][i + 1] = NULL;
    155   1.1  joerg 	}
    156   1.1  joerg }
    157   1.1  joerg 
    158   1.1  joerg int
    159   1.1  joerg add_licenses(const char *line)
    160   1.1  joerg {
    161   1.1  joerg 	const char *next;
    162   1.1  joerg 
    163   1.1  joerg 	if (line == NULL)
    164   1.1  joerg 		return 0;
    165   1.1  joerg 
    166   1.1  joerg 	for (line += strspn(line, license_spaces); line; ) {
    167   1.1  joerg 		next = line + strspn(line, license_chars);
    168   1.1  joerg 		if (next == line)
    169   1.1  joerg 			return *line ? -1 : 0;
    170   1.1  joerg 		add_license_internal(line, next - line);
    171   1.1  joerg 		line = next + strspn(next, license_spaces);
    172   1.1  joerg 		if (next == line)
    173   1.1  joerg 			return *line ? -1 : 0;
    174   1.1  joerg 	}
    175   1.1  joerg 	return 0;
    176   1.1  joerg }
    177   1.1  joerg 
    178   1.1  joerg static int
    179   1.1  joerg acceptable_license_internal(const char *license, size_t len)
    180   1.1  joerg {
    181   1.1  joerg 	size_t slot, i;
    182   1.1  joerg 
    183   1.1  joerg 	slot = hash_license(license, len);
    184   1.1  joerg 
    185   1.1  joerg 	if (license_hash[slot] == NULL)
    186   1.1  joerg 		return 0;
    187   1.1  joerg 
    188   1.1  joerg 	for (i = 0; license_hash[slot][i]; ++i) {
    189   1.1  joerg 		if (strncmp(license_hash[slot][i], license, len) == 0 &&
    190   1.1  joerg 		    license_hash[slot][i][len] == '\0')
    191   1.1  joerg 			return 1;
    192   1.1  joerg 	}
    193   1.1  joerg 
    194   1.1  joerg 	return 0;
    195   1.1  joerg }
    196   1.1  joerg 
    197   1.1  joerg int
    198   1.1  joerg acceptable_license(const char *license)
    199   1.1  joerg {
    200   1.1  joerg 	size_t len;
    201   1.1  joerg 
    202   1.1  joerg 	len = strlen(license);
    203   1.2   adam 	if (strspn(license, license_chars) != len) {
    204   1.2   adam 		warnx("Invalid character in license name at position %" PRIzu, len);
    205   1.1  joerg 		return -1;
    206   1.2   adam 	}
    207   1.1  joerg 
    208   1.1  joerg 	return acceptable_license_internal(license, len);
    209   1.1  joerg }
    210   1.1  joerg 
    211   1.1  joerg static int
    212   1.2   adam acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
    213   1.1  joerg {
    214   1.1  joerg 	const char *license = *licensep;
    215   1.1  joerg 	int need_parenthesis, is_true = 0;
    216   1.1  joerg 	int expr_type = 0; /* 0: unset, 1: or, 2: and */
    217   1.1  joerg 	size_t len;
    218   1.1  joerg 
    219   1.1  joerg 	license += strspn(license, license_spaces);
    220   1.1  joerg 
    221   1.1  joerg 	if (*license == '(' && !toplevel) {
    222   1.1  joerg 		need_parenthesis = 1;
    223   1.1  joerg 		++license;
    224   1.1  joerg 		license += strspn(license, license_spaces);
    225   1.1  joerg 	} else {
    226   1.1  joerg 		need_parenthesis = 0;
    227   1.1  joerg 	}
    228   1.1  joerg 
    229   1.1  joerg 	for (;;) {
    230   1.1  joerg 		if (*license == '(') {
    231   1.2   adam 			switch (acceptable_pkg_license_internal(&license, 0, start)) {
    232   1.1  joerg 			case -1:
    233   1.1  joerg 				return -1;
    234   1.1  joerg 			case 0:
    235   1.1  joerg 				if (expr_type == 2)
    236   1.1  joerg 					is_true = 0;
    237   1.1  joerg 				break;
    238   1.1  joerg 			case 1:
    239   1.1  joerg 				is_true = 1;
    240   1.1  joerg 				break;
    241   1.1  joerg 			}
    242   1.1  joerg 			license += strspn(license, license_spaces);
    243   1.1  joerg 		} else {
    244   1.1  joerg 			len = strspn(license, license_chars);
    245   1.2   adam 			if (len == 0) {
    246   1.2   adam 				warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
    247   1.1  joerg 				return -1;
    248   1.2   adam 			}
    249   1.1  joerg 
    250   1.1  joerg 			if (acceptable_license_internal(license, len)) {
    251   1.1  joerg 				if (expr_type != 2)
    252   1.1  joerg 					is_true = 1;
    253   1.1  joerg 			} else if (expr_type == 2) {
    254   1.1  joerg 				is_true = 0;
    255   1.1  joerg 			}
    256   1.1  joerg 
    257   1.1  joerg 			license += len;
    258   1.1  joerg 
    259   1.1  joerg 			len = strspn(license, license_spaces);
    260   1.2   adam 			if (len == 0 && *license && *license  != ')') {
    261   1.2   adam 				warnx("Missing space at position %" PRIzu, license - start + 1);
    262   1.1  joerg 				return -1;
    263   1.2   adam 			}
    264   1.1  joerg 			license += len;
    265   1.1  joerg 		}
    266   1.1  joerg 
    267   1.1  joerg 		if (*license == ')') {
    268   1.2   adam 			if (!need_parenthesis) {
    269   1.2   adam 				warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
    270   1.1  joerg 				return -1;
    271   1.2   adam 			}
    272   1.1  joerg 			*licensep = license + 1;
    273   1.1  joerg 			return is_true;
    274   1.1  joerg 		}
    275   1.1  joerg 		if (*license == '\0') {
    276   1.2   adam 			if (need_parenthesis) {
    277   1.2   adam 				warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
    278   1.1  joerg 				return -1;
    279   1.2   adam 			}
    280   1.1  joerg 			*licensep = license;
    281   1.1  joerg 			return is_true;
    282   1.1  joerg 		}
    283   1.1  joerg 
    284   1.1  joerg 		if (strncmp(license, "AND", 3) == 0) {
    285   1.2   adam 			if (expr_type == 1) {
    286   1.2   adam 				warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
    287   1.1  joerg 				return -1;
    288   1.2   adam 			}
    289   1.1  joerg 			expr_type = 2;
    290   1.1  joerg 			license += 3;
    291   1.1  joerg 		} else if (strncmp(license, "OR", 2) == 0) {
    292   1.2   adam 			if (expr_type == 2) {
    293   1.2   adam 				warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
    294   1.1  joerg 				return -1;
    295   1.2   adam 			}
    296   1.1  joerg 			expr_type = 1;
    297   1.1  joerg 			license += 2;
    298   1.1  joerg 		} else {
    299   1.2   adam 			warnx("Invalid operator at position %" PRIzu, license - start + 1);
    300   1.1  joerg 			return -1;
    301   1.1  joerg 		}
    302   1.1  joerg 		len = strspn(license, license_spaces);
    303   1.2   adam 		if (len == 0 && *license != '(') {
    304   1.2   adam 			warnx("Missing space at position %" PRIzu, license - start + 1);
    305   1.1  joerg 			return -1;
    306   1.2   adam 		}
    307   1.1  joerg 		license += len;
    308   1.1  joerg 	}
    309   1.1  joerg }
    310   1.1  joerg 
    311   1.1  joerg int
    312   1.1  joerg acceptable_pkg_license(const char *license)
    313   1.1  joerg {
    314   1.1  joerg 	int ret;
    315   1.1  joerg 
    316   1.2   adam 	ret = acceptable_pkg_license_internal(&license, 1, license);
    317   1.1  joerg 	if (ret == -1)
    318   1.1  joerg 		return -1;
    319   1.1  joerg 	license += strspn(license, license_spaces);
    320   1.2   adam 	if (*license) {
    321   1.2   adam 		warnx("Trailing garbage in license specification");
    322   1.1  joerg 		return -1;
    323   1.2   adam 	}
    324   1.1  joerg 	return ret;
    325   1.1  joerg }
    326   1.1  joerg 
    327   1.1  joerg void
    328   1.1  joerg load_license_lists(void)
    329   1.1  joerg {
    330   1.1  joerg 	if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
    331   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
    332   1.1  joerg 	if (add_licenses(acceptable_licenses))
    333   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
    334   1.1  joerg 	if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
    335   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
    336   1.1  joerg 	if (add_licenses(default_acceptable_licenses))
    337   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
    338   1.1  joerg }
    339