xref: /illumos-gate/usr/src/cmd/getfacl/getfacl.c (revision c686756220120076a07be0dcce54be698101a3d1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2020 Peter Tribble.
25  */
26 
27 /*
28  * getfacl [-ad] file ...
29  * This command displays discretionary information for a file or files.
30  * display format:
31  *	# file: filename
32  *	# owner: uid
33  *	# group: gid
34  *	user::perm
35  *	user:uid:perm
36  *	group::perm
37  *	group:gid:perm
38  *	mask:perm
39  *	other:perm
40  *	default:user::perm
41  *	default:user:uid:perm
42  *	default:group::perm
43  *	default:group:gid:perm
44  *	default:mask:perm
45  *	default:other:perm
46  */
47 
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <locale.h>
53 #include <sys/acl.h>
54 #include <errno.h>
55 
56 static char	*pruname(uid_t);
57 static char	*prgname(gid_t);
58 static char	*display(int);
59 static void	usage();
60 
61 
62 int
63 main(int argc, char *argv[])
64 {
65 	int		c;
66 	int		aflag = 0;
67 	int		dflag = 0;
68 	int		errflag = 0;
69 	int		savecnt;
70 	int		aclcnt;
71 	int		mask = 0;
72 	aclent_t	*aclp;
73 	aclent_t	*tp;
74 	char		*permp;
75 
76 	(void) setlocale(LC_ALL, "");
77 	(void) textdomain(TEXT_DOMAIN);
78 
79 	if (argc < 2)
80 		usage();
81 
82 	while ((c = getopt(argc, argv, "ad")) != EOF) {
83 		switch (c) {
84 		case 'a':
85 			aflag++;
86 			break;
87 		case 'd':
88 			dflag++;
89 			break;
90 		case '?':
91 			errflag++;
92 			break;
93 		}
94 	}
95 	if (errflag)
96 		usage();
97 
98 	if (optind >= argc)
99 		usage();
100 
101 	for (; optind < argc; optind++) {
102 		register char *filep;
103 
104 		filep = argv[optind];
105 
106 		/* Get ACL info of the files */
107 		errno = 0;
108 		if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) {
109 			if (errno == ENOSYS) {
110 				(void) fprintf(stderr,
111 				    gettext("File system doesn't support "
112 				    "aclent_t style ACL's.\n"
113 				    "See acl(5) for more information on "
114 				    "POSIX-draft ACL support.\n"));
115 				exit(2);
116 			}
117 			perror(filep);
118 			exit(2);
119 		}
120 		if (aclcnt < MIN_ACL_ENTRIES) {
121 			(void) fprintf(stderr,
122 			    gettext("%d: acl count too small from %s\n"),
123 			    aclcnt, filep);
124 			exit(2);
125 		}
126 
127 		if ((aclp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt))
128 		    == NULL) {
129 			(void) fprintf(stderr,
130 			    gettext("Insufficient memory\n"));
131 			exit(1);
132 		}
133 
134 		errno = 0;
135 		if (acl(filep, GETACL, aclcnt, aclp) < 0) {
136 			perror(filep);
137 			exit(2);
138 		}
139 
140 		/* display ACL: assume it is sorted. */
141 		(void) printf("\n# file: %s\n", filep);
142 		savecnt = aclcnt;
143 		for (tp = aclp; aclcnt--; tp++) {
144 			if (tp->a_type == USER_OBJ)
145 				(void) printf("# owner: %s\n",
146 				    pruname(tp->a_id));
147 			if (tp->a_type == GROUP_OBJ)
148 				(void) printf("# group: %s\n",
149 				    prgname(tp->a_id));
150 			if (tp->a_type == CLASS_OBJ)
151 				mask = tp->a_perm;
152 		}
153 		aclcnt = savecnt;
154 		for (tp = aclp; aclcnt--; tp++) {
155 			switch (tp->a_type) {
156 			case USER:
157 				if (!dflag) {
158 					permp = display(tp->a_perm);
159 					(void) printf("user:%s:%s\t\t",
160 					    pruname(tp->a_id), permp);
161 					free(permp);
162 					permp = display(tp->a_perm & mask);
163 					(void) printf(
164 					    "#effective:%s\n", permp);
165 					free(permp);
166 				}
167 				break;
168 			case USER_OBJ:
169 				if (!dflag) {
170 					/* no need to display uid */
171 					permp = display(tp->a_perm);
172 					(void) printf("user::%s\n", permp);
173 					free(permp);
174 				}
175 				break;
176 			case GROUP:
177 				if (!dflag) {
178 					permp = display(tp->a_perm);
179 					(void) printf("group:%s:%s\t\t",
180 					    prgname(tp->a_id), permp);
181 					free(permp);
182 					permp = display(tp->a_perm & mask);
183 					(void) printf(
184 					    "#effective:%s\n", permp);
185 					free(permp);
186 				}
187 				break;
188 			case GROUP_OBJ:
189 				if (!dflag) {
190 					permp = display(tp->a_perm);
191 					(void) printf("group::%s\t\t", permp);
192 					free(permp);
193 					permp = display(tp->a_perm & mask);
194 					(void) printf(
195 					    "#effective:%s\n", permp);
196 					free(permp);
197 				}
198 				break;
199 			case CLASS_OBJ:
200 				if (!dflag) {
201 					permp = display(tp->a_perm);
202 					(void) printf("mask:%s\n", permp);
203 					free(permp);
204 				}
205 				break;
206 			case OTHER_OBJ:
207 				if (!dflag) {
208 					permp = display(tp->a_perm);
209 					(void) printf("other:%s\n", permp);
210 					free(permp);
211 				}
212 				break;
213 			case DEF_USER:
214 				if (!aflag) {
215 					permp = display(tp->a_perm);
216 					(void) printf("default:user:%s:%s\n",
217 					    pruname(tp->a_id), permp);
218 					free(permp);
219 				}
220 				break;
221 			case DEF_USER_OBJ:
222 				if (!aflag) {
223 					permp = display(tp->a_perm);
224 					(void) printf("default:user::%s\n",
225 					    permp);
226 					free(permp);
227 				}
228 				break;
229 			case DEF_GROUP:
230 				if (!aflag) {
231 					permp = display(tp->a_perm);
232 					(void) printf("default:group:%s:%s\n",
233 					    prgname(tp->a_id), permp);
234 					free(permp);
235 				}
236 				break;
237 			case DEF_GROUP_OBJ:
238 				if (!aflag) {
239 					permp = display(tp->a_perm);
240 					(void) printf("default:group::%s\n",
241 					    permp);
242 					free(permp);
243 				}
244 				break;
245 			case DEF_CLASS_OBJ:
246 				if (!aflag) {
247 					permp = display(tp->a_perm);
248 					(void) printf("default:mask:%s\n",
249 					    permp);
250 					free(permp);
251 				}
252 				break;
253 			case DEF_OTHER_OBJ:
254 				if (!aflag) {
255 					permp = display(tp->a_perm);
256 					(void) printf("default:other:%s\n",
257 					    permp);
258 					free(permp);
259 				}
260 				break;
261 			default:
262 				(void) fprintf(stderr,
263 				    gettext("unrecognized entry\n"));
264 				break;
265 			}
266 		}
267 		free(aclp);
268 	}
269 	return (0);
270 }
271 
272 static char *
273 display(int perm)
274 {
275 	char	*buf;
276 
277 	buf = malloc(4);
278 	if (buf == NULL) {
279 		(void) fprintf(stderr, gettext("Insufficient memory\n"));
280 		exit(1);
281 	}
282 
283 	if (perm & 4)
284 		buf[0] = 'r';
285 	else
286 		buf[0] = '-';
287 	if (perm & 2)
288 		buf[1] = 'w';
289 	else
290 		buf[1] = '-';
291 	if (perm & 1)
292 		buf[2] = 'x';
293 	else
294 		buf[2] = '-';
295 	buf[3] = '\0';
296 	return (buf);
297 }
298 
299 static char *
300 pruname(uid_t uid)
301 {
302 	struct passwd	*passwdp;
303 	static char	uidp[10];	/* big enough */
304 
305 	passwdp = getpwuid(uid);
306 	if (passwdp == (struct passwd *)NULL) {
307 		/* could not get passwd information: display uid instead */
308 		(void) sprintf(uidp, "%u", uid);
309 		return (uidp);
310 	} else
311 		return (passwdp->pw_name);
312 }
313 
314 static char *
315 prgname(gid_t gid)
316 {
317 	struct group	*groupp;
318 	static char	gidp[10];	/* big enough */
319 
320 	groupp = getgrgid(gid);
321 	if (groupp == (struct group *)NULL) {
322 		/* could not get group information: display gid instead */
323 		(void) sprintf(gidp, "%u", gid);
324 		return (gidp);
325 	} else
326 		return (groupp->gr_name);
327 }
328 
329 static void
330 usage()
331 {
332 	(void) fprintf(stderr,
333 	    gettext("usage: getfacl [-ad] file ... \n"));
334 	exit(1);
335 }
336