xref: /freebsd/bin/getfacl/getfacl.c (revision ae824d80)
143960f15SRobert Watson /*-
28051fddeSRobert Watson  * Copyright (c) 1999, 2001, 2002 Robert N M Watson
343960f15SRobert Watson  * All rights reserved.
443960f15SRobert Watson  *
59331ef53SRobert Watson  * This software was developed by Robert Watson for the TrustedBSD Project.
69331ef53SRobert Watson  *
743960f15SRobert Watson  * Redistribution and use in source and binary forms, with or without
843960f15SRobert Watson  * modification, are permitted provided that the following conditions
943960f15SRobert Watson  * are met:
1043960f15SRobert Watson  * 1. Redistributions of source code must retain the above copyright
1143960f15SRobert Watson  *    notice, this list of conditions and the following disclaimer.
1243960f15SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
1343960f15SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
1443960f15SRobert Watson  *    documentation and/or other materials provided with the distribution.
1543960f15SRobert Watson  *
1643960f15SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1743960f15SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1843960f15SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1943960f15SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2043960f15SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2143960f15SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2243960f15SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2343960f15SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2443960f15SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2543960f15SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2643960f15SRobert Watson  * SUCH DAMAGE.
2743960f15SRobert Watson  */
2843960f15SRobert Watson /*
2943960f15SRobert Watson  * getfacl -- POSIX.1e utility to extract ACLs from files and directories
3043960f15SRobert Watson  * and send the results to stdout
3143960f15SRobert Watson  */
3243960f15SRobert Watson 
335eb43ac2SDavid E. O'Brien 
345eb43ac2SDavid E. O'Brien #include <sys/cdefs.h>
355eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$");
365eb43ac2SDavid E. O'Brien 
3743960f15SRobert Watson #include <sys/types.h>
3843960f15SRobert Watson #include <sys/param.h>
3943960f15SRobert Watson #include <sys/acl.h>
4043960f15SRobert Watson #include <sys/stat.h>
415eb43ac2SDavid E. O'Brien 
4243960f15SRobert Watson #include <err.h>
4343960f15SRobert Watson #include <errno.h>
44c5771451SKevin Lo #include <grp.h>
45c5771451SKevin Lo #include <pwd.h>
4643960f15SRobert Watson #include <stdio.h>
477a832d43SChris D. Faulhaber #include <stdlib.h>
4828bf3202SKris Kennaway #include <string.h>
4943960f15SRobert Watson #include <unistd.h>
5043960f15SRobert Watson 
51ae824d80SEd Schouten static int more_than_one = 0;
5243960f15SRobert Watson 
5343960f15SRobert Watson static void
5443960f15SRobert Watson usage(void)
5543960f15SRobert Watson {
5643960f15SRobert Watson 
5783bd4cd0SEdward Tomasz Napierala 	fprintf(stderr, "getfacl [-dhnqv] [file ...]\n");
5843960f15SRobert Watson }
5943960f15SRobert Watson 
60c5771451SKevin Lo static char *
61c5771451SKevin Lo getuname(uid_t uid)
62c5771451SKevin Lo {
63c5771451SKevin Lo 	struct passwd *pw;
64c5771451SKevin Lo 	static char uids[10];
65c5771451SKevin Lo 
66c5771451SKevin Lo 	if ((pw = getpwuid(uid)) == NULL) {
67c5771451SKevin Lo 		(void)snprintf(uids, sizeof(uids), "%u", uid);
68c5771451SKevin Lo 		return (uids);
69c5771451SKevin Lo 	} else
70c5771451SKevin Lo 		return (pw->pw_name);
71c5771451SKevin Lo }
72c5771451SKevin Lo 
73c5771451SKevin Lo static char *
74c5771451SKevin Lo getgname(gid_t gid)
75c5771451SKevin Lo {
76c5771451SKevin Lo 	struct group *gr;
77c5771451SKevin Lo 	static char gids[10];
78c5771451SKevin Lo 
79c5771451SKevin Lo 	if ((gr = getgrgid(gid)) == NULL) {
80c5771451SKevin Lo 		(void)snprintf(gids, sizeof(gids), "%u", gid);
81c5771451SKevin Lo 		return (gids);
82c5771451SKevin Lo 	} else
83c5771451SKevin Lo 		return (gr->gr_name);
84c5771451SKevin Lo }
85c5771451SKevin Lo 
867a832d43SChris D. Faulhaber /*
877a832d43SChris D. Faulhaber  * return an ACL corresponding to the permissions
887a832d43SChris D. Faulhaber  * contained in struct stat
897a832d43SChris D. Faulhaber  */
9043960f15SRobert Watson static acl_t
9143960f15SRobert Watson acl_from_stat(struct stat sb)
9243960f15SRobert Watson {
9343960f15SRobert Watson 	acl_t acl;
947a832d43SChris D. Faulhaber 	acl_entry_t entry;
957a832d43SChris D. Faulhaber 	acl_permset_t perms;
9643960f15SRobert Watson 
977a832d43SChris D. Faulhaber 	/* create the ACL */
9843960f15SRobert Watson 	acl = acl_init(3);
9943960f15SRobert Watson 	if (!acl)
1007a832d43SChris D. Faulhaber 		return NULL;
10143960f15SRobert Watson 
1027a832d43SChris D. Faulhaber 	/* First entry: ACL_USER_OBJ */
1037a832d43SChris D. Faulhaber 	if (acl_create_entry(&acl, &entry) == -1)
1047a832d43SChris D. Faulhaber 		return NULL;
1057a832d43SChris D. Faulhaber 	if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
1067a832d43SChris D. Faulhaber 		return NULL;
1077a832d43SChris D. Faulhaber 
1087a832d43SChris D. Faulhaber 	if (acl_get_permset(entry, &perms) == -1)
1097a832d43SChris D. Faulhaber 		return NULL;
1107a832d43SChris D. Faulhaber 	if (acl_clear_perms(perms) == -1)
1117a832d43SChris D. Faulhaber 		return NULL;
1127a832d43SChris D. Faulhaber 
1137a832d43SChris D. Faulhaber 	/* calculate user mode */
11443960f15SRobert Watson 	if (sb.st_mode & S_IRUSR)
1157a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_READ) == -1)
1167a832d43SChris D. Faulhaber 			return NULL;
11743960f15SRobert Watson 	if (sb.st_mode & S_IWUSR)
1187a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_WRITE) == -1)
1197a832d43SChris D. Faulhaber 			return NULL;
12043960f15SRobert Watson 	if (sb.st_mode & S_IXUSR)
1217a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1227a832d43SChris D. Faulhaber 			return NULL;
1237a832d43SChris D. Faulhaber 	if (acl_set_permset(entry, perms) == -1)
1247a832d43SChris D. Faulhaber 		return NULL;
12543960f15SRobert Watson 
1267a832d43SChris D. Faulhaber 	/* Second entry: ACL_GROUP_OBJ */
1277a832d43SChris D. Faulhaber 	if (acl_create_entry(&acl, &entry) == -1)
1287a832d43SChris D. Faulhaber 		return NULL;
1297a832d43SChris D. Faulhaber 	if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
1307a832d43SChris D. Faulhaber 		return NULL;
1317a832d43SChris D. Faulhaber 
1327a832d43SChris D. Faulhaber 	if (acl_get_permset(entry, &perms) == -1)
1337a832d43SChris D. Faulhaber 		return NULL;
1347a832d43SChris D. Faulhaber 	if (acl_clear_perms(perms) == -1)
1357a832d43SChris D. Faulhaber 		return NULL;
1367a832d43SChris D. Faulhaber 
1377a832d43SChris D. Faulhaber 	/* calculate group mode */
13843960f15SRobert Watson 	if (sb.st_mode & S_IRGRP)
1397a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_READ) == -1)
1407a832d43SChris D. Faulhaber 			return NULL;
14143960f15SRobert Watson 	if (sb.st_mode & S_IWGRP)
1427a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_WRITE) == -1)
1437a832d43SChris D. Faulhaber 			return NULL;
14443960f15SRobert Watson 	if (sb.st_mode & S_IXGRP)
1457a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1467a832d43SChris D. Faulhaber 			return NULL;
1477a832d43SChris D. Faulhaber 	if (acl_set_permset(entry, perms) == -1)
1487a832d43SChris D. Faulhaber 		return NULL;
14943960f15SRobert Watson 
1507a832d43SChris D. Faulhaber 	/* Third entry: ACL_OTHER */
1517a832d43SChris D. Faulhaber 	if (acl_create_entry(&acl, &entry) == -1)
1527a832d43SChris D. Faulhaber 		return NULL;
1537a832d43SChris D. Faulhaber 	if (acl_set_tag_type(entry, ACL_OTHER) == -1)
1547a832d43SChris D. Faulhaber 		return NULL;
1557a832d43SChris D. Faulhaber 
1567a832d43SChris D. Faulhaber 	if (acl_get_permset(entry, &perms) == -1)
1577a832d43SChris D. Faulhaber 		return NULL;
1587a832d43SChris D. Faulhaber 	if (acl_clear_perms(perms) == -1)
1597a832d43SChris D. Faulhaber 		return NULL;
1607a832d43SChris D. Faulhaber 
1617a832d43SChris D. Faulhaber 	/* calculate other mode */
16243960f15SRobert Watson 	if (sb.st_mode & S_IROTH)
1637a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_READ) == -1)
1647a832d43SChris D. Faulhaber 			return NULL;
16543960f15SRobert Watson 	if (sb.st_mode & S_IWOTH)
1667a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_WRITE) == -1)
1677a832d43SChris D. Faulhaber 			return NULL;
16843960f15SRobert Watson 	if (sb.st_mode & S_IXOTH)
1697a832d43SChris D. Faulhaber 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1707a832d43SChris D. Faulhaber 			return NULL;
1717a832d43SChris D. Faulhaber 	if (acl_set_permset(entry, perms) == -1)
1727a832d43SChris D. Faulhaber 		return NULL;
17343960f15SRobert Watson 
17443960f15SRobert Watson 	return(acl);
17543960f15SRobert Watson }
17643960f15SRobert Watson 
17743960f15SRobert Watson static int
17883bd4cd0SEdward Tomasz Napierala print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
17983bd4cd0SEdward Tomasz Napierala     int qflag, int vflag)
18043960f15SRobert Watson {
18143960f15SRobert Watson 	struct stat	sb;
18243960f15SRobert Watson 	acl_t	acl;
18343960f15SRobert Watson 	char	*acl_text;
18483bd4cd0SEdward Tomasz Napierala 	int	error, flags = 0, ret;
18543960f15SRobert Watson 
1868051fddeSRobert Watson 	if (hflag)
1878051fddeSRobert Watson 		error = lstat(path, &sb);
1888051fddeSRobert Watson 	else
18943960f15SRobert Watson 		error = stat(path, &sb);
19043960f15SRobert Watson 	if (error == -1) {
19183bd4cd0SEdward Tomasz Napierala 		warn("%s: stat() failed", path);
19283bd4cd0SEdward Tomasz Napierala 		return(-1);
19383bd4cd0SEdward Tomasz Napierala 	}
19483bd4cd0SEdward Tomasz Napierala 
19583bd4cd0SEdward Tomasz Napierala 	if (hflag)
19683bd4cd0SEdward Tomasz Napierala 		ret = lpathconf(path, _PC_ACL_NFS4);
19783bd4cd0SEdward Tomasz Napierala 	else
19883bd4cd0SEdward Tomasz Napierala 		ret = pathconf(path, _PC_ACL_NFS4);
19983bd4cd0SEdward Tomasz Napierala 	if (ret > 0) {
20083bd4cd0SEdward Tomasz Napierala 		if (type == ACL_TYPE_DEFAULT) {
20183bd4cd0SEdward Tomasz Napierala 			warnx("%s: there are no default entries in NFSv4 ACLs",
20283bd4cd0SEdward Tomasz Napierala 			    path);
20383bd4cd0SEdward Tomasz Napierala 			return (-1);
20483bd4cd0SEdward Tomasz Napierala 		}
20583bd4cd0SEdward Tomasz Napierala 		type = ACL_TYPE_NFS4;
20683bd4cd0SEdward Tomasz Napierala 	} else if (ret < 0 && errno != EINVAL) {
20783bd4cd0SEdward Tomasz Napierala 		warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
20843960f15SRobert Watson 		return (-1);
20943960f15SRobert Watson 	}
21043960f15SRobert Watson 
21143960f15SRobert Watson 	if (more_than_one)
21243960f15SRobert Watson 		printf("\n");
21343960f15SRobert Watson 	else
21443960f15SRobert Watson 		more_than_one++;
21543960f15SRobert Watson 
216f9a86e37SRobert Watson 	if (!qflag)
217c5771451SKevin Lo 		printf("# file: %s\n# owner: %s\n# group: %s\n", path,
218c5771451SKevin Lo 		    getuname(sb.st_uid), getgname(sb.st_gid));
21943960f15SRobert Watson 
2208051fddeSRobert Watson 	if (hflag)
2218051fddeSRobert Watson 		acl = acl_get_link_np(path, type);
2228051fddeSRobert Watson 	else
22343960f15SRobert Watson 		acl = acl_get_file(path, type);
22443960f15SRobert Watson 	if (!acl) {
22543960f15SRobert Watson 		if (errno != EOPNOTSUPP) {
22643960f15SRobert Watson 			warn("%s", path);
22743960f15SRobert Watson 			return(-1);
22843960f15SRobert Watson 		}
22943960f15SRobert Watson 		errno = 0;
23083bd4cd0SEdward Tomasz Napierala 		if (type == ACL_TYPE_DEFAULT)
23143960f15SRobert Watson 			return(0);
23243960f15SRobert Watson 		acl = acl_from_stat(sb);
23343960f15SRobert Watson 		if (!acl) {
23483bd4cd0SEdward Tomasz Napierala 			warn("%s: acl_from_stat() failed", path);
23543960f15SRobert Watson 			return(-1);
23643960f15SRobert Watson 		}
23743960f15SRobert Watson 	}
23843960f15SRobert Watson 
23983bd4cd0SEdward Tomasz Napierala 	if (iflag)
24083bd4cd0SEdward Tomasz Napierala 		flags |= ACL_TEXT_APPEND_ID;
24183bd4cd0SEdward Tomasz Napierala 
24283bd4cd0SEdward Tomasz Napierala 	if (nflag)
24383bd4cd0SEdward Tomasz Napierala 		flags |= ACL_TEXT_NUMERIC_IDS;
24483bd4cd0SEdward Tomasz Napierala 
24583bd4cd0SEdward Tomasz Napierala 	if (vflag)
24683bd4cd0SEdward Tomasz Napierala 		flags |= ACL_TEXT_VERBOSE;
24783bd4cd0SEdward Tomasz Napierala 
24883bd4cd0SEdward Tomasz Napierala 	acl_text = acl_to_text_np(acl, 0, flags);
24943960f15SRobert Watson 	if (!acl_text) {
25083bd4cd0SEdward Tomasz Napierala 		warn("%s: acl_to_text_np() failed", path);
25143960f15SRobert Watson 		return(-1);
25243960f15SRobert Watson 	}
25343960f15SRobert Watson 
25443960f15SRobert Watson 	printf("%s", acl_text);
25543960f15SRobert Watson 
256fab912dfSMark Murray 	(void)acl_free(acl);
257fab912dfSMark Murray 	(void)acl_free(acl_text);
25843960f15SRobert Watson 
25943960f15SRobert Watson 	return(0);
26043960f15SRobert Watson }
26143960f15SRobert Watson 
26243960f15SRobert Watson static int
26383bd4cd0SEdward Tomasz Napierala print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
26483bd4cd0SEdward Tomasz Napierala     int qflag, int vflag)
26543960f15SRobert Watson {
2664e65ab95STim J. Robbins 	char	*p, pathname[PATH_MAX];
26743960f15SRobert Watson 	int	carried_error = 0;
26843960f15SRobert Watson 
26928bf3202SKris Kennaway 	while (fgets(pathname, (int)sizeof(pathname), stdin)) {
2704e65ab95STim J. Robbins 		if ((p = strchr(pathname, '\n')) != NULL)
2714e65ab95STim J. Robbins 			*p = '\0';
27283bd4cd0SEdward Tomasz Napierala 		if (print_acl(pathname, type, hflag, iflag, nflag,
27383bd4cd0SEdward Tomasz Napierala 		    qflag, vflag) == -1) {
27443960f15SRobert Watson 			carried_error = -1;
27543960f15SRobert Watson 		}
27643960f15SRobert Watson 	}
27743960f15SRobert Watson 
27843960f15SRobert Watson 	return(carried_error);
27943960f15SRobert Watson }
28043960f15SRobert Watson 
28143960f15SRobert Watson int
28243960f15SRobert Watson main(int argc, char *argv[])
28343960f15SRobert Watson {
28443960f15SRobert Watson 	acl_type_t	type = ACL_TYPE_ACCESS;
28543960f15SRobert Watson 	int	carried_error = 0;
28643960f15SRobert Watson 	int	ch, error, i;
28783bd4cd0SEdward Tomasz Napierala 	int	hflag, iflag, qflag, nflag, vflag;
28843960f15SRobert Watson 
2898051fddeSRobert Watson 	hflag = 0;
29083bd4cd0SEdward Tomasz Napierala 	iflag = 0;
291f9a86e37SRobert Watson 	qflag = 0;
29283bd4cd0SEdward Tomasz Napierala 	nflag = 0;
29383bd4cd0SEdward Tomasz Napierala 	vflag = 0;
29483bd4cd0SEdward Tomasz Napierala 	while ((ch = getopt(argc, argv, "dhinqv")) != -1)
29543960f15SRobert Watson 		switch(ch) {
29643960f15SRobert Watson 		case 'd':
29743960f15SRobert Watson 			type = ACL_TYPE_DEFAULT;
29843960f15SRobert Watson 			break;
2998051fddeSRobert Watson 		case 'h':
3008051fddeSRobert Watson 			hflag = 1;
3018051fddeSRobert Watson 			break;
30283bd4cd0SEdward Tomasz Napierala 		case 'i':
30383bd4cd0SEdward Tomasz Napierala 			iflag = 1;
30483bd4cd0SEdward Tomasz Napierala 			break;
30583bd4cd0SEdward Tomasz Napierala 		case 'n':
30683bd4cd0SEdward Tomasz Napierala 			nflag = 1;
30783bd4cd0SEdward Tomasz Napierala 			break;
308f9a86e37SRobert Watson 		case 'q':
309f9a86e37SRobert Watson 			qflag = 1;
310f9a86e37SRobert Watson 			break;
31183bd4cd0SEdward Tomasz Napierala 		case 'v':
31283bd4cd0SEdward Tomasz Napierala 			vflag = 1;
31383bd4cd0SEdward Tomasz Napierala 			break;
31443960f15SRobert Watson 		default:
31543960f15SRobert Watson 			usage();
31643960f15SRobert Watson 			return(-1);
31743960f15SRobert Watson 		}
31843960f15SRobert Watson 	argc -= optind;
31943960f15SRobert Watson 	argv += optind;
32043960f15SRobert Watson 
32143960f15SRobert Watson 	if (argc == 0) {
32283bd4cd0SEdward Tomasz Napierala 		error = print_acl_from_stdin(type, hflag, iflag, nflag,
32383bd4cd0SEdward Tomasz Napierala 		    qflag, vflag);
3244e65ab95STim J. Robbins 		return(error ? 1 : 0);
32543960f15SRobert Watson 	}
32643960f15SRobert Watson 
32743960f15SRobert Watson 	for (i = 0; i < argc; i++) {
32843960f15SRobert Watson 		if (!strcmp(argv[i], "-")) {
32983bd4cd0SEdward Tomasz Napierala 			error = print_acl_from_stdin(type, hflag, iflag, nflag,
33083bd4cd0SEdward Tomasz Napierala 			    qflag, vflag);
33143960f15SRobert Watson 			if (error == -1)
33243960f15SRobert Watson 				carried_error = -1;
33343960f15SRobert Watson 		} else {
33483bd4cd0SEdward Tomasz Napierala 			error = print_acl(argv[i], type, hflag, iflag, nflag,
33583bd4cd0SEdward Tomasz Napierala 			    qflag, vflag);
33643960f15SRobert Watson 			if (error == -1)
33743960f15SRobert Watson 				carried_error = -1;
33843960f15SRobert Watson 		}
33943960f15SRobert Watson 	}
34043960f15SRobert Watson 
3414e65ab95STim J. Robbins 	return(carried_error ? 1 : 0);
34243960f15SRobert Watson }
343