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 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/mman.h>
35 #include <limits.h>
36 #include <deflt.h>
37 #include <auth_attr.h>
38 #include <prof_attr.h>
39 #include <user_attr.h>
40 
41 
42 static int _is_authorized(const char *, char *);
43 static int _chk_policy_auth(const char *, char **, int *);
44 static int _chkprof_for_auth(const char *, const char *, char **, int *);
45 
46 
47 int
48 chkauthattr(const char *authname, const char *username)
49 {
50 	int		auth_granted = 0;
51 	char		*auths;
52 	char		*profiles;
53 	userattr_t	*user = NULL;
54 	char		*chkedprof[MAXPROFS];
55 	int		chkedprof_cnt = 0;
56 	int		i;
57 
58 	if (authname == NULL || username == NULL)
59 		return (0);
60 
61 	/* Check against AUTHS_GRANTED and PROFS_GRANTED in policy.conf */
62 	auth_granted = _chk_policy_auth(authname, chkedprof, &chkedprof_cnt);
63 	if (auth_granted)
64 		goto exit;
65 
66 	if ((user = getusernam(username)) == NULL)
67 		goto exit;
68 
69 	/* Check against authorizations listed in user_attr */
70 	if ((auths = kva_match(user->attr, USERATTR_AUTHS_KW)) != NULL) {
71 		auth_granted = _is_authorized(authname, auths);
72 		if (auth_granted)
73 			goto exit;
74 	}
75 
76 	/* Check against authorizations specified by profiles */
77 	if ((profiles = kva_match(user->attr, USERATTR_PROFILES_KW)) != NULL)
78 		auth_granted = _chkprof_for_auth(profiles, authname,
79 		    chkedprof, &chkedprof_cnt);
80 
81 exit:
82 	/* free memory allocated for checked array */
83 	for (i = 0; i < chkedprof_cnt; i++) {
84 		free(chkedprof[i]);
85 	}
86 
87 	if (user != NULL)
88 		free_userattr(user);
89 
90 	return (auth_granted);
91 }
92 
93 static int
94 _chkprof_for_auth(const char *profs, const char *authname,
95     char **chkedprof, int *chkedprof_cnt)
96 {
97 
98 	char *prof, *lasts, *auths, *profiles;
99 	profattr_t	*pa;
100 	int		i;
101 	int		checked = 0;
102 
103 	for (prof = strtok_r((char *)profs, ",", &lasts); prof != NULL;
104 	    prof = strtok_r(NULL, ",", &lasts)) {
105 
106 		checked = 0;
107 		/* check if this profile has been checked */
108 		for (i = 0; i < *chkedprof_cnt; i++) {
109 			if (strcmp(chkedprof[i], prof) == 0) {
110 				checked = 1;
111 				break;
112 			}
113 		}
114 
115 		if (!checked) {
116 
117 			chkedprof[*chkedprof_cnt] = strdup(prof);
118 			*chkedprof_cnt = *chkedprof_cnt + 1;
119 
120 			if ((pa = getprofnam(prof)) == NULL)
121 				continue;
122 
123 			if ((auths = kva_match(pa->attr,
124 			    PROFATTR_AUTHS_KW)) != NULL) {
125 				if (_is_authorized(authname, auths)) {
126 					free_profattr(pa);
127 					return (1);
128 				}
129 			}
130 			if ((profiles =
131 			    kva_match(pa->attr, PROFATTR_PROFS_KW)) != NULL) {
132 				/* Check for authorization in subprofiles */
133 				if (_chkprof_for_auth(profiles, authname,
134 				    chkedprof, chkedprof_cnt)) {
135 					free_profattr(pa);
136 					return (1);
137 				}
138 			}
139 			free_profattr(pa);
140 		}
141 	}
142 	/* authorization not found in any profile */
143 	return (0);
144 }
145 
146 int
147 _auth_match(const char *pattern, const char *auth)
148 {
149 	size_t len;
150 	char wildcard = KV_WILDCHAR;
151 	char *grant;
152 
153 	len = strlen(pattern);
154 
155 	/*
156 	 * If the wildcard is not in the last position in the string, don't
157 	 * match against it.
158 	 */
159 	if (pattern[len-1] != wildcard)
160 		return (0);
161 
162 	/*
163 	 * If the strings are identical up to the wildcard and auth does not
164 	 * end in "grant", then we have a match.
165 	 */
166 	if (strncmp(pattern, auth, len-1) == 0) {
167 		grant = strrchr(auth, '.');
168 		if (grant != NULL) {
169 			if (strncmp(grant + 1, "grant", 5) != NULL)
170 				return (1);
171 		}
172 	}
173 
174 	return (0);
175 }
176 
177 static int
178 _is_authorized(const char *authname, char *auths)
179 {
180 	int	found = 0;	/* have we got a match, yet */
181 	char	wildcard = '*';
182 	char	*auth;		/* current authorization being compared */
183 	char	*buf;
184 	char	*lasts;
185 
186 	buf = strdup(auths);
187 	for (auth = strtok_r(auths, ",", &lasts); auth != NULL && !found;
188 	    auth = strtok_r(NULL, ",", &lasts)) {
189 		if (strcmp((char *)authname, auth) == 0) {
190 			/* Exact match.  We're done. */
191 			found = 1;
192 		} else if (strchr(auth, wildcard) != NULL) {
193 			if (_auth_match(auth, authname)) {
194 				found = 1;
195 				break;
196 			}
197 		}
198 	}
199 
200 	free(buf);
201 
202 	return (found);
203 }
204 
205 
206 int
207 _get_auth_policy(char **def_auth, char **def_prof)
208 {
209 	char *cp;
210 
211 	if (defopen(AUTH_POLICY) != 0)
212 		return (-1);
213 
214 	cp = defread(DEF_AUTH);
215 	if (cp != NULL) {
216 		*def_auth = strdup(cp);
217 		if (*def_auth == NULL)
218 			return (-1);
219 	} else {
220 		*def_auth = NULL;
221 	}
222 
223 	cp = defread(DEF_PROF);
224 	if (cp != NULL) {
225 		*def_prof = strdup(cp);
226 		if (*def_prof == NULL) {
227 			free(*def_auth);
228 			return (-1);
229 		}
230 	} else {
231 		*def_prof = NULL;
232 	}
233 
234 	(void) defopen(NULL);
235 	return (0);
236 }
237 
238 void
239 _free_auth_policy(char *def_auth, char *def_prof)
240 {
241 	free(def_auth);
242 	free(def_prof);
243 }
244 
245 /*
246  * read /etc/security/policy.conf for AUTHS_GRANTED.
247  * return 1 if found matching authname.
248  * Otherwise, read PROFS_GRANTED to see if authname exists in any
249  * default profiles.
250  */
251 static int
252 _chk_policy_auth(const char *authname, char **chkedprof, int *chkedprof_cnt)
253 {
254 	char	*auths, *profs;
255 	int	ret = 1;
256 
257 	if (_get_auth_policy(&auths, &profs) != 0)
258 		return (0);
259 
260 	if (auths != NULL) {
261 		if (_is_authorized(authname, auths))
262 			goto exit;
263 	}
264 
265 	if (profs != NULL) {
266 		if (_chkprof_for_auth(profs, authname, chkedprof,
267 		    chkedprof_cnt))
268 			goto exit;
269 	}
270 	ret = 0;
271 
272 exit:
273 	_free_auth_policy(auths, profs);
274 	return (ret);
275 }
276