xref: /illumos-gate/usr/src/lib/libsecdb/common/chkauthattr.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/mman.h>
33 #include <limits.h>
34 #include <pwd.h>
35 #include <nss_dbdefs.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 *, const char *, char **, int *);
44 static int _chkprof_for_auth(const char *, const char *, char **, int *);
45 int
46 chkauthattr(const char *authname, const char *username)
47 {
48 	int		auth_granted = 0;
49 	char		*auths;
50 	char		*profiles;
51 	userattr_t	*user = NULL;
52 	char		*chkedprof[MAXPROFS];
53 	int		chkedprof_cnt = 0;
54 	int		i;
55 
56 	if (authname == NULL || username == NULL)
57 		return (0);
58 
59 	/* Check against AUTHS_GRANTED and PROFS_GRANTED in policy.conf */
60 	auth_granted = _chk_policy_auth(authname, username, chkedprof,
61 	    &chkedprof_cnt);
62 	if (auth_granted)
63 		goto exit;
64 
65 	if ((user = getusernam(username)) == NULL)
66 		goto exit;
67 
68 	/* Check against authorizations listed in user_attr */
69 	if ((auths = kva_match(user->attr, USERATTR_AUTHS_KW)) != NULL) {
70 		auth_granted = _is_authorized(authname, auths);
71 		if (auth_granted)
72 			goto exit;
73 	}
74 
75 	/* Check against authorizations specified by profiles */
76 	if ((profiles = kva_match(user->attr, USERATTR_PROFILES_KW)) != NULL)
77 		auth_granted = _chkprof_for_auth(profiles, authname,
78 		    chkedprof, &chkedprof_cnt);
79 
80 exit:
81 	/* free memory allocated for checked array */
82 	for (i = 0; i < chkedprof_cnt; i++) {
83 		free(chkedprof[i]);
84 	}
85 
86 	if (user != NULL)
87 		free_userattr(user);
88 
89 	return (auth_granted);
90 }
91 
92 static int
93 _chkprof_for_auth(const char *profs, const char *authname,
94     char **chkedprof, int *chkedprof_cnt)
95 {
96 
97 	char *prof, *lasts, *auths, *profiles;
98 	profattr_t	*pa;
99 	int		i;
100 	int		checked = 0;
101 
102 	for (prof = strtok_r((char *)profs, ",", &lasts); prof != NULL;
103 	    prof = strtok_r(NULL, ",", &lasts)) {
104 
105 		checked = 0;
106 		/* check if this profile has been checked */
107 		for (i = 0; i < *chkedprof_cnt; i++) {
108 			if (strcmp(chkedprof[i], prof) == 0) {
109 				checked = 1;
110 				break;
111 			}
112 		}
113 
114 		if (!checked) {
115 
116 			chkedprof[*chkedprof_cnt] = strdup(prof);
117 			*chkedprof_cnt = *chkedprof_cnt + 1;
118 
119 			if ((pa = getprofnam(prof)) == NULL)
120 				continue;
121 
122 			if ((auths = kva_match(pa->attr,
123 			    PROFATTR_AUTHS_KW)) != NULL) {
124 				if (_is_authorized(authname, auths)) {
125 					free_profattr(pa);
126 					return (1);
127 				}
128 			}
129 			if ((profiles =
130 			    kva_match(pa->attr, PROFATTR_PROFS_KW)) != NULL) {
131 				/* Check for authorization in subprofiles */
132 				if (_chkprof_for_auth(profiles, authname,
133 				    chkedprof, chkedprof_cnt)) {
134 					free_profattr(pa);
135 					return (1);
136 				}
137 			}
138 			free_profattr(pa);
139 		}
140 	}
141 	/* authorization not found in any profile */
142 	return (0);
143 }
144 
145 int
146 _auth_match(const char *pattern, const char *auth)
147 {
148 	size_t len;
149 	char wildcard = KV_WILDCHAR;
150 	char *grant;
151 
152 	len = strlen(pattern);
153 
154 	/*
155 	 * If the wildcard is not in the last position in the string, don't
156 	 * match against it.
157 	 */
158 	if (pattern[len-1] != wildcard)
159 		return (0);
160 
161 	/*
162 	 * If the strings are identical up to the wildcard and auth does not
163 	 * end in "grant", then we have a match.
164 	 */
165 	if (strncmp(pattern, auth, len-1) == 0) {
166 		grant = strrchr(auth, '.');
167 		if (grant != NULL) {
168 			if (strncmp(grant + 1, "grant", 5) != NULL)
169 				return (1);
170 		}
171 	}
172 
173 	return (0);
174 }
175 
176 static int
177 _is_authorized(const char *authname, char *auths)
178 {
179 	int	found = 0;	/* have we got a match, yet */
180 	char	wildcard = '*';
181 	char	*auth;		/* current authorization being compared */
182 	char	*buf;
183 	char	*lasts;
184 
185 	buf = strdup(auths);
186 	for (auth = strtok_r(auths, ",", &lasts); auth != NULL && !found;
187 	    auth = strtok_r(NULL, ",", &lasts)) {
188 		if (strcmp((char *)authname, auth) == 0) {
189 			/* Exact match.  We're done. */
190 			found = 1;
191 		} else if (strchr(auth, wildcard) != NULL) {
192 			if (_auth_match(auth, authname)) {
193 				found = 1;
194 				break;
195 			}
196 		}
197 	}
198 
199 	free(buf);
200 
201 	return (found);
202 }
203 
204 
205 /*
206  * read /etc/security/policy.conf for AUTHS_GRANTED.
207  * return 1 if found matching authname.
208  * Otherwise, read PROFS_GRANTED to see if authname exists in any
209  * default profiles.
210  */
211 static int
212 _chk_policy_auth(const char *authname, const char *username, char **chkedprof,
213     int *chkedprof_cnt)
214 {
215 	char	*auths = NULL;
216 	char	*profs = NULL;
217 	int	ret = 1;
218 
219 	if (_get_user_defs(username, &auths, &profs) != 0)
220 		return (0);
221 
222 	if (auths != NULL) {
223 		if (_is_authorized(authname, auths))
224 			goto exit;
225 	}
226 
227 	if (profs != NULL) {
228 		if (_chkprof_for_auth(profs, authname, chkedprof,
229 		    chkedprof_cnt))
230 			goto exit;
231 	}
232 	ret = 0;
233 
234 exit:
235 	_free_user_defs(auths, profs);
236 	return (ret);
237 }
238 
239 #define	CONSOLE "/dev/console"
240 
241 static int
242 is_cons_user(const char *user)
243 {
244 	struct stat	cons;
245 	struct passwd	pw;
246 	char		pwbuf[NSS_BUFLEN_PASSWD];
247 
248 	if (user == NULL) {
249 		return (0);
250 	}
251 	if (stat(CONSOLE, &cons) == -1) {
252 		return (0);
253 	}
254 	if (getpwnam_r(user, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
255 		return (0);
256 	}
257 
258 	return (pw.pw_uid == cons.st_uid);
259 }
260 
261 
262 int
263 _get_user_defs(const char *user, char **def_auth, char **def_prof)
264 {
265 	char *cp;
266 	char *profs;
267 	void	*defp;
268 
269 	if ((defp = defopen_r(AUTH_POLICY)) == NULL) {
270 		if (def_auth != NULL) {
271 			*def_auth = NULL;
272 		}
273 		if (def_prof != NULL) {
274 			*def_prof = NULL;
275 		}
276 		return (-1);
277 	}
278 
279 	if (def_auth != NULL) {
280 		if ((cp = defread_r(DEF_AUTH, defp)) != NULL) {
281 			if ((*def_auth = strdup(cp)) == NULL) {
282 				defclose_r(defp);
283 				return (-1);
284 			}
285 		} else {
286 			*def_auth = NULL;
287 		}
288 	}
289 	if (def_prof != NULL) {
290 		if (is_cons_user(user) &&
291 		    (cp = defread_r(DEF_CONSUSER, defp)) != NULL) {
292 			if ((*def_prof = strdup(cp)) == NULL) {
293 				defclose_r(defp);
294 				return (-1);
295 			}
296 		}
297 		if ((cp = defread_r(DEF_PROF, defp)) != NULL) {
298 			int	prof_len;
299 
300 			if (*def_prof == NULL) {
301 				if ((*def_prof = strdup(cp)) == NULL) {
302 					defclose_r(defp);
303 					return (-1);
304 				}
305 				defclose_r(defp);
306 				return (0);
307 			}
308 
309 			/* concatenate def profs with "," separator */
310 			prof_len = strlen(*def_prof) + strlen(cp) + 2;
311 			if ((profs = malloc(prof_len)) == NULL) {
312 				free(*def_prof);
313 				*def_prof = NULL;
314 				defclose_r(defp);
315 				return (-1);
316 			}
317 			(void) snprintf(profs, prof_len, "%s,%s", *def_prof,
318 			    cp);
319 			free(*def_prof);
320 			*def_prof = profs;
321 		}
322 	}
323 
324 	defclose_r(defp);
325 	return (0);
326 }
327 
328 
329 void
330 _free_user_defs(char *def_auth, char *def_prof)
331 {
332 	free(def_auth);
333 	free(def_prof);
334 }
335