getfacl.c revision 1.1 1 /* $NetBSD: getfacl.c,v 1.1 2020/05/16 18:31:45 christos 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.1 2020/05/16 18:31:45 christos 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
60 usage(void)
61 {
62
63 fprintf(stderr, "Usage: %s [-dhnqv] [file ...]\n", getprogname());
64 }
65
66 static char *
67 getuname(uid_t uid)
68 {
69 struct passwd *pw;
70 static char uids[10];
71
72 if ((pw = getpwuid(uid)) == NULL) {
73 (void)snprintf(uids, sizeof(uids), "%u", uid);
74 return (uids);
75 } else
76 return (pw->pw_name);
77 }
78
79 static char *
80 getgname(gid_t gid)
81 {
82 struct group *gr;
83 static char gids[10];
84
85 if ((gr = getgrgid(gid)) == NULL) {
86 (void)snprintf(gids, sizeof(gids), "%u", gid);
87 return (gids);
88 } else
89 return (gr->gr_name);
90 }
91
92 /*
93 * return an ACL corresponding to the permissions
94 * contained in struct stat
95 */
96 static acl_t
97 acl_from_stat(const struct stat *sb)
98 {
99 acl_t acl;
100 acl_entry_t entry;
101 acl_permset_t perms;
102
103 /* create the ACL */
104 acl = acl_init(3);
105 if (!acl)
106 return NULL;
107
108 /* First entry: ACL_USER_OBJ */
109 if (acl_create_entry(&acl, &entry) == -1)
110 return NULL;
111 if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
112 return NULL;
113
114 if (acl_get_permset(entry, &perms) == -1)
115 return NULL;
116 if (acl_clear_perms(perms) == -1)
117 return NULL;
118
119 /* calculate user mode */
120 if (sb->st_mode & S_IRUSR)
121 if (acl_add_perm(perms, ACL_READ) == -1)
122 return NULL;
123 if (sb->st_mode & S_IWUSR)
124 if (acl_add_perm(perms, ACL_WRITE) == -1)
125 return NULL;
126 if (sb->st_mode & S_IXUSR)
127 if (acl_add_perm(perms, ACL_EXECUTE) == -1)
128 return NULL;
129 if (acl_set_permset(entry, perms) == -1)
130 return NULL;
131
132 /* Second entry: ACL_GROUP_OBJ */
133 if (acl_create_entry(&acl, &entry) == -1)
134 return NULL;
135 if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
136 return NULL;
137
138 if (acl_get_permset(entry, &perms) == -1)
139 return NULL;
140 if (acl_clear_perms(perms) == -1)
141 return NULL;
142
143 /* calculate group mode */
144 if (sb->st_mode & S_IRGRP)
145 if (acl_add_perm(perms, ACL_READ) == -1)
146 return NULL;
147 if (sb->st_mode & S_IWGRP)
148 if (acl_add_perm(perms, ACL_WRITE) == -1)
149 return NULL;
150 if (sb->st_mode & S_IXGRP)
151 if (acl_add_perm(perms, ACL_EXECUTE) == -1)
152 return NULL;
153 if (acl_set_permset(entry, perms) == -1)
154 return NULL;
155
156 /* Third entry: ACL_OTHER */
157 if (acl_create_entry(&acl, &entry) == -1)
158 return NULL;
159 if (acl_set_tag_type(entry, ACL_OTHER) == -1)
160 return NULL;
161
162 if (acl_get_permset(entry, &perms) == -1)
163 return NULL;
164 if (acl_clear_perms(perms) == -1)
165 return NULL;
166
167 /* calculate other mode */
168 if (sb->st_mode & S_IROTH)
169 if (acl_add_perm(perms, ACL_READ) == -1)
170 return NULL;
171 if (sb->st_mode & S_IWOTH)
172 if (acl_add_perm(perms, ACL_WRITE) == -1)
173 return NULL;
174 if (sb->st_mode & S_IXOTH)
175 if (acl_add_perm(perms, ACL_EXECUTE) == -1)
176 return NULL;
177 if (acl_set_permset(entry, perms) == -1)
178 return NULL;
179
180 return(acl);
181 }
182
183 static int
184 print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
185 int qflag, int vflag)
186 {
187 struct stat sb;
188 acl_t acl;
189 char *acl_text;
190 int error, flags = 0, ret;
191
192 if (hflag)
193 error = lstat(path, &sb);
194 else
195 error = stat(path, &sb);
196 if (error == -1) {
197 warn("%s: stat() failed", path);
198 return(-1);
199 }
200
201 if (hflag)
202 ret = lpathconf(path, _PC_ACL_NFS4);
203 else
204 ret = pathconf(path, _PC_ACL_NFS4);
205 if (ret > 0) {
206 if (type == ACL_TYPE_DEFAULT) {
207 warnx("%s: there are no default entries in NFSv4 ACLs",
208 path);
209 return (-1);
210 }
211 type = ACL_TYPE_NFS4;
212 } else if (ret < 0 && errno != EINVAL) {
213 warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
214 return (-1);
215 }
216
217 if (more_than_one)
218 printf("\n");
219 else
220 more_than_one++;
221
222 if (!qflag)
223 printf("# file: %s\n# owner: %s\n# group: %s\n", path,
224 getuname(sb.st_uid), getgname(sb.st_gid));
225
226 if (hflag)
227 acl = acl_get_link_np(path, type);
228 else
229 acl = acl_get_file(path, type);
230 if (!acl) {
231 if (errno != EOPNOTSUPP) {
232 warn("%s", path);
233 return(-1);
234 }
235 errno = 0;
236 if (type == ACL_TYPE_DEFAULT)
237 return(0);
238 acl = acl_from_stat(&sb);
239 if (!acl) {
240 warn("%s: acl_from_stat() failed", path);
241 return(-1);
242 }
243 }
244
245 if (iflag)
246 flags |= ACL_TEXT_APPEND_ID;
247
248 if (nflag)
249 flags |= ACL_TEXT_NUMERIC_IDS;
250
251 if (vflag)
252 flags |= ACL_TEXT_VERBOSE;
253
254 acl_text = acl_to_text_np(acl, 0, flags);
255 if (!acl_text) {
256 warn("%s: acl_to_text_np() failed", path);
257 return(-1);
258 }
259
260 printf("%s", acl_text);
261
262 (void)acl_free(acl);
263 (void)acl_free(acl_text);
264
265 return(0);
266 }
267
268 static int
269 print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
270 int qflag, int vflag)
271 {
272 char *p, pathname[PATH_MAX];
273 int carried_error = 0;
274
275 while (fgets(pathname, (int)sizeof(pathname), stdin)) {
276 if ((p = strchr(pathname, '\n')) != NULL)
277 *p = '\0';
278 if (print_acl(pathname, type, hflag, iflag, nflag,
279 qflag, vflag) == -1) {
280 carried_error = -1;
281 }
282 }
283
284 return(carried_error);
285 }
286
287 int
288 main(int argc, char *argv[])
289 {
290 acl_type_t type = ACL_TYPE_ACCESS;
291 int carried_error = 0;
292 int ch, error, i;
293 int hflag, iflag, qflag, nflag, vflag;
294
295 hflag = 0;
296 iflag = 0;
297 qflag = 0;
298 nflag = 0;
299 vflag = 0;
300 while ((ch = getopt(argc, argv, "dhinqv")) != -1)
301 switch(ch) {
302 case 'd':
303 type = ACL_TYPE_DEFAULT;
304 break;
305 case 'h':
306 hflag = 1;
307 break;
308 case 'i':
309 iflag = 1;
310 break;
311 case 'n':
312 nflag = 1;
313 break;
314 case 'q':
315 qflag = 1;
316 break;
317 case 'v':
318 vflag = 1;
319 break;
320 default:
321 usage();
322 return(-1);
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