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