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 			free_proflist(profs, cnt);
175 			return (res);
176 		}
177 	}
178 
179 	if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) &&
180 	    (kattrs = get_default_attrs(username)) != NULL) {
181 
182 		res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres,
183 		    wantattr, &cnt, profs);
184 
185 		if (res == 0) {
186 			res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres,
187 			    wantattr, &cnt, profs);
188 		}
189 
190 		if (res == 0 && wantattr)
191 			res = cb(NULL, kattrs, ctxt, pres);
192 
193 		free_default_attrs(kattrs);
194 	}
195 
196 	free_proflist(profs, cnt);
197 
198 	return (res);
199 }
200 
201 /*
202  * Enumerate profiles with a username argument.
203  */
204 int
205 _enum_profs(const char *username,
206     int (*cb)(const char *, kva_t *, void *, void *),
207     void *ctxt, void *pres)
208 {
209 	return (_enum_common(username, cb, ctxt, pres, B_FALSE));
210 }
211 
212 /*
213  * Enumerate attributes with a username argument.
214  */
215 int
216 _enum_attrs(const char *username,
217     int (*cb)(const char *, kva_t *, void *, void *),
218     void *ctxt, void *pres)
219 {
220 	return (_enum_common(username, cb, ctxt, pres, B_TRUE));
221 }
222 
223 
224 /*
225  * Enumerate authorizations in the "auths" argument.
226  */
227 static int
228 _enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *),
229     void *ctxt, void *pres)
230 {
231 	char *auth, *last, *auths;
232 	int res = 0;
233 
234 	if (cauths == NULL || cb == NULL)
235 		return (0);
236 
237 	COPYTOSTACK(auths, cauths)
238 
239 	while (auth = strtok_r(auths, KV_SEPSTR, &last)) {
240 		auths = NULL;		/* For next iterations of strtok_r */
241 
242 		res = cb(auth, ctxt, pres);
243 
244 		if (res != 0)
245 			return (res);
246 	}
247 	return (res);
248 }
249 
250 /*
251  * Magic struct and function to allow using the _enum_attrs functions to
252  * enumerate the authorizations.
253  */
254 typedef struct ccomm2auth {
255 	int (*cb)(const char *, void *, void *);
256 	void *ctxt;
257 } ccomm2auth;
258 
259 /*ARGSUSED*/
260 static int
261 comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres)
262 {
263 	ccomm2auth *ca = ctxt;
264 	char *auths;
265 
266 	/* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */
267 	auths = kva_match(attr, PROFATTR_AUTHS_KW);
268 	return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres));
269 }
270 
271 /*
272  * Enumerate authorizations for username.
273  */
274 int
275 _enum_auths(const char *username,
276     int (*cb)(const char *, void *, void *),
277     void *ctxt, void *pres)
278 {
279 	ccomm2auth c2a;
280 
281 	if (cb == NULL)
282 		return (-1);
283 
284 	c2a.cb = cb;
285 	c2a.ctxt = ctxt;
286 
287 	return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE));
288 }
289 
290 int
291 _auth_match(const char *pattern, const char *auth)
292 {
293 	size_t len;
294 	char *grant;
295 
296 	len = strlen(pattern);
297 
298 	/*
299 	 * If the wildcard is not in the last position in the string, don't
300 	 * match against it.
301 	 */
302 	if (pattern[len-1] != KV_WILDCHAR)
303 		return (0);
304 
305 	/*
306 	 * If the strings are identical up to the wildcard and auth does not
307 	 * end in "grant", then we have a match.
308 	 */
309 	if (strncmp(pattern, auth, len-1) == 0) {
310 		grant = strrchr(auth, '.');
311 		if (grant != NULL) {
312 			if (strncmp(grant + 1, "grant", 5) != NULL)
313 				return (1);
314 		}
315 	}
316 
317 	return (0);
318 }
319 
320 static int
321 _is_authorized(const char *auth, void *authname, void *res)
322 {
323 	int *resp = res;
324 
325 	if (strcmp(authname, auth) == 0 ||
326 	    (strchr(auth, KV_WILDCHAR) != NULL &&
327 	    _auth_match(auth, authname))) {
328 		*resp = 1;
329 		return (1);
330 	}
331 
332 	return (0);
333 }
334 
335 int
336 chkauthattr(const char *authname, const char *username)
337 {
338 	int		auth_granted = 0;
339 
340 	if (authname == NULL || username == NULL)
341 		return (0);
342 
343 	(void) _enum_auths(username, _is_authorized, (char *)authname,
344 	    &auth_granted);
345 
346 	return (auth_granted);
347 }
348 
349 #define	CONSOLE_USER_LINK "/dev/vt/console_user"
350 
351 static int
352 is_cons_user(const char *user)
353 {
354 	struct stat	cons;
355 	struct passwd	pw;
356 	char		pwbuf[NSS_BUFLEN_PASSWD];
357 
358 	if (user == NULL) {
359 		return (0);
360 	}
361 	if (stat(CONSOLE_USER_LINK, &cons) == -1) {
362 		return (0);
363 	}
364 	if (getpwnam_r(user, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
365 		return (0);
366 	}
367 
368 	return (pw.pw_uid == cons.st_uid);
369 }
370 
371 static void
372 free_default_attrs(kva_t *kva)
373 {
374 	int i;
375 
376 	for (i = 0; i < kva->length; i++)
377 		free(kva->data[i].value);
378 
379 	free(kva);
380 }
381 
382 /*
383  * Return the default attributes; this are ignored when a STOP profile
384  * was found.
385  */
386 static kva_t *
387 get_default_attrs(const char *user)
388 {
389 	void *defp;
390 	kva_t *kva;
391 	int i;
392 
393 	kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY);
394 
395 	if (kva == NULL)
396 		return (NULL);
397 
398 	kva->data = (kv_t *)(void *)&kva[1];
399 	kva->length = 0;
400 
401 	if ((defp = defopen_r(AUTH_POLICY)) == NULL)
402 		goto return_null;
403 
404 	for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) {
405 		char *cp = defread_r(dfltply[i].defkw, defp);
406 
407 		if (cp == NULL)
408 			continue;
409 		if ((cp = strdup(cp)) == NULL)
410 			goto return_null;
411 
412 		kva->data[kva->length].key = dfltply[i].attr;
413 		kva->data[kva->length++].value = cp;
414 	}
415 
416 	(void) defclose_r(defp);
417 	return (kva);
418 
419 return_null:
420 	if (defp != NULL)
421 		(void) defclose_r(defp);
422 
423 	free_default_attrs(kva);
424 	return (NULL);
425 }
426