Home | History | Annotate | Line # | Download | only in lib
      1  1.14    wiz /*	$NetBSD: license.c,v 1.14 2025/05/09 13:26:38 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.12    wiz     "beer-ware "
     54   1.4    wiz     "boost-license "
     55   1.4    wiz     "cc-by-sa-v3.0 "
     56   1.8  sevan     "cc-by-sa-v4.0 "
     57   1.8  sevan     "cc-by-v4.0 "
     58   1.5  joerg     "cc0-1.0-universal "
     59   1.4    wiz     "cddl-1.0 "
     60   1.5  joerg     "cecill-2.1 "
     61   1.9  joerg     "cecill-b-v1 "
     62  1.12    wiz     "cecill-c-v1 "
     63   1.4    wiz     "cpl-1.0 "
     64  1.14    wiz     "epl-v1.0 epl-v2.0 "
     65   1.5  joerg     "eupl-v1.1 "
     66  1.12    wiz     "eupl-v1.2 "
     67   1.5  joerg     "gfsl "
     68   1.2   adam     "gnu-fdl-v1.1 gnu-fdl-v1.2 gnu-fdl-v1.3 "
     69   1.3   tron     "gnu-gpl-v1 "
     70   1.2   adam     "gnu-gpl-v2 gnu-lgpl-v2 gnu-lgpl-v2.1 "
     71   1.1  joerg     "gnu-gpl-v3 gnu-lgpl-v3 "
     72   1.7  sevan     "happy "
     73   1.5  joerg     "hpnd "
     74  1.12    wiz     "icu "
     75  1.12    wiz     "ijg "
     76   1.5  joerg     "info-zip "
     77   1.4    wiz     "ipafont "
     78   1.5  joerg     "ipl-1.0 "
     79   1.4    wiz     "isc "
     80   1.5  joerg     "lppl-1.0 lppl-1.2 lppl-1.3c "
     81   1.4    wiz     "lucent "
     82   1.4    wiz     "miros "
     83   1.4    wiz     "mit "
     84   1.4    wiz     "mpl-1.0 mpl-1.1 mpl-2.0 "
     85   1.4    wiz     "mplusfont "
     86  1.12    wiz     "ms-pl "
     87  1.11    nia     "odbl-v1 "
     88   1.4    wiz     "ofl-v1.0 ofl-v1.1 "
     89   1.5  joerg     "openssl "
     90  1.12    wiz     "original-bsd modified-bsd 2-clause-bsd 0-clause-bsd "
     91   1.8  sevan     "osl "
     92   1.5  joerg     "paratype "
     93   1.4    wiz     "php "
     94   1.4    wiz     "png-license "
     95   1.2   adam     "postgresql-license "
     96   1.4    wiz     "public-domain "
     97   1.4    wiz     "python-software-foundation "
     98  1.14    wiz     "qhull "
     99   1.4    wiz     "qpl-v1.0 "
    100   1.5  joerg     "sgi-free-software-b-v2.0 "
    101   1.5  joerg     "sissl-1.1 "
    102   1.4    wiz     "sleepycat-public "
    103   1.5  joerg     "unicode "
    104  1.12    wiz     "unicode-v3 "
    105   1.4    wiz     "unlicense "
    106  1.13    wiz     "upl-1.0 "
    107   1.5  joerg     "vera-ttf-license "
    108   1.5  joerg     "w3c "
    109   1.4    wiz     "x11 "
    110   1.3   tron     "zlib "
    111   1.6   maya     "zpl-2.0 zpl-2.1 "
    112   1.6   maya     "zsh";
    113   1.1  joerg 
    114   1.1  joerg #ifdef DEBUG
    115   1.1  joerg static size_t hash_collisions;
    116   1.1  joerg #endif
    117   1.1  joerg 
    118   1.1  joerg static char **license_hash[HASH_SIZE];
    119   1.1  joerg static const char license_spaces[] = " \t\n";
    120   1.2   adam static const char license_chars[] =
    121   1.2   adam     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
    122   1.1  joerg 
    123   1.1  joerg static size_t
    124   1.1  joerg hash_license(const char *license, size_t len)
    125   1.1  joerg {
    126   1.1  joerg 	size_t hash;
    127   1.1  joerg 
    128   1.1  joerg 	for (hash = 0; *license && len; ++license, --len)
    129   1.1  joerg 		hash = *license + hash * 32;
    130   1.1  joerg 	return hash % HASH_SIZE;
    131   1.1  joerg }
    132   1.1  joerg 
    133   1.1  joerg static void
    134   1.1  joerg add_license_internal(const char *license, size_t len)
    135   1.1  joerg {
    136   1.1  joerg 	char *new_license;
    137   1.1  joerg 	size_t slot, i;
    138   1.1  joerg 
    139   1.1  joerg 	slot = hash_license(license, len);
    140   1.1  joerg 
    141   1.1  joerg 	new_license = malloc(len + 1);
    142   1.1  joerg 	memcpy(new_license, license, len);
    143   1.1  joerg 	new_license[len] = '\0';
    144   1.1  joerg 
    145   1.1  joerg 	if (license_hash[slot] == NULL) {
    146   1.1  joerg 		license_hash[slot] = calloc(sizeof(char *), 2);
    147   1.1  joerg 		license_hash[slot][0] = new_license;
    148   1.1  joerg 	} else {
    149   1.1  joerg 		for (i = 0; license_hash[slot][i]; ++i) {
    150   1.1  joerg 			if (!memcmp(license_hash[slot][i], license, len) &&
    151   1.1  joerg 			    license_hash[slot][i][len] == '\0') {
    152   1.1  joerg 				free(new_license);
    153   1.1  joerg 				return;
    154   1.1  joerg 			}
    155   1.1  joerg 		}
    156   1.1  joerg 
    157   1.1  joerg #ifdef DEBUG
    158   1.1  joerg 		++hash_collisions;
    159   1.1  joerg #endif
    160   1.1  joerg 
    161   1.1  joerg 		license_hash[slot] = realloc(license_hash[slot],
    162   1.1  joerg 		    sizeof(char *) * (i + 2));
    163   1.1  joerg 		license_hash[slot][i] = new_license;
    164   1.1  joerg 		license_hash[slot][i + 1] = NULL;
    165   1.1  joerg 	}
    166   1.1  joerg }
    167   1.1  joerg 
    168   1.1  joerg int
    169   1.1  joerg add_licenses(const char *line)
    170   1.1  joerg {
    171   1.1  joerg 	const char *next;
    172   1.1  joerg 
    173   1.1  joerg 	if (line == NULL)
    174   1.1  joerg 		return 0;
    175   1.1  joerg 
    176   1.1  joerg 	for (line += strspn(line, license_spaces); line; ) {
    177   1.1  joerg 		next = line + strspn(line, license_chars);
    178   1.1  joerg 		if (next == line)
    179   1.1  joerg 			return *line ? -1 : 0;
    180   1.1  joerg 		add_license_internal(line, next - line);
    181   1.1  joerg 		line = next + strspn(next, license_spaces);
    182   1.1  joerg 		if (next == line)
    183   1.1  joerg 			return *line ? -1 : 0;
    184   1.1  joerg 	}
    185   1.1  joerg 	return 0;
    186   1.1  joerg }
    187   1.1  joerg 
    188   1.1  joerg static int
    189   1.1  joerg acceptable_license_internal(const char *license, size_t len)
    190   1.1  joerg {
    191   1.1  joerg 	size_t slot, i;
    192   1.1  joerg 
    193   1.1  joerg 	slot = hash_license(license, len);
    194   1.1  joerg 
    195   1.1  joerg 	if (license_hash[slot] == NULL)
    196   1.1  joerg 		return 0;
    197   1.1  joerg 
    198   1.1  joerg 	for (i = 0; license_hash[slot][i]; ++i) {
    199   1.1  joerg 		if (strncmp(license_hash[slot][i], license, len) == 0 &&
    200   1.1  joerg 		    license_hash[slot][i][len] == '\0')
    201   1.1  joerg 			return 1;
    202   1.1  joerg 	}
    203   1.1  joerg 
    204   1.1  joerg 	return 0;
    205   1.1  joerg }
    206   1.1  joerg 
    207   1.1  joerg int
    208   1.1  joerg acceptable_license(const char *license)
    209   1.1  joerg {
    210   1.1  joerg 	size_t len;
    211   1.1  joerg 
    212   1.1  joerg 	len = strlen(license);
    213   1.2   adam 	if (strspn(license, license_chars) != len) {
    214   1.2   adam 		warnx("Invalid character in license name at position %" PRIzu, len);
    215   1.1  joerg 		return -1;
    216   1.2   adam 	}
    217   1.1  joerg 
    218   1.1  joerg 	return acceptable_license_internal(license, len);
    219   1.1  joerg }
    220   1.1  joerg 
    221   1.1  joerg static int
    222   1.2   adam acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
    223   1.1  joerg {
    224   1.1  joerg 	const char *license = *licensep;
    225   1.1  joerg 	int need_parenthesis, is_true = 0;
    226   1.1  joerg 	int expr_type = 0; /* 0: unset, 1: or, 2: and */
    227   1.1  joerg 	size_t len;
    228   1.1  joerg 
    229   1.1  joerg 	license += strspn(license, license_spaces);
    230   1.1  joerg 
    231   1.1  joerg 	if (*license == '(' && !toplevel) {
    232   1.1  joerg 		need_parenthesis = 1;
    233   1.1  joerg 		++license;
    234   1.1  joerg 		license += strspn(license, license_spaces);
    235   1.1  joerg 	} else {
    236   1.1  joerg 		need_parenthesis = 0;
    237   1.1  joerg 	}
    238   1.1  joerg 
    239   1.1  joerg 	for (;;) {
    240   1.1  joerg 		if (*license == '(') {
    241   1.2   adam 			switch (acceptable_pkg_license_internal(&license, 0, start)) {
    242   1.1  joerg 			case -1:
    243   1.1  joerg 				return -1;
    244   1.1  joerg 			case 0:
    245   1.1  joerg 				if (expr_type == 2)
    246   1.1  joerg 					is_true = 0;
    247   1.1  joerg 				break;
    248   1.1  joerg 			case 1:
    249   1.1  joerg 				is_true = 1;
    250   1.1  joerg 				break;
    251   1.1  joerg 			}
    252   1.1  joerg 			license += strspn(license, license_spaces);
    253   1.1  joerg 		} else {
    254   1.1  joerg 			len = strspn(license, license_chars);
    255   1.2   adam 			if (len == 0) {
    256   1.2   adam 				warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
    257   1.1  joerg 				return -1;
    258   1.2   adam 			}
    259   1.1  joerg 
    260   1.1  joerg 			if (acceptable_license_internal(license, len)) {
    261   1.1  joerg 				if (expr_type != 2)
    262   1.1  joerg 					is_true = 1;
    263   1.1  joerg 			} else if (expr_type == 2) {
    264   1.1  joerg 				is_true = 0;
    265   1.1  joerg 			}
    266   1.1  joerg 
    267   1.1  joerg 			license += len;
    268   1.1  joerg 
    269   1.1  joerg 			len = strspn(license, license_spaces);
    270   1.2   adam 			if (len == 0 && *license && *license  != ')') {
    271   1.2   adam 				warnx("Missing space at position %" PRIzu, license - start + 1);
    272   1.1  joerg 				return -1;
    273   1.2   adam 			}
    274   1.1  joerg 			license += len;
    275   1.1  joerg 		}
    276   1.1  joerg 
    277   1.1  joerg 		if (*license == ')') {
    278   1.2   adam 			if (!need_parenthesis) {
    279   1.2   adam 				warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
    280   1.1  joerg 				return -1;
    281   1.2   adam 			}
    282   1.1  joerg 			*licensep = license + 1;
    283   1.1  joerg 			return is_true;
    284   1.1  joerg 		}
    285   1.1  joerg 		if (*license == '\0') {
    286   1.2   adam 			if (need_parenthesis) {
    287   1.2   adam 				warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
    288   1.1  joerg 				return -1;
    289   1.2   adam 			}
    290   1.1  joerg 			*licensep = license;
    291   1.1  joerg 			return is_true;
    292   1.1  joerg 		}
    293   1.1  joerg 
    294   1.1  joerg 		if (strncmp(license, "AND", 3) == 0) {
    295   1.2   adam 			if (expr_type == 1) {
    296   1.2   adam 				warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
    297   1.1  joerg 				return -1;
    298   1.2   adam 			}
    299   1.1  joerg 			expr_type = 2;
    300   1.1  joerg 			license += 3;
    301   1.1  joerg 		} else if (strncmp(license, "OR", 2) == 0) {
    302   1.2   adam 			if (expr_type == 2) {
    303   1.2   adam 				warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
    304   1.1  joerg 				return -1;
    305   1.2   adam 			}
    306   1.1  joerg 			expr_type = 1;
    307   1.1  joerg 			license += 2;
    308   1.1  joerg 		} else {
    309   1.2   adam 			warnx("Invalid operator at position %" PRIzu, license - start + 1);
    310   1.1  joerg 			return -1;
    311   1.1  joerg 		}
    312   1.1  joerg 		len = strspn(license, license_spaces);
    313   1.2   adam 		if (len == 0 && *license != '(') {
    314   1.2   adam 			warnx("Missing space at position %" PRIzu, license - start + 1);
    315   1.1  joerg 			return -1;
    316   1.2   adam 		}
    317   1.1  joerg 		license += len;
    318   1.1  joerg 	}
    319   1.1  joerg }
    320   1.1  joerg 
    321   1.1  joerg int
    322   1.1  joerg acceptable_pkg_license(const char *license)
    323   1.1  joerg {
    324   1.1  joerg 	int ret;
    325   1.1  joerg 
    326   1.2   adam 	ret = acceptable_pkg_license_internal(&license, 1, license);
    327   1.1  joerg 	if (ret == -1)
    328   1.1  joerg 		return -1;
    329   1.1  joerg 	license += strspn(license, license_spaces);
    330   1.2   adam 	if (*license) {
    331   1.2   adam 		warnx("Trailing garbage in license specification");
    332   1.1  joerg 		return -1;
    333   1.2   adam 	}
    334   1.1  joerg 	return ret;
    335   1.1  joerg }
    336   1.1  joerg 
    337   1.1  joerg void
    338   1.1  joerg load_license_lists(void)
    339   1.1  joerg {
    340   1.1  joerg 	if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
    341   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
    342   1.1  joerg 	if (add_licenses(acceptable_licenses))
    343   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
    344   1.1  joerg 	if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
    345   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
    346   1.1  joerg 	if (add_licenses(default_acceptable_licenses))
    347   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
    348   1.1  joerg }
    349