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