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
56static char	*pruname(uid_t);
57static char	*prgname(gid_t);
58static char	*display(int);
59static void	usage();
60
61
62int
63main(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
272static char *
273display(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
299static char *
300pruname(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
314static char *
315prgname(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
329static void
330usage()
331{
332	(void) fprintf(stderr,
333	    gettext("usage: getfacl [-ad] file ... \n"));
334	exit(1);
335}
336