setfacl.c revision 75928
133965Sjdp/* 233965Sjdp * Copyright (c) 2001 Chris D. Faulhaber 3218822Sdim * All rights reserved. 433965Sjdp * 5218822Sdim * Redistribution and use in source and binary forms, with or without 633965Sjdp * modification, are permitted provided that the following conditions 733965Sjdp * are met: 8218822Sdim * 1. Redistributions of source code must retain the above copyright 9218822Sdim * notice, this list of conditions and the following disclaimer. 10218822Sdim * 2. Redistributions in binary form must reproduce the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer in the 12218822Sdim * documentation and/or other materials provided with the distribution. 13218822Sdim * 14218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16218822Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17218822Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE 18218822Sdim * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19218822Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20218822Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21218822Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22218822Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23218822Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24218822Sdim * POSSIBILITY OF SUCH DAMAGE. 25218822Sdim * 26218822Sdim * $FreeBSD: head/bin/setfacl/setfacl.c 75928 2001-04-24 22:45:41Z jedgar $ 27218822Sdim */ 28218822Sdim 29218822Sdim#include <sys/types.h> 30218822Sdim#include <sys/param.h> 31218822Sdim#include <sys/stat.h> 32218822Sdim#include <sys/acl.h> 33218822Sdim#include <sys/queue.h> 34218822Sdim 35218822Sdim#include <err.h> 36218822Sdim#include <stdio.h> 37218822Sdim#include <stdlib.h> 38218822Sdim#include <string.h> 39218822Sdim#include <sysexits.h> 40218822Sdim#include <unistd.h> 41218822Sdim 42218822Sdim#include "setfacl.h" 43218822Sdim 44218822Sdimstatic void add_filename(const char *filename); 45218822Sdimstatic acl_t *get_file_acls(const char *filename); 46218822Sdimstatic void usage(void); 47218822Sdim 48218822Sdimstatic void 49218822Sdimadd_filename(const char *filename) 50218822Sdim{ 51218822Sdim struct sf_file *file; 52218822Sdim 53218822Sdim if (strlen(filename) > PATH_MAX - 1) { 54218822Sdim warn("illegal filename"); 55218822Sdim return; 56218822Sdim } 57218822Sdim file = zmalloc(sizeof(struct sf_file)); 58218822Sdim file->filename = filename; 59218822Sdim TAILQ_INSERT_TAIL(&filelist, file, next); 60218822Sdim} 61218822Sdim 62218822Sdimstatic acl_t * 63218822Sdimget_file_acls(const char *filename) 64218822Sdim{ 65218822Sdim acl_t *acl; 66218822Sdim struct stat sb; 67218822Sdim 68218822Sdim if (stat(filename, &sb) == -1) { 69218822Sdim warn("stat() of %s failed", filename); 70218822Sdim return NULL; 71218822Sdim } 72218822Sdim 73218822Sdim acl = zmalloc(sizeof(acl_t) * 2); 74218822Sdim acl[0] = acl_get_file(filename, ACL_TYPE_ACCESS); 75218822Sdim if (!acl[0]) 76218822Sdim err(EX_OSERR, "acl_get_file() failed"); 77218822Sdim if (S_ISDIR(sb.st_mode)) { 78218822Sdim acl[1] = acl_get_file(filename, ACL_TYPE_DEFAULT); 79218822Sdim if (!acl[1]) 80218822Sdim err(EX_OSERR, "acl_get_file() failed"); 81218822Sdim } else 82218822Sdim acl[1] = NULL; 83218822Sdim 84218822Sdim return acl; 85218822Sdim} 86218822Sdim 87218822Sdimstatic void 88218822Sdimusage(void) 89218822Sdim{ 90218822Sdim 91218822Sdim fprintf(stderr, "usage: setfacl [-bdknv] [-m entries] [-M file1] " 92218822Sdim "[-x entries] [-X file2] [file ...]\n"); 93218822Sdim exit(EX_USAGE); 94218822Sdim} 95218822Sdim 96218822Sdimint 97218822Sdimmain(int argc, char *argv[]) 98218822Sdim{ 99218822Sdim acl_t *acl, final_acl; 100218822Sdim char filename[PATH_MAX]; 101218822Sdim int local_error, carried_error, ch, i; 102218822Sdim struct sf_file *file; 103218822Sdim struct sf_entry *entry; 104218822Sdim 105218822Sdim acl_type = ACL_TYPE_ACCESS; 106218822Sdim carried_error = local_error = 0; 107218822Sdim have_mask = have_stdin = n_flag = need_mask = 0; 108218822Sdim 109218822Sdim TAILQ_INIT(&entrylist); 110218822Sdim TAILQ_INIT(&filelist); 111218822Sdim 112218822Sdim while ((ch = getopt(argc, argv, "M:X:bdkm:nx:")) != -1) 113218822Sdim switch(ch) { 114218822Sdim case 'M': 115218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 116218822Sdim entry->acl = get_acl_from_file(optarg); 117218822Sdim if (!entry->acl) 118218822Sdim err(EX_OSERR, "get_acl_from_file() failed"); 119218822Sdim entry->op = OP_MERGE_ACL; 120218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 121218822Sdim break; 122218822Sdim case 'X': 123218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 124218822Sdim entry->acl = get_acl_from_file(optarg); 125218822Sdim entry->op = OP_REMOVE_ACL; 126218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 127218822Sdim break; 128218822Sdim case 'b': 129218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 130218822Sdim entry->op = OP_REMOVE_EXT; 131218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 132218822Sdim break; 133218822Sdim case 'd': 134218822Sdim acl_type = ACL_TYPE_DEFAULT; 135218822Sdim break; 136218822Sdim case 'k': 137218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 138218822Sdim entry->op = OP_REMOVE_DEF; 139218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 140218822Sdim break; 141218822Sdim case 'm': 142218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 143218822Sdim entry->acl = acl_from_text(optarg); 144218822Sdim if (!entry->acl) 145218822Sdim err(EX_USAGE, "acl_from_text() failed"); 146218822Sdim entry->op = OP_MERGE_ACL; 147218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 148218822Sdim break; 149218822Sdim case 'n': 150218822Sdim n_flag++; 151218822Sdim break; 152218822Sdim case 'x': 153218822Sdim entry = zmalloc(sizeof(struct sf_entry)); 154218822Sdim entry->acl = acl_from_text(optarg); 155218822Sdim if (!entry->acl) 156218822Sdim err(EX_USAGE, "acl_from_text() failed"); 157218822Sdim entry->op = OP_REMOVE_ACL; 158218822Sdim TAILQ_INSERT_TAIL(&entrylist, entry, next); 159218822Sdim break; 160218822Sdim default: 161218822Sdim usage(); 162218822Sdim break; 163218822Sdim } 164218822Sdim argc -= optind; 165218822Sdim argv += optind; 166218822Sdim 167218822Sdim if (!n_flag && TAILQ_EMPTY(&entrylist)) 168218822Sdim usage(); 169218822Sdim 170218822Sdim /* take list of files from stdin */ 171218822Sdim if (argc == 0 || !strcmp(argv[0], "-")) { 172218822Sdim if (have_stdin) 173218822Sdim err(EX_USAGE, "cannot have more than one stdin"); 174218822Sdim have_stdin = 1; 175218822Sdim bzero(&filename, sizeof(filename)); 176218822Sdim while (fgets(filename, sizeof(filename), stdin)) { 177218822Sdim /* remove the \n */ 178218822Sdim filename[strlen(filename) - 1] = '\0'; 179218822Sdim add_filename(filename); 180218822Sdim } 181218822Sdim } else 182218822Sdim for (i = 0; i < argc; i++) 183218822Sdim add_filename(argv[i]); 184218822Sdim 185218822Sdim /* cycle through each file */ 186218822Sdim TAILQ_FOREACH(file, &filelist, next) { 187218822Sdim /* get our initial access and default ACL's */ 188218822Sdim acl = get_file_acls(file->filename); 189218822Sdim if (!acl) 190218822Sdim continue; 191218822Sdim if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) { 192218822Sdim warnx("Default ACL not valid for %s", file->filename); 193218822Sdim continue; 194218822Sdim } 195218822Sdim 196218822Sdim local_error = 0; 197218822Sdim 198218822Sdim /* cycle through each option */ 199218822Sdim TAILQ_FOREACH(entry, &entrylist, next) { 200218822Sdim if (local_error) 201218822Sdim continue; 202218822Sdim 203218822Sdim switch(entry->op) { 204218822Sdim case OP_MERGE_ACL: 205218822Sdim local_error += merge_acl(entry->acl, acl); 206218822Sdim need_mask = 1; 207218822Sdim break; 208218822Sdim case OP_REMOVE_EXT: 209218822Sdim remove_ext(acl); 210218822Sdim need_mask = 0; 211218822Sdim break; 212218822Sdim case OP_REMOVE_DEF: 213218822Sdim if (acl_delete_def_file(file->filename) == -1) { 214218822Sdim warn("acl_delete_def_file() failed"); 215218822Sdim local_error++; 216218822Sdim } 217218822Sdim local_error += remove_default(acl); 218218822Sdim need_mask = 0; 219218822Sdim break; 220218822Sdim case OP_REMOVE_ACL: 221218822Sdim local_error += remove_acl(entry->acl, acl); 222218822Sdim need_mask = 1; 223218822Sdim break; 224218822Sdim /* NOTREACHED */ 225218822Sdim } 226218822Sdim } 227218822Sdim 228218822Sdim /* don't bother setting the ACL if something is broken */ 229218822Sdim if (local_error) { 230218822Sdim carried_error++; 231218822Sdim continue; 232218822Sdim } 233218822Sdim 234218822Sdim if (acl_type == ACL_TYPE_ACCESS) 235218822Sdim final_acl = acl[0]; 236218822Sdim else 237218822Sdim final_acl = acl[1]; 238218822Sdim 239218822Sdim if (need_mask && (set_acl_mask(&final_acl) == -1)) { 240218822Sdim warnx("failed to set ACL mask on %s", file->filename); 241218822Sdim carried_error++; 242218822Sdim } else if (acl_set_file(file->filename, acl_type, 243218822Sdim final_acl) == -1) { 244218822Sdim carried_error++; 245218822Sdim warn("acl_set_file() failed for %s", file->filename); 246218822Sdim } 247218822Sdim 248218822Sdim acl_free(acl[0]); 249218822Sdim acl_free(acl[1]); 250218822Sdim free(acl); 251218822Sdim } 252218822Sdim 253218822Sdim return carried_error; 254218822Sdim} 255218822Sdim