xref: /netbsd/bin/getfacl/getfacl.c (revision 51ac0ef6)
1*51ac0ef6Sjoerg /*	$NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $	*/
2b9c1fd7fSchristos 
3b9c1fd7fSchristos /*-
4b9c1fd7fSchristos  * Copyright (c) 1999, 2001, 2002 Robert N M Watson
5b9c1fd7fSchristos  * All rights reserved.
6b9c1fd7fSchristos  *
7b9c1fd7fSchristos  * This software was developed by Robert Watson for the TrustedBSD Project.
8b9c1fd7fSchristos  *
9b9c1fd7fSchristos  * Redistribution and use in source and binary forms, with or without
10b9c1fd7fSchristos  * modification, are permitted provided that the following conditions
11b9c1fd7fSchristos  * are met:
12b9c1fd7fSchristos  * 1. Redistributions of source code must retain the above copyright
13b9c1fd7fSchristos  *    notice, this list of conditions and the following disclaimer.
14b9c1fd7fSchristos  * 2. Redistributions in binary form must reproduce the above copyright
15b9c1fd7fSchristos  *    notice, this list of conditions and the following disclaimer in the
16b9c1fd7fSchristos  *    documentation and/or other materials provided with the distribution.
17b9c1fd7fSchristos  *
18b9c1fd7fSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b9c1fd7fSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b9c1fd7fSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b9c1fd7fSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b9c1fd7fSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b9c1fd7fSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b9c1fd7fSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b9c1fd7fSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b9c1fd7fSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b9c1fd7fSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b9c1fd7fSchristos  * SUCH DAMAGE.
29b9c1fd7fSchristos  */
30b9c1fd7fSchristos /*
31b9c1fd7fSchristos  * getfacl -- POSIX.1e utility to extract ACLs from files and directories
32b9c1fd7fSchristos  * and send the results to stdout
33b9c1fd7fSchristos  */
34b9c1fd7fSchristos 
35b9c1fd7fSchristos 
36b9c1fd7fSchristos #include <sys/cdefs.h>
37b9c1fd7fSchristos #if 0
38b9c1fd7fSchristos __FBSDID("$FreeBSD: head/bin/getfacl/getfacl.c 340014 2018-11-01 17:45:29Z markj $");
39b9c1fd7fSchristos #else
40*51ac0ef6Sjoerg __RCSID("$NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $");
41b9c1fd7fSchristos #endif
42b9c1fd7fSchristos 
43b9c1fd7fSchristos #include <sys/types.h>
44b9c1fd7fSchristos #include <sys/param.h>
45b9c1fd7fSchristos #include <sys/acl.h>
46b9c1fd7fSchristos #include <sys/stat.h>
47b9c1fd7fSchristos 
48b9c1fd7fSchristos #include <err.h>
49b9c1fd7fSchristos #include <errno.h>
50b9c1fd7fSchristos #include <grp.h>
51b9c1fd7fSchristos #include <pwd.h>
52b9c1fd7fSchristos #include <stdio.h>
53b9c1fd7fSchristos #include <stdlib.h>
54b9c1fd7fSchristos #include <string.h>
55b9c1fd7fSchristos #include <unistd.h>
56b9c1fd7fSchristos 
57b9c1fd7fSchristos static int more_than_one = 0;
58b9c1fd7fSchristos 
59b9c1fd7fSchristos static __dead void
usage(void)60b9c1fd7fSchristos usage(void)
61b9c1fd7fSchristos {
62b9c1fd7fSchristos 
63b9c1fd7fSchristos 	fprintf(stderr, "Usage: %s [-dhnqv] [file ...]\n", getprogname());
64*51ac0ef6Sjoerg 	exit(1);
65b9c1fd7fSchristos }
66b9c1fd7fSchristos 
67b9c1fd7fSchristos static char *
getuname(uid_t uid)68b9c1fd7fSchristos getuname(uid_t uid)
69b9c1fd7fSchristos {
70b9c1fd7fSchristos 	struct passwd *pw;
71b9c1fd7fSchristos 	static char uids[10];
72b9c1fd7fSchristos 
73b9c1fd7fSchristos 	if ((pw = getpwuid(uid)) == NULL) {
74b9c1fd7fSchristos 		(void)snprintf(uids, sizeof(uids), "%u", uid);
75b9c1fd7fSchristos 		return (uids);
76b9c1fd7fSchristos 	} else
77b9c1fd7fSchristos 		return (pw->pw_name);
78b9c1fd7fSchristos }
79b9c1fd7fSchristos 
80b9c1fd7fSchristos static char *
getgname(gid_t gid)81b9c1fd7fSchristos getgname(gid_t gid)
82b9c1fd7fSchristos {
83b9c1fd7fSchristos 	struct group *gr;
84b9c1fd7fSchristos 	static char gids[10];
85b9c1fd7fSchristos 
86b9c1fd7fSchristos 	if ((gr = getgrgid(gid)) == NULL) {
87b9c1fd7fSchristos 		(void)snprintf(gids, sizeof(gids), "%u", gid);
88b9c1fd7fSchristos 		return (gids);
89b9c1fd7fSchristos 	} else
90b9c1fd7fSchristos 		return (gr->gr_name);
91b9c1fd7fSchristos }
92b9c1fd7fSchristos 
93b9c1fd7fSchristos /*
94b9c1fd7fSchristos  * return an ACL corresponding to the permissions
95b9c1fd7fSchristos  * contained in struct stat
96b9c1fd7fSchristos  */
97b9c1fd7fSchristos static acl_t
acl_from_stat(const struct stat * sb)98b9c1fd7fSchristos acl_from_stat(const struct stat *sb)
99b9c1fd7fSchristos {
100b9c1fd7fSchristos 	acl_t acl;
101b9c1fd7fSchristos 	acl_entry_t entry;
102b9c1fd7fSchristos 	acl_permset_t perms;
103b9c1fd7fSchristos 
104b9c1fd7fSchristos 	/* create the ACL */
105b9c1fd7fSchristos 	acl = acl_init(3);
106b9c1fd7fSchristos 	if (!acl)
107b9c1fd7fSchristos 		return NULL;
108b9c1fd7fSchristos 
109b9c1fd7fSchristos 	/* First entry: ACL_USER_OBJ */
110b9c1fd7fSchristos 	if (acl_create_entry(&acl, &entry) == -1)
111b9c1fd7fSchristos 		return NULL;
112b9c1fd7fSchristos 	if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
113b9c1fd7fSchristos 		return NULL;
114b9c1fd7fSchristos 
115b9c1fd7fSchristos 	if (acl_get_permset(entry, &perms) == -1)
116b9c1fd7fSchristos 		return NULL;
117b9c1fd7fSchristos 	if (acl_clear_perms(perms) == -1)
118b9c1fd7fSchristos 		return NULL;
119b9c1fd7fSchristos 
120b9c1fd7fSchristos 	/* calculate user mode */
121b9c1fd7fSchristos 	if (sb->st_mode & S_IRUSR)
122b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_READ) == -1)
123b9c1fd7fSchristos 			return NULL;
124b9c1fd7fSchristos 	if (sb->st_mode & S_IWUSR)
125b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_WRITE) == -1)
126b9c1fd7fSchristos 			return NULL;
127b9c1fd7fSchristos 	if (sb->st_mode & S_IXUSR)
128b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
129b9c1fd7fSchristos 			return NULL;
130b9c1fd7fSchristos 	if (acl_set_permset(entry, perms) == -1)
131b9c1fd7fSchristos 		return NULL;
132b9c1fd7fSchristos 
133b9c1fd7fSchristos 	/* Second entry: ACL_GROUP_OBJ */
134b9c1fd7fSchristos 	if (acl_create_entry(&acl, &entry) == -1)
135b9c1fd7fSchristos 		return NULL;
136b9c1fd7fSchristos 	if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
137b9c1fd7fSchristos 		return NULL;
138b9c1fd7fSchristos 
139b9c1fd7fSchristos 	if (acl_get_permset(entry, &perms) == -1)
140b9c1fd7fSchristos 		return NULL;
141b9c1fd7fSchristos 	if (acl_clear_perms(perms) == -1)
142b9c1fd7fSchristos 		return NULL;
143b9c1fd7fSchristos 
144b9c1fd7fSchristos 	/* calculate group mode */
145b9c1fd7fSchristos 	if (sb->st_mode & S_IRGRP)
146b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_READ) == -1)
147b9c1fd7fSchristos 			return NULL;
148b9c1fd7fSchristos 	if (sb->st_mode & S_IWGRP)
149b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_WRITE) == -1)
150b9c1fd7fSchristos 			return NULL;
151b9c1fd7fSchristos 	if (sb->st_mode & S_IXGRP)
152b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
153b9c1fd7fSchristos 			return NULL;
154b9c1fd7fSchristos 	if (acl_set_permset(entry, perms) == -1)
155b9c1fd7fSchristos 		return NULL;
156b9c1fd7fSchristos 
157b9c1fd7fSchristos 	/* Third entry: ACL_OTHER */
158b9c1fd7fSchristos 	if (acl_create_entry(&acl, &entry) == -1)
159b9c1fd7fSchristos 		return NULL;
160b9c1fd7fSchristos 	if (acl_set_tag_type(entry, ACL_OTHER) == -1)
161b9c1fd7fSchristos 		return NULL;
162b9c1fd7fSchristos 
163b9c1fd7fSchristos 	if (acl_get_permset(entry, &perms) == -1)
164b9c1fd7fSchristos 		return NULL;
165b9c1fd7fSchristos 	if (acl_clear_perms(perms) == -1)
166b9c1fd7fSchristos 		return NULL;
167b9c1fd7fSchristos 
168b9c1fd7fSchristos 	/* calculate other mode */
169b9c1fd7fSchristos 	if (sb->st_mode & S_IROTH)
170b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_READ) == -1)
171b9c1fd7fSchristos 			return NULL;
172b9c1fd7fSchristos 	if (sb->st_mode & S_IWOTH)
173b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_WRITE) == -1)
174b9c1fd7fSchristos 			return NULL;
175b9c1fd7fSchristos 	if (sb->st_mode & S_IXOTH)
176b9c1fd7fSchristos 		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
177b9c1fd7fSchristos 			return NULL;
178b9c1fd7fSchristos 	if (acl_set_permset(entry, perms) == -1)
179b9c1fd7fSchristos 		return NULL;
180b9c1fd7fSchristos 
181b9c1fd7fSchristos 	return(acl);
182b9c1fd7fSchristos }
183b9c1fd7fSchristos 
184b9c1fd7fSchristos static int
print_acl(char * path,acl_type_t type,int hflag,int iflag,int nflag,int qflag,int vflag)185b9c1fd7fSchristos print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
186b9c1fd7fSchristos     int qflag, int vflag)
187b9c1fd7fSchristos {
188b9c1fd7fSchristos 	struct stat	sb;
189b9c1fd7fSchristos 	acl_t	acl;
190b9c1fd7fSchristos 	char	*acl_text;
191b9c1fd7fSchristos 	int	error, flags = 0, ret;
192b9c1fd7fSchristos 
193b9c1fd7fSchristos 	if (hflag)
194b9c1fd7fSchristos 		error = lstat(path, &sb);
195b9c1fd7fSchristos 	else
196b9c1fd7fSchristos 		error = stat(path, &sb);
197b9c1fd7fSchristos 	if (error == -1) {
198b9c1fd7fSchristos 		warn("%s: stat() failed", path);
199b9c1fd7fSchristos 		return(-1);
200b9c1fd7fSchristos 	}
201b9c1fd7fSchristos 
202b9c1fd7fSchristos 	if (hflag)
203b9c1fd7fSchristos 		ret = lpathconf(path, _PC_ACL_NFS4);
204b9c1fd7fSchristos 	else
205b9c1fd7fSchristos 		ret = pathconf(path, _PC_ACL_NFS4);
206b9c1fd7fSchristos 	if (ret > 0) {
207b9c1fd7fSchristos 		if (type == ACL_TYPE_DEFAULT) {
208b9c1fd7fSchristos 			warnx("%s: there are no default entries in NFSv4 ACLs",
209b9c1fd7fSchristos 			    path);
210b9c1fd7fSchristos 			return (-1);
211b9c1fd7fSchristos 		}
212b9c1fd7fSchristos 		type = ACL_TYPE_NFS4;
213b9c1fd7fSchristos 	} else if (ret < 0 && errno != EINVAL) {
214b9c1fd7fSchristos 		warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
215b9c1fd7fSchristos 		return (-1);
216b9c1fd7fSchristos 	}
217b9c1fd7fSchristos 
218b9c1fd7fSchristos 	if (more_than_one)
219b9c1fd7fSchristos 		printf("\n");
220b9c1fd7fSchristos 	else
221b9c1fd7fSchristos 		more_than_one++;
222b9c1fd7fSchristos 
223b9c1fd7fSchristos 	if (!qflag)
224b9c1fd7fSchristos 		printf("# file: %s\n# owner: %s\n# group: %s\n", path,
225b9c1fd7fSchristos 		    getuname(sb.st_uid), getgname(sb.st_gid));
226b9c1fd7fSchristos 
227b9c1fd7fSchristos 	if (hflag)
228b9c1fd7fSchristos 		acl = acl_get_link_np(path, type);
229b9c1fd7fSchristos 	else
230b9c1fd7fSchristos 		acl = acl_get_file(path, type);
231b9c1fd7fSchristos 	if (!acl) {
232b9c1fd7fSchristos 		if (errno != EOPNOTSUPP) {
233b9c1fd7fSchristos 			warn("%s", path);
234b9c1fd7fSchristos 			return(-1);
235b9c1fd7fSchristos 		}
236b9c1fd7fSchristos 		errno = 0;
237b9c1fd7fSchristos 		if (type == ACL_TYPE_DEFAULT)
238b9c1fd7fSchristos 			return(0);
239b9c1fd7fSchristos 		acl = acl_from_stat(&sb);
240b9c1fd7fSchristos 		if (!acl) {
241b9c1fd7fSchristos 			warn("%s: acl_from_stat() failed", path);
242b9c1fd7fSchristos 			return(-1);
243b9c1fd7fSchristos 		}
244b9c1fd7fSchristos 	}
245b9c1fd7fSchristos 
246b9c1fd7fSchristos 	if (iflag)
247b9c1fd7fSchristos 		flags |= ACL_TEXT_APPEND_ID;
248b9c1fd7fSchristos 
249b9c1fd7fSchristos 	if (nflag)
250b9c1fd7fSchristos 		flags |= ACL_TEXT_NUMERIC_IDS;
251b9c1fd7fSchristos 
252b9c1fd7fSchristos 	if (vflag)
253b9c1fd7fSchristos 		flags |= ACL_TEXT_VERBOSE;
254b9c1fd7fSchristos 
255b9c1fd7fSchristos 	acl_text = acl_to_text_np(acl, 0, flags);
256b9c1fd7fSchristos 	if (!acl_text) {
257b9c1fd7fSchristos 		warn("%s: acl_to_text_np() failed", path);
258b9c1fd7fSchristos 		return(-1);
259b9c1fd7fSchristos 	}
260b9c1fd7fSchristos 
261b9c1fd7fSchristos 	printf("%s", acl_text);
262b9c1fd7fSchristos 
263b9c1fd7fSchristos 	(void)acl_free(acl);
264b9c1fd7fSchristos 	(void)acl_free(acl_text);
265b9c1fd7fSchristos 
266b9c1fd7fSchristos 	return(0);
267b9c1fd7fSchristos }
268b9c1fd7fSchristos 
269b9c1fd7fSchristos static int
print_acl_from_stdin(acl_type_t type,int hflag,int iflag,int nflag,int qflag,int vflag)270b9c1fd7fSchristos print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
271b9c1fd7fSchristos     int qflag, int vflag)
272b9c1fd7fSchristos {
273b9c1fd7fSchristos 	char	*p, pathname[PATH_MAX];
274b9c1fd7fSchristos 	int	carried_error = 0;
275b9c1fd7fSchristos 
276b9c1fd7fSchristos 	while (fgets(pathname, (int)sizeof(pathname), stdin)) {
277b9c1fd7fSchristos 		if ((p = strchr(pathname, '\n')) != NULL)
278b9c1fd7fSchristos 			*p = '\0';
279b9c1fd7fSchristos 		if (print_acl(pathname, type, hflag, iflag, nflag,
280b9c1fd7fSchristos 		    qflag, vflag) == -1) {
281b9c1fd7fSchristos 			carried_error = -1;
282b9c1fd7fSchristos 		}
283b9c1fd7fSchristos 	}
284b9c1fd7fSchristos 
285b9c1fd7fSchristos 	return(carried_error);
286b9c1fd7fSchristos }
287b9c1fd7fSchristos 
288b9c1fd7fSchristos int
main(int argc,char * argv[])289b9c1fd7fSchristos main(int argc, char *argv[])
290b9c1fd7fSchristos {
291b9c1fd7fSchristos 	acl_type_t	type = ACL_TYPE_ACCESS;
292b9c1fd7fSchristos 	int	carried_error = 0;
293b9c1fd7fSchristos 	int	ch, error, i;
294b9c1fd7fSchristos 	int	hflag, iflag, qflag, nflag, vflag;
295b9c1fd7fSchristos 
296b9c1fd7fSchristos 	hflag = 0;
297b9c1fd7fSchristos 	iflag = 0;
298b9c1fd7fSchristos 	qflag = 0;
299b9c1fd7fSchristos 	nflag = 0;
300b9c1fd7fSchristos 	vflag = 0;
301b9c1fd7fSchristos 	while ((ch = getopt(argc, argv, "dhinqv")) != -1)
302b9c1fd7fSchristos 		switch(ch) {
303b9c1fd7fSchristos 		case 'd':
304b9c1fd7fSchristos 			type = ACL_TYPE_DEFAULT;
305b9c1fd7fSchristos 			break;
306b9c1fd7fSchristos 		case 'h':
307b9c1fd7fSchristos 			hflag = 1;
308b9c1fd7fSchristos 			break;
309b9c1fd7fSchristos 		case 'i':
310b9c1fd7fSchristos 			iflag = 1;
311b9c1fd7fSchristos 			break;
312b9c1fd7fSchristos 		case 'n':
313b9c1fd7fSchristos 			nflag = 1;
314b9c1fd7fSchristos 			break;
315b9c1fd7fSchristos 		case 'q':
316b9c1fd7fSchristos 			qflag = 1;
317b9c1fd7fSchristos 			break;
318b9c1fd7fSchristos 		case 'v':
319b9c1fd7fSchristos 			vflag = 1;
320b9c1fd7fSchristos 			break;
321b9c1fd7fSchristos 		default:
322b9c1fd7fSchristos 			usage();
323b9c1fd7fSchristos 		}
324b9c1fd7fSchristos 	argc -= optind;
325b9c1fd7fSchristos 	argv += optind;
326b9c1fd7fSchristos 
327b9c1fd7fSchristos 	if (argc == 0) {
328b9c1fd7fSchristos 		error = print_acl_from_stdin(type, hflag, iflag, nflag,
329b9c1fd7fSchristos 		    qflag, vflag);
330b9c1fd7fSchristos 		return(error ? 1 : 0);
331b9c1fd7fSchristos 	}
332b9c1fd7fSchristos 
333b9c1fd7fSchristos 	for (i = 0; i < argc; i++) {
334b9c1fd7fSchristos 		if (!strcmp(argv[i], "-")) {
335b9c1fd7fSchristos 			error = print_acl_from_stdin(type, hflag, iflag, nflag,
336b9c1fd7fSchristos 			    qflag, vflag);
337b9c1fd7fSchristos 			if (error == -1)
338b9c1fd7fSchristos 				carried_error = -1;
339b9c1fd7fSchristos 		} else {
340b9c1fd7fSchristos 			error = print_acl(argv[i], type, hflag, iflag, nflag,
341b9c1fd7fSchristos 			    qflag, vflag);
342b9c1fd7fSchristos 			if (error == -1)
343b9c1fd7fSchristos 				carried_error = -1;
344b9c1fd7fSchristos 		}
345b9c1fd7fSchristos 	}
346b9c1fd7fSchristos 
347b9c1fd7fSchristos 	return(carried_error ? 1 : 0);
348b9c1fd7fSchristos }
349