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