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