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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <pwd.h>
29#include <string.h>
30#include <deflt.h>
31#include <libintl.h>
32#include <locale.h>
33#include <user_attr.h>
34#include <prof_attr.h>
35#include <auth_attr.h>
36
37#define	EXIT_OK		0
38#define	EXIT_FATAL	1
39#define	EXIT_NON_FATAL	2
40
41#ifndef	TEXT_DOMAIN			/* Should be defined by cc -D */
42#define	TEXT_DOMAIN	"SYS_TEST"
43#endif
44
45#define	INCRAUTHS	512
46
47typedef struct cbs {
48	int	auth_cnt;
49	int	auth_max;
50	char	**auths;
51} cbs_t;
52
53static int show_auths(char *, int);
54static int add_auth(const char *, void *, void *);
55static void free_auths(cbs_t *);
56static void simplify(cbs_t *);
57
58static char *progname = "auths";
59
60int
61main(int argc, char *argv[])
62{
63	int		status = EXIT_OK;
64
65	(void) setlocale(LC_ALL, "");
66	(void) textdomain(TEXT_DOMAIN);
67
68	switch (argc) {
69	case 1:
70		status = show_auths(NULL, 0);
71		break;
72	case 2:
73		status = show_auths(argv[argc-1], 0);
74		break;
75	default:
76		while (*++argv) {
77			status = show_auths(*argv, 1);
78			if (status == EXIT_FATAL) {
79				break;
80			}
81		}
82		break;
83	}
84
85	status = (status == EXIT_OK) ? status : EXIT_FATAL;
86	return (status);
87}
88
89static int
90show_auths(char *username, int print_name)
91{
92	int		status = EXIT_OK;
93	struct passwd	*pw;
94	int		i;
95	cbs_t		cbs = { 0, 0, NULL };
96
97	if (username == NULL) {
98		if ((pw = getpwuid(getuid())) == NULL) {
99			status = EXIT_NON_FATAL;
100			(void) fprintf(stderr, "%s: ", progname);
101			(void) fprintf(stderr, gettext("No passwd entry\n"));
102			return (status);
103		}
104		username = pw->pw_name;
105	} else if (getpwnam(username) == NULL) {
106		status = EXIT_NON_FATAL;
107		(void) fprintf(stderr, "%s: %s : ", progname, username);
108		(void) fprintf(stderr, gettext("No such user\n"));
109		return (status);
110	}
111
112	(void) _enum_auths(username, add_auth, NULL, &cbs);
113
114	if (cbs.auth_cnt == 0)
115		status = EXIT_NON_FATAL;
116
117	if (status == EXIT_NON_FATAL) {
118		(void) fprintf(stderr, "%s: %s: ", progname, username);
119		(void) fprintf(stderr, gettext("No authorizations\n"));
120	} else {
121		simplify(&cbs);
122
123		if (print_name)
124			(void) printf("%s: ", username);
125
126		/* print out the auths */
127		for (i = 0; i < cbs.auth_cnt - 1; i++)
128			(void) printf("%s,", cbs.auths[i]);
129
130		/* print out the last entry, without the comma */
131		(void) printf("%s\n", cbs.auths[cbs.auth_cnt - 1]);
132
133		/* free memory allocated for authorizations */
134		free_auths(&cbs);
135	}
136
137	return (status);
138}
139
140/*ARGSUSED*/
141static int
142add_auth(const char *authname, void *ctxt, void *res)
143{
144	cbs_t	*cbs = res;
145
146	if (cbs->auth_cnt >= cbs->auth_max) {
147		cbs->auth_max += INCRAUTHS;
148		cbs->auths = realloc(cbs->auths,
149		    cbs->auth_max * sizeof (char *));
150
151		if (cbs->auths == NULL) {
152			(void) fprintf(stderr, "%s: ", progname);
153			(void) fprintf(stderr, gettext("Out of memory\n"));
154			exit(1);
155		}
156	}
157
158	cbs->auths[cbs->auth_cnt] = strdup(authname);
159	cbs->auth_cnt++;
160
161	return (0);
162}
163
164static void
165free_auths(cbs_t *cbs)
166{
167	int i;
168
169	for (i = 0; i < cbs->auth_cnt; i++)
170		free(cbs->auths[i]);
171
172	free(cbs->auths);
173}
174
175/* We have always ignored .grant in auths(1) */
176static boolean_t
177auth_match(const char *pattern, const char *auth)
178{
179	size_t len = strlen(pattern);
180
181	if (pattern[len - 1] != KV_WILDCHAR)
182		return (B_FALSE);
183
184	return (strncmp(pattern, auth, len - 1) == 0);
185}
186
187static int
188mstrptr(const void *a, const void *b)
189{
190	char *const *ap = a;
191	char *const *bp = b;
192
193	return (strcmp(*ap, *bp));
194}
195
196/*
197 * Simplify the returned authorizations: sort and match wildcards;
198 * we're using here that "*" sorts before any other character.
199 */
200static void
201simplify(cbs_t *cbs)
202{
203	int rem, i;
204
205	/* First we sort */
206	qsort(cbs->auths, cbs->auth_cnt, sizeof (cbs->auths[0]), mstrptr);
207
208	/*
209	 * Then we remove the entries which match a later entry.
210	 * We walk the list, with "i + rem + 1" the cursor for the possible
211	 * candidate for removal. With "rem" we count the removed entries
212	 * and we copy while we're looking for duplicate/superfluous entries.
213	 */
214	for (i = 0, rem = 0; i < cbs->auth_cnt - rem - 1; ) {
215		if (strcmp(cbs->auths[i], cbs->auths[i + rem + 1]) == 0 ||
216		    strchr(cbs->auths[i], KV_WILDCHAR) != NULL &&
217		    auth_match(cbs->auths[i], cbs->auths[i + rem + 1])) {
218			free(cbs->auths[i + rem + 1]);
219			rem++;
220		} else {
221			i++;
222			if (rem > 0)
223				cbs->auths[i] = cbs->auths[i + rem];
224		}
225	}
226
227	cbs->auth_cnt -= rem;
228}
229