setfacl.c revision 108450
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 108450 2002-12-30 15:36:29Z rwatson $"); 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); 74108450Srwatson if (h_flag) 75108450Srwatson acl[ACCESS_ACL] = acl_get_link_np(filename, ACL_TYPE_ACCESS); 76108450Srwatson else 77108450Srwatson acl[ACCESS_ACL] = acl_get_file(filename, ACL_TYPE_ACCESS); 7887259Sjedgar if (acl[ACCESS_ACL] == NULL) 7987254Sjedgar err(1, "acl_get_file() failed"); 8074465Srwatson if (S_ISDIR(sb.st_mode)) { 81108450Srwatson if (h_flag) 82108450Srwatson acl[DEFAULT_ACL] = acl_get_link_np(filename, 83108450Srwatson ACL_TYPE_DEFAULT); 84108450Srwatson else 85108450Srwatson acl[DEFAULT_ACL] = acl_get_file(filename, 86108450Srwatson ACL_TYPE_DEFAULT); 8787259Sjedgar if (acl[DEFAULT_ACL] == NULL) 8887254Sjedgar err(1, "acl_get_file() failed"); 8974465Srwatson } else 9087259Sjedgar acl[DEFAULT_ACL] = NULL; 9174465Srwatson 9287254Sjedgar return (acl); 9374465Srwatson} 9474465Srwatson 9574465Srwatsonstatic void 9674465Srwatsonusage(void) 9774465Srwatson{ 9874465Srwatson 99108450Srwatson fprintf(stderr, "usage: setfacl [-bdhknv] [-m entries] [-M file1] " 10074465Srwatson "[-x entries] [-X file2] [file ...]\n"); 10187254Sjedgar exit(1); 10274465Srwatson} 10374465Srwatson 10474465Srwatsonint 10574465Srwatsonmain(int argc, char *argv[]) 10674465Srwatson{ 10774465Srwatson acl_t *acl, final_acl; 10874465Srwatson char filename[PATH_MAX]; 10974465Srwatson int local_error, carried_error, ch, i; 11074465Srwatson struct sf_file *file; 11174465Srwatson struct sf_entry *entry; 11274465Srwatson 11374465Srwatson acl_type = ACL_TYPE_ACCESS; 11474465Srwatson carried_error = local_error = 0; 115108450Srwatson h_flag = have_mask = have_stdin = n_flag = need_mask = 0; 11674465Srwatson 11775928Sjedgar TAILQ_INIT(&entrylist); 11875928Sjedgar TAILQ_INIT(&filelist); 11974465Srwatson 120108450Srwatson while ((ch = getopt(argc, argv, "M:X:bdhkm:nx:")) != -1) 12174465Srwatson switch(ch) { 12274465Srwatson case 'M': 12374465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 12474465Srwatson entry->acl = get_acl_from_file(optarg); 12587254Sjedgar if (entry->acl == NULL) 12687254Sjedgar err(1, "get_acl_from_file() failed"); 12774465Srwatson entry->op = OP_MERGE_ACL; 12875928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 12974465Srwatson break; 13074465Srwatson case 'X': 13174465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 13274465Srwatson entry->acl = get_acl_from_file(optarg); 13374465Srwatson entry->op = OP_REMOVE_ACL; 13475928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 13574465Srwatson break; 13674465Srwatson case 'b': 13774465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 13874465Srwatson entry->op = OP_REMOVE_EXT; 13975928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 14074465Srwatson break; 14174465Srwatson case 'd': 14274465Srwatson acl_type = ACL_TYPE_DEFAULT; 14374465Srwatson break; 144108450Srwatson case 'h': 145108450Srwatson h_flag = 1; 146108450Srwatson break; 14774465Srwatson case 'k': 14874465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 14974465Srwatson entry->op = OP_REMOVE_DEF; 15075928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 15174465Srwatson break; 15274465Srwatson case 'm': 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_MERGE_ACL; 15875928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 15974465Srwatson break; 16074465Srwatson case 'n': 16174465Srwatson n_flag++; 16274465Srwatson break; 16374465Srwatson case 'x': 16474465Srwatson entry = zmalloc(sizeof(struct sf_entry)); 16574465Srwatson entry->acl = acl_from_text(optarg); 16687254Sjedgar if (entry->acl == NULL) 16787254Sjedgar err(1, "acl_from_text() failed"); 16874465Srwatson entry->op = OP_REMOVE_ACL; 16975928Sjedgar TAILQ_INSERT_TAIL(&entrylist, entry, next); 17074465Srwatson break; 17174465Srwatson default: 17274465Srwatson usage(); 17374465Srwatson break; 17474465Srwatson } 17574465Srwatson argc -= optind; 17674465Srwatson argv += optind; 17774465Srwatson 17887254Sjedgar if (n_flag == 0 && TAILQ_EMPTY(&entrylist)) 17974465Srwatson usage(); 18074465Srwatson 18174465Srwatson /* take list of files from stdin */ 18287254Sjedgar if (argc == 0 || strcmp(argv[0], "-") == 0) { 18374465Srwatson if (have_stdin) 18487254Sjedgar err(1, "cannot have more than one stdin"); 18574465Srwatson have_stdin = 1; 18674465Srwatson bzero(&filename, sizeof(filename)); 18776881Skris while (fgets(filename, (int)sizeof(filename), stdin)) { 18874465Srwatson /* remove the \n */ 18974465Srwatson filename[strlen(filename) - 1] = '\0'; 19074465Srwatson add_filename(filename); 19174465Srwatson } 19274465Srwatson } else 19374465Srwatson for (i = 0; i < argc; i++) 19474465Srwatson add_filename(argv[i]); 19574465Srwatson 19674465Srwatson /* cycle through each file */ 19775928Sjedgar TAILQ_FOREACH(file, &filelist, next) { 19874465Srwatson /* get our initial access and default ACL's */ 19974465Srwatson acl = get_file_acls(file->filename); 20087254Sjedgar if (acl == NULL) 20174465Srwatson continue; 20274465Srwatson if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) { 20374465Srwatson warnx("Default ACL not valid for %s", file->filename); 20474465Srwatson continue; 20574465Srwatson } 20674465Srwatson 20774465Srwatson local_error = 0; 20874465Srwatson 20974465Srwatson /* cycle through each option */ 21075928Sjedgar TAILQ_FOREACH(entry, &entrylist, next) { 21174465Srwatson if (local_error) 21274465Srwatson continue; 21374465Srwatson 21474465Srwatson switch(entry->op) { 21574465Srwatson case OP_MERGE_ACL: 21674465Srwatson local_error += merge_acl(entry->acl, acl); 21774465Srwatson need_mask = 1; 21874465Srwatson break; 21974465Srwatson case OP_REMOVE_EXT: 22074465Srwatson remove_ext(acl); 22174465Srwatson need_mask = 0; 22274465Srwatson break; 22374465Srwatson case OP_REMOVE_DEF: 22474465Srwatson if (acl_delete_def_file(file->filename) == -1) { 22574465Srwatson warn("acl_delete_def_file() failed"); 22674465Srwatson local_error++; 22774465Srwatson } 22874465Srwatson local_error += remove_default(acl); 22974465Srwatson need_mask = 0; 23074465Srwatson break; 23174465Srwatson case OP_REMOVE_ACL: 23274465Srwatson local_error += remove_acl(entry->acl, acl); 23374465Srwatson need_mask = 1; 23474465Srwatson break; 23574465Srwatson } 23674465Srwatson } 23774465Srwatson 23874465Srwatson /* don't bother setting the ACL if something is broken */ 23974465Srwatson if (local_error) { 24074465Srwatson carried_error++; 24174465Srwatson continue; 24274465Srwatson } 24374465Srwatson 24474465Srwatson if (acl_type == ACL_TYPE_ACCESS) 24587259Sjedgar final_acl = acl[ACCESS_ACL]; 24674465Srwatson else 24787259Sjedgar final_acl = acl[DEFAULT_ACL]; 24874465Srwatson 24975928Sjedgar if (need_mask && (set_acl_mask(&final_acl) == -1)) { 25074465Srwatson warnx("failed to set ACL mask on %s", file->filename); 25174465Srwatson carried_error++; 25274465Srwatson } else if (acl_set_file(file->filename, acl_type, 25374465Srwatson final_acl) == -1) { 25474465Srwatson carried_error++; 25574465Srwatson warn("acl_set_file() failed for %s", file->filename); 25674465Srwatson } 25774465Srwatson 25887259Sjedgar acl_free(acl[ACCESS_ACL]); 25987259Sjedgar acl_free(acl[DEFAULT_ACL]); 26074465Srwatson free(acl); 26174465Srwatson } 26274465Srwatson 26387254Sjedgar return (carried_error); 26474465Srwatson} 265