/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1992, 19934* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031#include <sys/param.h>32#include <sys/stat.h>3334#include <db.h>35#include <err.h>36#include <fcntl.h>37#include <stdio.h>38#include <stdlib.h>39#include <string.h>40#include <unistd.h>4142static void db_build(char **);43static void dounlink(void);44static void usage(void);4546static DB *capdbp;47static int verbose;48static char *capname, buf[8 * 1024];4950static HASHINFO openinfo = {514096, /* bsize */520, /* ffactor */530, /* nelem */540, /* cachesize */55NULL, /* hash() */560 /* lorder */57};5859/*60* Mkcapdb creates a capability hash database for quick retrieval of capability61* records. The database contains 2 types of entries: records and references62* marked by the first byte in the data. A record entry contains the actual63* capability record whereas a reference contains the name (key) under which64* the correct record is stored.65*/66int67main(int argc, char *argv[])68{69int byteorder, c;7071capname = NULL;72byteorder = 0;73while ((c = getopt(argc, argv, "bf:lv")) != -1) {74switch(c) {75case 'b':76case 'l':77if (byteorder != 0)78usage();79byteorder = c == 'b' ? 4321 : 1234;80break;81case 'f':82capname = optarg;83break;84case 'v':85verbose = 1;86break;87case '?':88default:89usage();90}91}92argc -= optind;93argv += optind;9495if (*argv == NULL)96usage();9798/* Set byte order. */99openinfo.lorder = byteorder;100101/*102* The database file is the first argument if no name is specified.103* Make arrangements to unlink it if exit badly.104*/105(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);106if ((capname = strdup(buf)) == NULL)107errx(1, "strdup failed");108if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,109DEFFILEMODE, DB_HASH, &openinfo)) == NULL)110err(1, "%s", buf);111112if (atexit(dounlink))113err(1, "atexit");114115db_build(argv);116117if (capdbp->close(capdbp) < 0)118err(1, "%s", capname);119capname = NULL;120exit(0);121}122123static void124dounlink(void)125{126if (capname != NULL)127(void)unlink(capname);128}129130/*131* Any changes to these definitions should be made also in the getcap(3)132* library routines.133*/134#define RECOK (char)0135#define TCERR (char)1136#define SHADOW (char)2137138/*139* Db_build() builds the name and capability databases according to the140* details above.141*/142static void143db_build(char **ifiles)144{145DBT key, data;146recno_t reccnt;147size_t len, bplen;148int st;149char *bp, *p, *t;150151data.data = NULL;152key.data = NULL;153for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {154155/*156* Allocate enough memory to store record, terminating157* NULL and one extra byte.158*/159len = strlen(bp);160if (bplen <= len + 2) {161bplen += MAX(256, len + 2);162if ((data.data = realloc(data.data, bplen)) == NULL)163errx(1, "malloc failed");164}165166/* Find the end of the name field. */167if ((p = strchr(bp, ':')) == NULL) {168warnx("no name field: %.*s", (int)MIN(len, 20), bp);169continue;170}171172/* First byte of stored record indicates status. */173switch(st) {174case 1:175((char *)(data.data))[0] = RECOK;176break;177case 2:178((char *)(data.data))[0] = TCERR;179warnx("record not tc expanded: %.*s", (int)(p - bp),180bp);181break;182}183184/* Create the stored record. */185memmove(&((u_char *)(data.data))[1], bp, len + 1);186data.size = len + 2;187188/* Store the record under the name field. */189key.data = bp;190key.size = p - bp;191192switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {193case -1:194err(1, "put");195/* NOTREACHED */196case 1:197warnx("ignored duplicate: %.*s",198(int)key.size, (char *)key.data);199continue;200}201++reccnt;202203/* If only one name, ignore the rest. */204*p = '\0';205if (strchr(bp, '|') == NULL)206continue;207*p = ':';208209/* The rest of the names reference the entire name. */210((char *)(data.data))[0] = SHADOW;211memmove(&((u_char *)(data.data))[1], key.data, key.size);212data.size = key.size + 1;213214/* Store references for other names. */215for (p = t = bp;; ++p) {216if (p > t && (*p == ':' || *p == '|')) {217key.size = p - t;218key.data = t;219switch(capdbp->put(capdbp,220&key, &data, R_NOOVERWRITE)) {221case -1:222err(1, "put");223/* NOTREACHED */224case 1:225warnx("ignored duplicate: %.*s",226(int)key.size, (char *)key.data);227}228t = p + 1;229}230if (*p == ':')231break;232}233}234235switch(st) {236case -1:237err(1, "file argument");238/* NOTREACHED */239case -2:240errx(1, "potential reference loop detected");241/* NOTREACHED */242}243244if (verbose)245(void)printf("cap_mkdb: %d capability records\n", reccnt);246}247248static void249usage(void)250{251(void)fprintf(stderr,252"usage: cap_mkdb [-b | -l] [-v] [-f outfile] file ...\n");253exit(1);254}255256257