xref: /illumos-gate/usr/src/cmd/auths/auths.c (revision a61ed2ce7a86a4d6428f2a83eb4739fae945447e)
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 
47 typedef struct cbs {
48 	int	auth_cnt;
49 	int	auth_max;
50 	char	**auths;
51 } cbs_t;
52 
53 static int show_auths(char *, int);
54 static int add_auth(const char *, void *, void *);
55 static void free_auths(cbs_t *);
56 static void simplify(cbs_t *);
57 
58 static char *progname = "auths";
59 
60 int
61 main(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 
89 static int
90 show_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*/
141 static int
142 add_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 
164 static void
165 free_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) */
176 static boolean_t
177 auth_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 
187 static int
188 mstrptr(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  */
200 static void
201 simplify(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