174465Srwatson/*-
2108450Srwatson * Copyright (c) 1999, 2001, 2002 Robert N M Watson
374465Srwatson * All rights reserved.
474465Srwatson *
586458Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
686458Srwatson *
774465Srwatson * Redistribution and use in source and binary forms, with or without
874465Srwatson * modification, are permitted provided that the following conditions
974465Srwatson * are met:
1074465Srwatson * 1. Redistributions of source code must retain the above copyright
1174465Srwatson *    notice, this list of conditions and the following disclaimer.
1274465Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1374465Srwatson *    notice, this list of conditions and the following disclaimer in the
1474465Srwatson *    documentation and/or other materials provided with the distribution.
1574465Srwatson *
1674465Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1774465Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874465Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974465Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2074465Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2174465Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2274465Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2374465Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2474465Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2574465Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2674465Srwatson * SUCH DAMAGE.
2774465Srwatson */
2874465Srwatson/*
2974465Srwatson * getfacl -- POSIX.1e utility to extract ACLs from files and directories
3074465Srwatson * and send the results to stdout
3174465Srwatson */
3274465Srwatson
3399109Sobrien
3499109Sobrien#include <sys/cdefs.h>
3599109Sobrien__FBSDID("$FreeBSD$");
3699109Sobrien
3774465Srwatson#include <sys/types.h>
3874465Srwatson#include <sys/param.h>
3974465Srwatson#include <sys/acl.h>
4074465Srwatson#include <sys/stat.h>
4199109Sobrien
4274465Srwatson#include <err.h>
4374465Srwatson#include <errno.h>
44172237Skevlo#include <grp.h>
45172237Skevlo#include <pwd.h>
4674465Srwatson#include <stdio.h>
4775491Sjedgar#include <stdlib.h>
4876875Skris#include <string.h>
4974465Srwatson#include <unistd.h>
5074465Srwatson
51241720Sedstatic int more_than_one = 0;
5274465Srwatson
5374465Srwatsonstatic void
5474465Srwatsonusage(void)
5574465Srwatson{
5674465Srwatson
57196827Strasz	fprintf(stderr, "getfacl [-dhnqv] [file ...]\n");
5874465Srwatson}
5974465Srwatson
60172237Skevlostatic char *
61172237Skevlogetuname(uid_t uid)
62172237Skevlo{
63172237Skevlo	struct passwd *pw;
64172237Skevlo	static char uids[10];
65172237Skevlo
66172237Skevlo	if ((pw = getpwuid(uid)) == NULL) {
67172237Skevlo		(void)snprintf(uids, sizeof(uids), "%u", uid);
68172237Skevlo		return (uids);
69172237Skevlo	} else
70172237Skevlo		return (pw->pw_name);
71172237Skevlo}
72172237Skevlo
73172237Skevlostatic char *
74172237Skevlogetgname(gid_t gid)
75172237Skevlo{
76172237Skevlo	struct group *gr;
77172237Skevlo	static char gids[10];
78172237Skevlo
79172237Skevlo	if ((gr = getgrgid(gid)) == NULL) {
80172237Skevlo		(void)snprintf(gids, sizeof(gids), "%u", gid);
81172237Skevlo		return (gids);
82172237Skevlo	} else
83172237Skevlo		return (gr->gr_name);
84172237Skevlo}
85172237Skevlo
8675491Sjedgar/*
8775491Sjedgar * return an ACL corresponding to the permissions
8875491Sjedgar * contained in struct stat
8975491Sjedgar */
9074465Srwatsonstatic acl_t
9174465Srwatsonacl_from_stat(struct stat sb)
9274465Srwatson{
9374465Srwatson	acl_t acl;
9475491Sjedgar	acl_entry_t entry;
9575491Sjedgar	acl_permset_t perms;
9674465Srwatson
9775491Sjedgar	/* create the ACL */
9874465Srwatson	acl = acl_init(3);
9974465Srwatson	if (!acl)
10075491Sjedgar		return NULL;
10174465Srwatson
10275491Sjedgar	/* First entry: ACL_USER_OBJ */
10375491Sjedgar	if (acl_create_entry(&acl, &entry) == -1)
10475491Sjedgar		return NULL;
10575491Sjedgar	if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
10675491Sjedgar		return NULL;
10775491Sjedgar
10875491Sjedgar	if (acl_get_permset(entry, &perms) == -1)
10975491Sjedgar		return NULL;
11075491Sjedgar	if (acl_clear_perms(perms) == -1)
11175491Sjedgar		return NULL;
11275491Sjedgar
11375491Sjedgar	/* calculate user mode */
11474465Srwatson	if (sb.st_mode & S_IRUSR)
11575491Sjedgar		if (acl_add_perm(perms, ACL_READ) == -1)
11675491Sjedgar			return NULL;
11774465Srwatson	if (sb.st_mode & S_IWUSR)
11875491Sjedgar		if (acl_add_perm(perms, ACL_WRITE) == -1)
11975491Sjedgar			return NULL;
12074465Srwatson	if (sb.st_mode & S_IXUSR)
12175491Sjedgar		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
12275491Sjedgar			return NULL;
12375491Sjedgar	if (acl_set_permset(entry, perms) == -1)
12475491Sjedgar		return NULL;
12574465Srwatson
12675491Sjedgar	/* Second entry: ACL_GROUP_OBJ */
12775491Sjedgar	if (acl_create_entry(&acl, &entry) == -1)
12875491Sjedgar		return NULL;
12975491Sjedgar	if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
13075491Sjedgar		return NULL;
13175491Sjedgar
13275491Sjedgar	if (acl_get_permset(entry, &perms) == -1)
13375491Sjedgar		return NULL;
13475491Sjedgar	if (acl_clear_perms(perms) == -1)
13575491Sjedgar		return NULL;
13675491Sjedgar
13775491Sjedgar	/* calculate group mode */
13874465Srwatson	if (sb.st_mode & S_IRGRP)
13975491Sjedgar		if (acl_add_perm(perms, ACL_READ) == -1)
14075491Sjedgar			return NULL;
14174465Srwatson	if (sb.st_mode & S_IWGRP)
14275491Sjedgar		if (acl_add_perm(perms, ACL_WRITE) == -1)
14375491Sjedgar			return NULL;
14474465Srwatson	if (sb.st_mode & S_IXGRP)
14575491Sjedgar		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
14675491Sjedgar			return NULL;
14775491Sjedgar	if (acl_set_permset(entry, perms) == -1)
14875491Sjedgar		return NULL;
14974465Srwatson
15075491Sjedgar	/* Third entry: ACL_OTHER */
15175491Sjedgar	if (acl_create_entry(&acl, &entry) == -1)
15275491Sjedgar		return NULL;
15375491Sjedgar	if (acl_set_tag_type(entry, ACL_OTHER) == -1)
15475491Sjedgar		return NULL;
15575491Sjedgar
15675491Sjedgar	if (acl_get_permset(entry, &perms) == -1)
15775491Sjedgar		return NULL;
15875491Sjedgar	if (acl_clear_perms(perms) == -1)
15975491Sjedgar		return NULL;
16075491Sjedgar
16175491Sjedgar	/* calculate other mode */
16274465Srwatson	if (sb.st_mode & S_IROTH)
16375491Sjedgar		if (acl_add_perm(perms, ACL_READ) == -1)
16475491Sjedgar			return NULL;
16574465Srwatson	if (sb.st_mode & S_IWOTH)
16675491Sjedgar		if (acl_add_perm(perms, ACL_WRITE) == -1)
16775491Sjedgar			return NULL;
16874465Srwatson	if (sb.st_mode & S_IXOTH)
16975491Sjedgar		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
17075491Sjedgar			return NULL;
17175491Sjedgar	if (acl_set_permset(entry, perms) == -1)
17275491Sjedgar		return NULL;
17374465Srwatson
17474465Srwatson	return(acl);
17574465Srwatson}
17674465Srwatson
17774465Srwatsonstatic int
178196827Straszprint_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
179196827Strasz    int qflag, int vflag)
18074465Srwatson{
18174465Srwatson	struct stat	sb;
18274465Srwatson	acl_t	acl;
18374465Srwatson	char	*acl_text;
184196827Strasz	int	error, flags = 0, ret;
18574465Srwatson
186108450Srwatson	if (hflag)
187108450Srwatson		error = lstat(path, &sb);
188108450Srwatson	else
189108450Srwatson		error = stat(path, &sb);
19074465Srwatson	if (error == -1) {
191196827Strasz		warn("%s: stat() failed", path);
19274465Srwatson		return(-1);
19374465Srwatson	}
19474465Srwatson
195196827Strasz	if (hflag)
196196827Strasz		ret = lpathconf(path, _PC_ACL_NFS4);
197196827Strasz	else
198196827Strasz		ret = pathconf(path, _PC_ACL_NFS4);
199196827Strasz	if (ret > 0) {
200196827Strasz		if (type == ACL_TYPE_DEFAULT) {
201196827Strasz			warnx("%s: there are no default entries in NFSv4 ACLs",
202196827Strasz			    path);
203196827Strasz			return (-1);
204196827Strasz		}
205196827Strasz		type = ACL_TYPE_NFS4;
206196827Strasz	} else if (ret < 0 && errno != EINVAL) {
207196827Strasz		warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
208196827Strasz		return (-1);
209196827Strasz	}
210196827Strasz
21174465Srwatson	if (more_than_one)
21274465Srwatson		printf("\n");
21374465Srwatson	else
21474465Srwatson		more_than_one++;
21574465Srwatson
216156681Srwatson	if (!qflag)
217172237Skevlo		printf("# file: %s\n# owner: %s\n# group: %s\n", path,
218172237Skevlo		    getuname(sb.st_uid), getgname(sb.st_gid));
21974465Srwatson
220108450Srwatson	if (hflag)
221108450Srwatson		acl = acl_get_link_np(path, type);
222108450Srwatson	else
223108450Srwatson		acl = acl_get_file(path, type);
22474465Srwatson	if (!acl) {
22574465Srwatson		if (errno != EOPNOTSUPP) {
22674465Srwatson			warn("%s", path);
22774465Srwatson			return(-1);
22874465Srwatson		}
22974465Srwatson		errno = 0;
230196827Strasz		if (type == ACL_TYPE_DEFAULT)
23174465Srwatson			return(0);
23274465Srwatson		acl = acl_from_stat(sb);
23374465Srwatson		if (!acl) {
234196827Strasz			warn("%s: acl_from_stat() failed", path);
23574465Srwatson			return(-1);
23674465Srwatson		}
23774465Srwatson	}
23874465Srwatson
239196827Strasz	if (iflag)
240196827Strasz		flags |= ACL_TEXT_APPEND_ID;
241196827Strasz
242196827Strasz	if (nflag)
243196827Strasz		flags |= ACL_TEXT_NUMERIC_IDS;
244196827Strasz
245196827Strasz	if (vflag)
246196827Strasz		flags |= ACL_TEXT_VERBOSE;
247196827Strasz
248196827Strasz	acl_text = acl_to_text_np(acl, 0, flags);
24974465Srwatson	if (!acl_text) {
250196827Strasz		warn("%s: acl_to_text_np() failed", path);
25174465Srwatson		return(-1);
25274465Srwatson	}
25374465Srwatson
25474465Srwatson	printf("%s", acl_text);
25574465Srwatson
25691083Smarkm	(void)acl_free(acl);
25791083Smarkm	(void)acl_free(acl_text);
25874465Srwatson
25974465Srwatson	return(0);
26074465Srwatson}
26174465Srwatson
26274465Srwatsonstatic int
263196827Straszprint_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
264196827Strasz    int qflag, int vflag)
26574465Srwatson{
266106388Stjr	char	*p, pathname[PATH_MAX];
26774465Srwatson	int	carried_error = 0;
26874465Srwatson
26976875Skris	while (fgets(pathname, (int)sizeof(pathname), stdin)) {
270106388Stjr		if ((p = strchr(pathname, '\n')) != NULL)
271106388Stjr			*p = '\0';
272196827Strasz		if (print_acl(pathname, type, hflag, iflag, nflag,
273196827Strasz		    qflag, vflag) == -1) {
27474465Srwatson			carried_error = -1;
27574465Srwatson		}
27674465Srwatson	}
27774465Srwatson
27874465Srwatson	return(carried_error);
27974465Srwatson}
28074465Srwatson
28174465Srwatsonint
28274465Srwatsonmain(int argc, char *argv[])
28374465Srwatson{
28474465Srwatson	acl_type_t	type = ACL_TYPE_ACCESS;
28574465Srwatson	int	carried_error = 0;
28674465Srwatson	int	ch, error, i;
287196827Strasz	int	hflag, iflag, qflag, nflag, vflag;
28874465Srwatson
289108450Srwatson	hflag = 0;
290196827Strasz	iflag = 0;
291156681Srwatson	qflag = 0;
292196827Strasz	nflag = 0;
293196827Strasz	vflag = 0;
294196827Strasz	while ((ch = getopt(argc, argv, "dhinqv")) != -1)
29574465Srwatson		switch(ch) {
29674465Srwatson		case 'd':
29774465Srwatson			type = ACL_TYPE_DEFAULT;
29874465Srwatson			break;
299108450Srwatson		case 'h':
300108450Srwatson			hflag = 1;
301108450Srwatson			break;
302196827Strasz		case 'i':
303196827Strasz			iflag = 1;
304196827Strasz			break;
305196827Strasz		case 'n':
306196827Strasz			nflag = 1;
307196827Strasz			break;
308156681Srwatson		case 'q':
309156681Srwatson			qflag = 1;
310156681Srwatson			break;
311196827Strasz		case 'v':
312196827Strasz			vflag = 1;
313196827Strasz			break;
31474465Srwatson		default:
31574465Srwatson			usage();
31674465Srwatson			return(-1);
31774465Srwatson		}
31874465Srwatson	argc -= optind;
31974465Srwatson	argv += optind;
32074465Srwatson
32174465Srwatson	if (argc == 0) {
322196827Strasz		error = print_acl_from_stdin(type, hflag, iflag, nflag,
323196827Strasz		    qflag, vflag);
324106388Stjr		return(error ? 1 : 0);
32574465Srwatson	}
32674465Srwatson
32774465Srwatson	for (i = 0; i < argc; i++) {
32874465Srwatson		if (!strcmp(argv[i], "-")) {
329196827Strasz			error = print_acl_from_stdin(type, hflag, iflag, nflag,
330196827Strasz			    qflag, vflag);
33174465Srwatson			if (error == -1)
33274465Srwatson				carried_error = -1;
33374465Srwatson		} else {
334196827Strasz			error = print_acl(argv[i], type, hflag, iflag, nflag,
335196827Strasz			    qflag, vflag);
33674465Srwatson			if (error == -1)
33774465Srwatson				carried_error = -1;
33874465Srwatson		}
33974465Srwatson	}
34074465Srwatson
341106388Stjr	return(carried_error ? 1 : 0);
34274465Srwatson}
343