setfacl.c revision 74465
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 * $FreeBSD: head/bin/setfacl/setfacl.c 74465 2001-03-19 18:09:25Z rwatson $
2774465Srwatson */
2874465Srwatson
2974465Srwatson#include <sys/types.h>
3074465Srwatson#include <sys/param.h>
3174465Srwatson#include <sys/stat.h>
3274465Srwatson#include <sys/acl.h>
3374465Srwatson#include <sys/queue.h>
3474465Srwatson
3574465Srwatson#include <err.h>
3674465Srwatson#include <stdio.h>
3774465Srwatson#include <stdlib.h>
3874465Srwatson#include <string.h>
3974465Srwatson#include <sysexits.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;
5974465Srwatson	STAILQ_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);
7074465Srwatson		return NULL;
7174465Srwatson	}
7274465Srwatson
7374465Srwatson	acl = zmalloc(sizeof(acl_t) * 2);
7474465Srwatson	acl[0] = acl_get_file(filename, ACL_TYPE_ACCESS);
7574465Srwatson	if (!acl[0])
7674465Srwatson		err(EX_OSERR, "acl_get_file() failed");
7774465Srwatson	if (S_ISDIR(sb.st_mode)) {
7874465Srwatson		acl[1] = acl_get_file(filename, ACL_TYPE_DEFAULT);
7974465Srwatson		if (!acl[1])
8074465Srwatson			err(EX_OSERR, "acl_get_file() failed");
8174465Srwatson	} else
8274465Srwatson		acl[1] = NULL;
8374465Srwatson
8474465Srwatson	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");
9374465Srwatson	exit(EX_USAGE);
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
10974465Srwatson	STAILQ_INIT(&entrylist);
11074465Srwatson	STAILQ_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);
11774465Srwatson			if (!entry->acl)
11874465Srwatson				err(EX_OSERR, "get_acl_from_file() failed");
11974465Srwatson			entry->op = OP_MERGE_ACL;
12074465Srwatson			STAILQ_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;
12674465Srwatson			STAILQ_INSERT_TAIL(&entrylist, entry, next);
12774465Srwatson			break;
12874465Srwatson		case 'b':
12974465Srwatson			entry = zmalloc(sizeof(struct sf_entry));
13074465Srwatson			entry->op = OP_REMOVE_EXT;
13174465Srwatson			STAILQ_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;
13974465Srwatson			STAILQ_INSERT_TAIL(&entrylist, entry, next);
14074465Srwatson			break;
14174465Srwatson		case 'm':
14274465Srwatson			entry = zmalloc(sizeof(struct sf_entry));
14374465Srwatson			entry->acl = acl_from_text(optarg);
14474465Srwatson			if (!entry->acl)
14574465Srwatson				err(EX_USAGE, "acl_from_text() failed");
14674465Srwatson			entry->op = OP_MERGE_ACL;
14774465Srwatson			STAILQ_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);
15574465Srwatson			if (!entry->acl)
15674465Srwatson				err(EX_USAGE, "acl_from_text() failed");
15774465Srwatson			entry->op = OP_REMOVE_ACL;
15874465Srwatson			STAILQ_INSERT_TAIL(&entrylist, entry, next);
15974465Srwatson			break;
16074465Srwatson		default:
16174465Srwatson			usage();
16274465Srwatson			break;
16374465Srwatson		}
16474465Srwatson	argc -= optind;
16574465Srwatson	argv += optind;
16674465Srwatson
16774465Srwatson	if (STAILQ_EMPTY(&entrylist))
16874465Srwatson		usage();
16974465Srwatson
17074465Srwatson	/* take list of files from stdin */
17174465Srwatson	if (argc == 0 || !strcmp(argv[0], "-")) {
17274465Srwatson		if (have_stdin)
17374465Srwatson			err(EX_USAGE, "cannot have more than one stdin");
17474465Srwatson		have_stdin = 1;
17574465Srwatson		bzero(&filename, sizeof(filename));
17674465Srwatson		while (fgets(filename, 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 */
18674465Srwatson	STAILQ_FOREACH(file, &filelist, next) {
18774465Srwatson		/* get our initial access and default ACL's */
18874465Srwatson		acl = get_file_acls(file->filename);
18974465Srwatson		if (!acl)
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 */
19974465Srwatson		STAILQ_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			/* NOTREACHED */
22574465Srwatson			}
22674465Srwatson		}
22774465Srwatson
22874465Srwatson		/* don't bother setting the ACL if something is broken */
22974465Srwatson		if (local_error) {
23074465Srwatson			carried_error++;
23174465Srwatson			continue;
23274465Srwatson		}
23374465Srwatson
23474465Srwatson		if (acl_type == ACL_TYPE_ACCESS)
23574465Srwatson			final_acl = acl[0];
23674465Srwatson		else
23774465Srwatson			final_acl = acl[1];
23874465Srwatson
23974465Srwatson		if (need_mask && (set_acl_mask(final_acl) == -1)) {
24074465Srwatson			warnx("failed to set ACL mask on %s", file->filename);
24174465Srwatson			carried_error++;
24274465Srwatson		} else if (acl_set_file(file->filename, acl_type,
24374465Srwatson		    final_acl) == -1) {
24474465Srwatson			carried_error++;
24574465Srwatson			warn("acl_set_file() failed for %s", file->filename);
24674465Srwatson		}
24774465Srwatson
24874465Srwatson		acl_free(acl[0]);
24974465Srwatson		acl_free(acl[1]);
25074465Srwatson		free(acl);
25174465Srwatson	}
25274465Srwatson
25374465Srwatson	return carried_error;
25474465Srwatson}
255