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