xref: /illumos-gate/usr/src/lib/libsecdb/common/chkauthattr.c (revision 5181c2afafac4c39b4d5d9d8dd14e6ba0d227db2)
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 <alloca.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <nss_dbdefs.h>
32 #include <deflt.h>
33 #include <auth_attr.h>
34 #include <prof_attr.h>
35 #include <user_attr.h>
36 
37 #define	COPYTOSTACK(dst, csrc)		{	\
38 		size_t len = strlen(csrc) + 1;	\
39 		dst = alloca(len);		\
40 		(void) memcpy(dst, csrc, len);	\
41 	}
42 
43 static kva_t *get_default_attrs(const char *);
44 static void free_default_attrs(kva_t *);
45 
46 /*
47  * Enumeration functions for auths and profiles; the enumeration functions
48  * take a callback with four arguments:
49  *	const char *		profile name (or NULL unless wantattr is false)
50  *	kva_t *			attributes (or NULL unless wantattr is true)
51  *	void *			context
52  *	void *			pointer to the result
53  * When the call back returns non-zero, the enumeration ends.
54  * The function might be NULL but only for profiles as we are always collecting
55  * all the profiles.
56  * Both the auths and the profiles arguments may be NULL.
57  *
58  * These should be the only implementation of the algorithm of "finding me
59  * all the profiles/athorizations/keywords/etc.
60  */
61 
62 #define	CONSUSER_PROFILE_KW		"consprofile"
63 #define	DEF_LOCK_AFTER_RETRIES		"LOCK_AFTER_RETRIES="
64 
65 static struct dfltplcy {
66 	char *attr;
67 	const char *defkw;
68 } dfltply[] = {
69 	/* CONSUSER MUST BE FIRST! */
70 	{ CONSUSER_PROFILE_KW,			DEF_CONSUSER},
71 	{ PROFATTR_AUTHS_KW,			DEF_AUTH},
72 	{ PROFATTR_PROFS_KW,			DEF_PROF},
73 	{ USERATTR_LIMPRIV_KW,			DEF_LIMITPRIV},
74 	{ USERATTR_DFLTPRIV_KW,			DEF_DFLTPRIV},
75 	{ USERATTR_LOCK_AFTER_RETRIES_KW,	DEF_LOCK_AFTER_RETRIES}
76 };
77 
78 #define	NDFLTPLY	(sizeof (dfltply)/sizeof (struct dfltplcy))
79 #define	GETCONSPROF(a)	(kva_match((a), CONSUSER_PROFILE_KW))
80 #define	GETPROF(a)	(kva_match((a), PROFATTR_PROFS_KW))
81 
82 /*
83  * Enumerate profiles from listed profiles.
84  */
85 int
86 _enum_common_p(const char *cprofiles,
87     int (*cb)(const char *, kva_t *, void *, void *),
88     void *ctxt, void *pres, boolean_t wantattr,
89     int *pcnt, char *profs[MAXPROFS])
90 {
91 	char *prof, *last;
92 	char *profiles;
93 	profattr_t *pa;
94 	int i;
95 	int res = 0;
96 
97 	if (cprofiles == NULL)
98 		return (0);
99 
100 	if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == NULL)
101 		return (0);
102 
103 	COPYTOSTACK(profiles, cprofiles)
104 
105 	while (prof = strtok_r(profiles, KV_SEPSTR, &last)) {
106 
107 		profiles = NULL;	/* For next iterations of strtok_r */
108 
109 		for (i = 0; i < *pcnt; i++)
110 			if (strcmp(profs[i], prof) == 0)
111 				goto cont;
112 
113 		if (*pcnt >= MAXPROFS)		/* oops: too many profs */
114 			return (-1);
115 
116 		/* Add it */
117 		profs[(*pcnt)++] = strdup(prof);
118 
119 		if (strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0)
120 			break;
121 
122 		/* find the profiles for this profile */
123 		pa = getprofnam(prof);
124 
125 		if (cb != NULL && (!wantattr || pa != NULL && pa->attr != NULL))
126 			res = cb(prof, pa ? pa->attr : NULL, ctxt, pres);
127 
128 		if (pa != NULL) {
129 			if (res == 0 && pa->attr != NULL) {
130 				res = _enum_common_p(GETPROF(pa->attr), cb,
131 				    ctxt, pres, wantattr, pcnt, profs);
132 			}
133 			free_profattr(pa);
134 		}
135 		if (res != 0)
136 			return (res);
137 cont:
138 		continue;
139 	}
140 	return (res);
141 }
142 
143 /*
144  * Enumerate all attributes associated with a username and the profiles
145  * associated with the user.
146  */
147 static int
148 _enum_common(const char *username,
149     int (*cb)(const char *, kva_t *, void *, void *),
150     void *ctxt, void *pres, boolean_t wantattr)
151 {
152 	userattr_t *ua;
153 	int res = 0;
154 	int cnt = 0;
155 	char *profs[MAXPROFS];
156 	kva_t *kattrs;
157 
158 	if (cb == NULL)
159 		return (-1);
160 
161 	ua = getusernam(username);
162 
163 	if (ua != NULL) {
164 		if (ua->attr != NULL) {
165 			if (wantattr)
166 				res = cb(NULL, ua->attr, ctxt, pres);
167 			if (res == 0) {
168 				res = _enum_common_p(GETPROF(ua->attr),
169 				    cb, ctxt, pres, wantattr, &cnt, profs);
170 			}
171 		}
172 		free_userattr(ua);
173 		if (res != 0)
174 			return (res);
175 	}
176 
177 	if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) &&
178 	    (kattrs = get_default_attrs(username)) != NULL) {
179 
180 		res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres,
181 		    wantattr, &cnt, profs);
182 
183 		if (res == 0) {
184 			res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres,
185 			    wantattr, &cnt, profs);
186 		}
187 
188 		if (res == 0 && wantattr)
189 			res = cb(NULL, kattrs, ctxt, pres);
190 
191 		free_default_attrs(kattrs);
192 	}
193 
194 	free_proflist(profs, cnt);
195 
196 	return (res);
197 }
198 
199 /*
200  * Enumerate profiles with a username argument.
201  */
202 int
203 _enum_profs(const char *username,
204     int (*cb)(const char *, kva_t *, void *, void *),
205     void *ctxt, void *pres)
206 {
207 	return (_enum_common(username, cb, ctxt, pres, B_FALSE));
208 }
209 
210 /*
211  * Enumerate attributes with a username argument.
212  */
213 int
214 _enum_attrs(const char *username,
215     int (*cb)(const char *, kva_t *, void *, void *),
216     void *ctxt, void *pres)
217 {
218 	return (_enum_common(username, cb, ctxt, pres, B_TRUE));
219 }
220 
221 
222 /*
223  * Enumerate authorizations in the "auths" argument.
224  */
225 static int
226 _enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *),
227     void *ctxt, void *pres)
228 {
229 	char *auth, *last, *auths;
230 	int res = 0;
231 
232 	if (cauths == NULL || cb == NULL)
233 		return (0);
234 
235 	COPYTOSTACK(auths, cauths)
236 
237 	while (auth = strtok_r(auths, KV_SEPSTR, &last)) {
238 		auths = NULL;		/* For next iterations of strtok_r */
239 
240 		res = cb(auth, ctxt, pres);
241 
242 		if (res != 0)
243 			return (res);
244 	}
245 	return (res);
246 }
247 
248 /*
249  * Magic struct and function to allow using the _enum_attrs functions to
250  * enumerate the authorizations.
251  */
252 typedef struct ccomm2auth {
253 	int (*cb)(const char *, void *, void *);
254 	void *ctxt;
255 } ccomm2auth;
256 
257 /*ARGSUSED*/
258 static int
259 comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres)
260 {
261 	ccomm2auth *ca = ctxt;
262 	char *auths;
263 
264 	/* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */
265 	auths = kva_match(attr, PROFATTR_AUTHS_KW);
266 	return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres));
267 }
268 
269 /*
270  * Enumerate authorizations for username.
271  */
272 int
273 _enum_auths(const char *username,
274     int (*cb)(const char *, void *, void *),
275     void *ctxt, void *pres)
276 {
277 	ccomm2auth c2a;
278 
279 	if (cb == NULL)
280 		return (-1);
281 
282 	c2a.cb = cb;
283 	c2a.ctxt = ctxt;
284 
285 	return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE));
286 }
287 
288 int
289 _auth_match(const char *pattern, const char *auth)
290 {
291 	size_t len;
292 	char *grant;
293 
294 	len = strlen(pattern);
295 
296 	/*
297 	 * If the wildcard is not in the last position in the string, don't
298 	 * match against it.
299 	 */
300 	if (pattern[len-1] != KV_WILDCHAR)
301 		return (0);
302 
303 	/*
304 	 * If the strings are identical up to the wildcard and auth does not
305 	 * end in "grant", then we have a match.
306 	 */
307 	if (strncmp(pattern, auth, len-1) == 0) {
308 		grant = strrchr(auth, '.');
309 		if (grant != NULL) {
310 			if (strncmp(grant + 1, "grant", 5) != NULL)
311 				return (1);
312 		}
313 	}
314 
315 	return (0);
316 }
317 
318 static int
319 _is_authorized(const char *auth, void *authname, void *res)
320 {
321 	int *resp = res;
322 
323 	if (strcmp(authname, auth) == 0 ||
324 	    (strchr(auth, KV_WILDCHAR) != NULL &&
325 	    _auth_match(auth, authname))) {
326 		*resp = 1;
327 		return (1);
328 	}
329 
330 	return (0);
331 }
332 
333 int
334 chkauthattr(const char *authname, const char *username)
335 {
336 	int		auth_granted = 0;
337 
338 	if (authname == NULL || username == NULL)
339 		return (0);
340 
341 	(void) _enum_auths(username, _is_authorized, (char *)authname,
342 	    &auth_granted);
343 
344 	return (auth_granted);
345 }
346 
347 #define	CONSOLE_USER_LINK "/dev/vt/console_user"
348 
349 static int
350 is_cons_user(const char *user)
351 {
352 	struct stat	cons;
353 	struct passwd	pw;
354 	char		pwbuf[NSS_BUFLEN_PASSWD];
355 
356 	if (user == NULL) {
357 		return (0);
358 	}
359 	if (stat(CONSOLE_USER_LINK, &cons) == -1) {
360 		return (0);
361 	}
362 	if (getpwnam_r(user, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
363 		return (0);
364 	}
365 
366 	return (pw.pw_uid == cons.st_uid);
367 }
368 
369 static void
370 free_default_attrs(kva_t *kva)
371 {
372 	int i;
373 
374 	for (i = 0; i < kva->length; i++)
375 		free(kva->data[i].value);
376 
377 	free(kva);
378 }
379 
380 /*
381  * Return the default attributes; this are ignored when a STOP profile
382  * was found.
383  */
384 static kva_t *
385 get_default_attrs(const char *user)
386 {
387 	void *defp;
388 	kva_t *kva;
389 	int i;
390 
391 	kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY);
392 
393 	if (kva == NULL)
394 		return (NULL);
395 
396 	kva->data = (kv_t *)(void *)&kva[1];
397 	kva->length = 0;
398 
399 	if ((defp = defopen_r(AUTH_POLICY)) == NULL)
400 		goto return_null;
401 
402 	for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) {
403 		char *cp = defread_r(dfltply[i].defkw, defp);
404 
405 		if (cp == NULL)
406 			continue;
407 		if ((cp = strdup(cp)) == NULL)
408 			goto return_null;
409 
410 		kva->data[kva->length].key = dfltply[i].attr;
411 		kva->data[kva->length++].value = cp;
412 	}
413 
414 	(void) defclose_r(defp);
415 	return (kva);
416 
417 return_null:
418 	if (defp != NULL)
419 		(void) defclose_r(defp);
420 
421 	free_default_attrs(kva);
422 	return (NULL);
423 }
424