setfacl.c revision 99110
174465Srwatson/* 274465Srwatson * Copyright (c) 2001 Chris D. Faulhaber 374465Srwatson * All rights reserved. 474465Srwatson * 574465Srwatson * Redistribution and use in source and binary forms, with or without 674465Srwatson * modification, are permitted provided that the following conditions 774465Srwatson * are met: 874465Srwatson * 1. Redistributions of source code must retain the above copyright 974465Srwatson * notice, this list of conditions and the following disclaimer. 1074465Srwatson * 2. Redistributions in binary form must reproduce the above copyright 1174465Srwatson * notice, this list of conditions and the following disclaimer in the 1274465Srwatson * documentation and/or other materials provided with the distribution. 1374465Srwatson * 1474465Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1574465Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1674465Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1774465Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE 1874465Srwatson * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1974465Srwatson * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2074465Srwatson * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2174465Srwatson * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2274465Srwatson * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2374465Srwatson * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2474465Srwatson * POSSIBILITY OF SUCH DAMAGE. 2574465Srwatson */ 2674465Srwatson 2799110Sobrien#include <sys/cdefs.h> 2899110Sobrien__FBSDID("$FreeBSD: head/bin/setfacl/setfacl.c 99110 2002-06-30 05:15:05Z obrien $"); 2999110Sobrien 3074465Srwatson#include <sys/types.h> 3174465Srwatson#include <sys/param.h> 3274465Srwatson#include <sys/stat.h> 3374465Srwatson#include <sys/acl.h> 3474465Srwatson#include <sys/queue.h> 3574465Srwatson 3674465Srwatson#include <err.h> 3774465Srwatson#include <stdio.h> 3874465Srwatson#include <stdlib.h> 3974465Srwatson#include <string.h> 4074465Srwatson#include <unistd.h> 4174465Srwatson 4274465Srwatson#include "setfacl.h" 4374465Srwatson 4474465Srwatsonstatic void add_filename(const char *filename); 4574465Srwatsonstatic acl_t *get_file_acls(const char *filename); 4674465Srwatsonstatic void usage(void); 4774465Srwatson 4874465Srwatsonstatic void 4974465Srwatsonadd_filename(const char *filename) 5074465Srwatson{ 5174465Srwatson struct sf_file *file; 5274465Srwatson 5374465Srwatson if (strlen(filename) > PATH_MAX - 1) { 5474465Srwatson warn("illegal filename"); 5574465Srwatson return; 5674465Srwatson } 5774465Srwatson file = zmalloc(sizeof(struct sf_file)); 5874465Srwatson file->filename = filename; 5975928Sjedgar TAILQ_INSERT_TAIL(&filelist, file, next); 6074465Srwatson} 6174465Srwatson 6274465Srwatsonstatic acl_t * 6374465Srwatsonget_file_acls(const char *filename) 6474465Srwatson{ 6574465Srwatson acl_t *acl; 6674465Srwatson struct stat sb; 6774465Srwatson 6874465Srwatson if (stat(filename, &sb) == -1) { 6974465Srwatson warn("stat() of %s failed", filename); 7087254Sjedgar return (NULL); 7174465Srwatson } 7274465Srwatson 7374465Srwatson acl = zmalloc(sizeof(acl_t) * 2); 7487259Sjedgar acl[ACCESS_ACL] = acl_get_file(filename, ACL_TYPE_ACCESS); 7587259Sjedgar if (acl[ACCESS_ACL] == NULL) 7687254Sjedgar err(1, "acl_get_file() failed"); 7774465Srwatson if (S_ISDIR(sb.st_mode)) { 7887259Sjedgar acl[DEFAULT_ACL] = acl_get_file(filename, ACL_TYPE_DEFAULT); 7987259Sjedgar if (acl[DEFAULT_ACL] == NULL) 8087254Sjedgar err(1, "acl_get_file() failed"); 8174465Srwatson } else 8287259Sjedgar acl[DEFAULT_ACL] = NULL; 8374465Srwatson 8487254Sjedgar return (acl); 8574465Srwatson} 8674465Srwatson 8774465Srwatsonstatic void 8874465Srwatsonusage(void) 8974465Srwatson{ 9074465Srwatson 9174465Srwatson fprintf(stderr, "usage: setfacl [-bdknv] [-m entries] [-M file1] " 9274465Srwatson "[-x entries] [-X file2] [file ...]\n"); 9387254Sjedgar exit(1); 9474465Srwatson} 9574465Srwatson 9674465Srwatsonint 9774465Srwatsonmain(int argc, char *argv[]) 9874465Srwatson{ 9974465Srwatson acl_t *acl, final_acl; 10074465Srwatson char filename[PATH_MAX]; 10174465Srwatson int local_error, carried_error, ch, i; 10274465Srwatson struct sf_file *file; 10374465Srwatson struct sf_entry *entry; 10474465Srwatson 10574465Srwatson acl_type = ACL_TYPE_ACCESS; 10674465Srwatson carried_error = local_error = 0; 10774465Srwatson have_mask = have_stdin = n_flag = need_mask = 0; 10874465Srwatson 10975928Sjedgar TAILQ_INIT(&entrylist); 11075928Sjedgar TAILQ_INIT(&filelist); 11174465Srwatson 11274465Srwatson while ((ch = getopt(argc, argv, "M:X:bdkm:nx:")) != -1) 11374465Srwatson switch(ch) { 11474465Srwatson case 'M': 11574465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 11674465Srwatson entry->acl = get_acl_from_file(optarg); 11787254Sjedgar if (entry->acl == NULL) 11887254Sjedgar err(1, "get_acl_from_file() failed"); 11974465Srwatson entry->op = OP_MERGE_ACL; 12075928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 12174465Srwatson break; 12274465Srwatson case 'X': 12374465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 12474465Srwatson entry->acl = get_acl_from_file(optarg); 12574465Srwatson entry->op = OP_REMOVE_ACL; 12675928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 12774465Srwatson break; 12874465Srwatson case 'b': 12974465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 13074465Srwatson entry->op = OP_REMOVE_EXT; 13175928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 13274465Srwatson break; 13374465Srwatson case 'd': 13474465Srwatson acl_type = ACL_TYPE_DEFAULT; 13574465Srwatson break; 13674465Srwatson case 'k': 13774465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 13874465Srwatson entry->op = OP_REMOVE_DEF; 13975928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 14074465Srwatson break; 14174465Srwatson case 'm': 14274465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 14374465Srwatson entry->acl = acl_from_text(optarg); 14487254Sjedgar if (entry->acl == NULL) 14587254Sjedgar err(1, "acl_from_text() failed"); 14674465Srwatson entry->op = OP_MERGE_ACL; 14775928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 14874465Srwatson break; 14974465Srwatson case 'n': 15074465Srwatson n_flag++; 15174465Srwatson break; 15274465Srwatson case 'x': 15374465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 15474465Srwatson entry->acl = acl_from_text(optarg); 15587254Sjedgar if (entry->acl == NULL) 15687254Sjedgar err(1, "acl_from_text() failed"); 15774465Srwatson entry->op = OP_REMOVE_ACL; 15875928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 15974465Srwatson break; 16074465Srwatson default: 16174465Srwatson usage(); 16274465Srwatson break; 16374465Srwatson } 16474465Srwatson argc -= optind; 16574465Srwatson argv += optind; 16674465Srwatson 16787254Sjedgar if (n_flag == 0 && TAILQ_EMPTY(&entrylist)) 16874465Srwatson usage(); 16974465Srwatson 17074465Srwatson /* take list of files from stdin */ 17187254Sjedgar if (argc == 0 || strcmp(argv[0], "-") == 0) { 17274465Srwatson if (have_stdin) 17387254Sjedgar err(1, "cannot have more than one stdin"); 17474465Srwatson have_stdin = 1; 17574465Srwatson bzero(&filename, sizeof(filename)); 17676881Skris while (fgets(filename, (int)sizeof(filename), stdin)) { 17774465Srwatson /* remove the \n */ 17874465Srwatson filename[strlen(filename) - 1] = '\0'; 17974465Srwatson add_filename(filename); 18074465Srwatson } 18174465Srwatson } else 18274465Srwatson for (i = 0; i < argc; i++) 18374465Srwatson add_filename(argv[i]); 18474465Srwatson 18574465Srwatson /* cycle through each file */ 18675928Sjedgar TAILQ_FOREACH(file, &filelist, next) { 18774465Srwatson /* get our initial access and default ACL's */ 18874465Srwatson acl = get_file_acls(file->filename); 18987254Sjedgar if (acl == NULL) 19074465Srwatson continue; 19174465Srwatson if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) { 19274465Srwatson warnx("Default ACL not valid for %s", file->filename); 19374465Srwatson continue; 19474465Srwatson } 19574465Srwatson 19674465Srwatson local_error = 0; 19774465Srwatson 19874465Srwatson /* cycle through each option */ 19975928Sjedgar TAILQ_FOREACH(entry, &entrylist, next) { 20074465Srwatson if (local_error) 20174465Srwatson continue; 20274465Srwatson 20374465Srwatson switch(entry->op) { 20474465Srwatson case OP_MERGE_ACL: 20574465Srwatson local_error += merge_acl(entry->acl, acl); 20674465Srwatson need_mask = 1; 20774465Srwatson break; 20874465Srwatson case OP_REMOVE_EXT: 20974465Srwatson remove_ext(acl); 21074465Srwatson need_mask = 0; 21174465Srwatson break; 21274465Srwatson case OP_REMOVE_DEF: 21374465Srwatson if (acl_delete_def_file(file->filename) == -1) { 21474465Srwatson warn("acl_delete_def_file() failed"); 21574465Srwatson local_error++; 21674465Srwatson } 21774465Srwatson local_error += remove_default(acl); 21874465Srwatson need_mask = 0; 21974465Srwatson break; 22074465Srwatson case OP_REMOVE_ACL: 22174465Srwatson local_error += remove_acl(entry->acl, acl); 22274465Srwatson need_mask = 1; 22374465Srwatson break; 22474465Srwatson } 22574465Srwatson } 22674465Srwatson 22774465Srwatson /* don't bother setting the ACL if something is broken */ 22874465Srwatson if (local_error) { 22974465Srwatson carried_error++; 23074465Srwatson continue; 23174465Srwatson } 23274465Srwatson 23374465Srwatson if (acl_type == ACL_TYPE_ACCESS) 23487259Sjedgar final_acl = acl[ACCESS_ACL]; 23574465Srwatson else 23687259Sjedgar final_acl = acl[DEFAULT_ACL]; 23774465Srwatson 23875928Sjedgar if (need_mask && (set_acl_mask(&final_acl) == -1)) { 23974465Srwatson warnx("failed to set ACL mask on %s", file->filename); 24074465Srwatson carried_error++; 24174465Srwatson } else if (acl_set_file(file->filename, acl_type, 24274465Srwatson final_acl) == -1) { 24374465Srwatson carried_error++; 24474465Srwatson warn("acl_set_file() failed for %s", file->filename); 24574465Srwatson } 24674465Srwatson 24787259Sjedgar acl_free(acl[ACCESS_ACL]); 24887259Sjedgar acl_free(acl[DEFAULT_ACL]); 24974465Srwatson free(acl); 25074465Srwatson } 25174465Srwatson 25287254Sjedgar return (carried_error); 25374465Srwatson} 254