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