Home | History | Annotate | Line # | Download | only in lib
license.c revision 1.13
      1  1.13    wiz /*	$NetBSD: license.c,v 1.13 2024/08/25 06:49:40 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.4    wiz     "epl-v1.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.4    wiz     "qpl-v1.0 "
     99   1.5  joerg     "sgi-free-software-b-v2.0 "
    100   1.5  joerg     "sissl-1.1 "
    101   1.4    wiz     "sleepycat-public "
    102   1.5  joerg     "unicode "
    103  1.12    wiz     "unicode-v3 "
    104   1.4    wiz     "unlicense "
    105  1.13    wiz     "upl-1.0 "
    106   1.5  joerg     "vera-ttf-license "
    107   1.5  joerg     "w3c "
    108   1.4    wiz     "x11 "
    109   1.3   tron     "zlib "
    110   1.6   maya     "zpl-2.0 zpl-2.1 "
    111   1.6   maya     "zsh";
    112   1.1  joerg 
    113   1.1  joerg #ifdef DEBUG
    114   1.1  joerg static size_t hash_collisions;
    115   1.1  joerg #endif
    116   1.1  joerg 
    117   1.1  joerg static char **license_hash[HASH_SIZE];
    118   1.1  joerg static const char license_spaces[] = " \t\n";
    119   1.2   adam static const char license_chars[] =
    120   1.2   adam     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
    121   1.1  joerg 
    122   1.1  joerg static size_t
    123   1.1  joerg hash_license(const char *license, size_t len)
    124   1.1  joerg {
    125   1.1  joerg 	size_t hash;
    126   1.1  joerg 
    127   1.1  joerg 	for (hash = 0; *license && len; ++license, --len)
    128   1.1  joerg 		hash = *license + hash * 32;
    129   1.1  joerg 	return hash % HASH_SIZE;
    130   1.1  joerg }
    131   1.1  joerg 
    132   1.1  joerg static void
    133   1.1  joerg add_license_internal(const char *license, size_t len)
    134   1.1  joerg {
    135   1.1  joerg 	char *new_license;
    136   1.1  joerg 	size_t slot, i;
    137   1.1  joerg 
    138   1.1  joerg 	slot = hash_license(license, len);
    139   1.1  joerg 
    140   1.1  joerg 	new_license = malloc(len + 1);
    141   1.1  joerg 	memcpy(new_license, license, len);
    142   1.1  joerg 	new_license[len] = '\0';
    143   1.1  joerg 
    144   1.1  joerg 	if (license_hash[slot] == NULL) {
    145   1.1  joerg 		license_hash[slot] = calloc(sizeof(char *), 2);
    146   1.1  joerg 		license_hash[slot][0] = new_license;
    147   1.1  joerg 	} else {
    148   1.1  joerg 		for (i = 0; license_hash[slot][i]; ++i) {
    149   1.1  joerg 			if (!memcmp(license_hash[slot][i], license, len) &&
    150   1.1  joerg 			    license_hash[slot][i][len] == '\0') {
    151   1.1  joerg 				free(new_license);
    152   1.1  joerg 				return;
    153   1.1  joerg 			}
    154   1.1  joerg 		}
    155   1.1  joerg 
    156   1.1  joerg #ifdef DEBUG
    157   1.1  joerg 		++hash_collisions;
    158   1.1  joerg #endif
    159   1.1  joerg 
    160   1.1  joerg 		license_hash[slot] = realloc(license_hash[slot],
    161   1.1  joerg 		    sizeof(char *) * (i + 2));
    162   1.1  joerg 		license_hash[slot][i] = new_license;
    163   1.1  joerg 		license_hash[slot][i + 1] = NULL;
    164   1.1  joerg 	}
    165   1.1  joerg }
    166   1.1  joerg 
    167   1.1  joerg int
    168   1.1  joerg add_licenses(const char *line)
    169   1.1  joerg {
    170   1.1  joerg 	const char *next;
    171   1.1  joerg 
    172   1.1  joerg 	if (line == NULL)
    173   1.1  joerg 		return 0;
    174   1.1  joerg 
    175   1.1  joerg 	for (line += strspn(line, license_spaces); line; ) {
    176   1.1  joerg 		next = line + strspn(line, license_chars);
    177   1.1  joerg 		if (next == line)
    178   1.1  joerg 			return *line ? -1 : 0;
    179   1.1  joerg 		add_license_internal(line, next - line);
    180   1.1  joerg 		line = next + strspn(next, license_spaces);
    181   1.1  joerg 		if (next == line)
    182   1.1  joerg 			return *line ? -1 : 0;
    183   1.1  joerg 	}
    184   1.1  joerg 	return 0;
    185   1.1  joerg }
    186   1.1  joerg 
    187   1.1  joerg static int
    188   1.1  joerg acceptable_license_internal(const char *license, size_t len)
    189   1.1  joerg {
    190   1.1  joerg 	size_t slot, i;
    191   1.1  joerg 
    192   1.1  joerg 	slot = hash_license(license, len);
    193   1.1  joerg 
    194   1.1  joerg 	if (license_hash[slot] == NULL)
    195   1.1  joerg 		return 0;
    196   1.1  joerg 
    197   1.1  joerg 	for (i = 0; license_hash[slot][i]; ++i) {
    198   1.1  joerg 		if (strncmp(license_hash[slot][i], license, len) == 0 &&
    199   1.1  joerg 		    license_hash[slot][i][len] == '\0')
    200   1.1  joerg 			return 1;
    201   1.1  joerg 	}
    202   1.1  joerg 
    203   1.1  joerg 	return 0;
    204   1.1  joerg }
    205   1.1  joerg 
    206   1.1  joerg int
    207   1.1  joerg acceptable_license(const char *license)
    208   1.1  joerg {
    209   1.1  joerg 	size_t len;
    210   1.1  joerg 
    211   1.1  joerg 	len = strlen(license);
    212   1.2   adam 	if (strspn(license, license_chars) != len) {
    213   1.2   adam 		warnx("Invalid character in license name at position %" PRIzu, len);
    214   1.1  joerg 		return -1;
    215   1.2   adam 	}
    216   1.1  joerg 
    217   1.1  joerg 	return acceptable_license_internal(license, len);
    218   1.1  joerg }
    219   1.1  joerg 
    220   1.1  joerg static int
    221   1.2   adam acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
    222   1.1  joerg {
    223   1.1  joerg 	const char *license = *licensep;
    224   1.1  joerg 	int need_parenthesis, is_true = 0;
    225   1.1  joerg 	int expr_type = 0; /* 0: unset, 1: or, 2: and */
    226   1.1  joerg 	size_t len;
    227   1.1  joerg 
    228   1.1  joerg 	license += strspn(license, license_spaces);
    229   1.1  joerg 
    230   1.1  joerg 	if (*license == '(' && !toplevel) {
    231   1.1  joerg 		need_parenthesis = 1;
    232   1.1  joerg 		++license;
    233   1.1  joerg 		license += strspn(license, license_spaces);
    234   1.1  joerg 	} else {
    235   1.1  joerg 		need_parenthesis = 0;
    236   1.1  joerg 	}
    237   1.1  joerg 
    238   1.1  joerg 	for (;;) {
    239   1.1  joerg 		if (*license == '(') {
    240   1.2   adam 			switch (acceptable_pkg_license_internal(&license, 0, start)) {
    241   1.1  joerg 			case -1:
    242   1.1  joerg 				return -1;
    243   1.1  joerg 			case 0:
    244   1.1  joerg 				if (expr_type == 2)
    245   1.1  joerg 					is_true = 0;
    246   1.1  joerg 				break;
    247   1.1  joerg 			case 1:
    248   1.1  joerg 				is_true = 1;
    249   1.1  joerg 				break;
    250   1.1  joerg 			}
    251   1.1  joerg 			license += strspn(license, license_spaces);
    252   1.1  joerg 		} else {
    253   1.1  joerg 			len = strspn(license, license_chars);
    254   1.2   adam 			if (len == 0) {
    255   1.2   adam 				warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
    256   1.1  joerg 				return -1;
    257   1.2   adam 			}
    258   1.1  joerg 
    259   1.1  joerg 			if (acceptable_license_internal(license, len)) {
    260   1.1  joerg 				if (expr_type != 2)
    261   1.1  joerg 					is_true = 1;
    262   1.1  joerg 			} else if (expr_type == 2) {
    263   1.1  joerg 				is_true = 0;
    264   1.1  joerg 			}
    265   1.1  joerg 
    266   1.1  joerg 			license += len;
    267   1.1  joerg 
    268   1.1  joerg 			len = strspn(license, license_spaces);
    269   1.2   adam 			if (len == 0 && *license && *license  != ')') {
    270   1.2   adam 				warnx("Missing space at position %" PRIzu, license - start + 1);
    271   1.1  joerg 				return -1;
    272   1.2   adam 			}
    273   1.1  joerg 			license += len;
    274   1.1  joerg 		}
    275   1.1  joerg 
    276   1.1  joerg 		if (*license == ')') {
    277   1.2   adam 			if (!need_parenthesis) {
    278   1.2   adam 				warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
    279   1.1  joerg 				return -1;
    280   1.2   adam 			}
    281   1.1  joerg 			*licensep = license + 1;
    282   1.1  joerg 			return is_true;
    283   1.1  joerg 		}
    284   1.1  joerg 		if (*license == '\0') {
    285   1.2   adam 			if (need_parenthesis) {
    286   1.2   adam 				warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
    287   1.1  joerg 				return -1;
    288   1.2   adam 			}
    289   1.1  joerg 			*licensep = license;
    290   1.1  joerg 			return is_true;
    291   1.1  joerg 		}
    292   1.1  joerg 
    293   1.1  joerg 		if (strncmp(license, "AND", 3) == 0) {
    294   1.2   adam 			if (expr_type == 1) {
    295   1.2   adam 				warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
    296   1.1  joerg 				return -1;
    297   1.2   adam 			}
    298   1.1  joerg 			expr_type = 2;
    299   1.1  joerg 			license += 3;
    300   1.1  joerg 		} else if (strncmp(license, "OR", 2) == 0) {
    301   1.2   adam 			if (expr_type == 2) {
    302   1.2   adam 				warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
    303   1.1  joerg 				return -1;
    304   1.2   adam 			}
    305   1.1  joerg 			expr_type = 1;
    306   1.1  joerg 			license += 2;
    307   1.1  joerg 		} else {
    308   1.2   adam 			warnx("Invalid operator at position %" PRIzu, license - start + 1);
    309   1.1  joerg 			return -1;
    310   1.1  joerg 		}
    311   1.1  joerg 		len = strspn(license, license_spaces);
    312   1.2   adam 		if (len == 0 && *license != '(') {
    313   1.2   adam 			warnx("Missing space at position %" PRIzu, license - start + 1);
    314   1.1  joerg 			return -1;
    315   1.2   adam 		}
    316   1.1  joerg 		license += len;
    317   1.1  joerg 	}
    318   1.1  joerg }
    319   1.1  joerg 
    320   1.1  joerg int
    321   1.1  joerg acceptable_pkg_license(const char *license)
    322   1.1  joerg {
    323   1.1  joerg 	int ret;
    324   1.1  joerg 
    325   1.2   adam 	ret = acceptable_pkg_license_internal(&license, 1, license);
    326   1.1  joerg 	if (ret == -1)
    327   1.1  joerg 		return -1;
    328   1.1  joerg 	license += strspn(license, license_spaces);
    329   1.2   adam 	if (*license) {
    330   1.2   adam 		warnx("Trailing garbage in license specification");
    331   1.1  joerg 		return -1;
    332   1.2   adam 	}
    333   1.1  joerg 	return ret;
    334   1.1  joerg }
    335   1.1  joerg 
    336   1.1  joerg void
    337   1.1  joerg load_license_lists(void)
    338   1.1  joerg {
    339   1.1  joerg 	if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
    340   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
    341   1.1  joerg 	if (add_licenses(acceptable_licenses))
    342   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
    343   1.1  joerg 	if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
    344   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
    345   1.1  joerg 	if (add_licenses(default_acceptable_licenses))
    346   1.1  joerg 		errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
    347   1.1  joerg }
    348