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