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