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