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