chkauthattr.c revision 12273:63678502e95e
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
43static kva_t *get_default_attrs(const char *);
44static 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
65static 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 */
85int
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);
137cont:
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 */
147static 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 */
202int
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 */
213int
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 */
225static 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 */
252typedef struct ccomm2auth {
253	int (*cb)(const char *, void *, void *);
254	void *ctxt;
255} ccomm2auth;
256
257/*ARGSUSED*/
258static int
259comm2auth(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 */
272int
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
288int
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
318static 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
333int
334chkauthattr(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
349static int
350is_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
369static void
370free_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 */
384static kva_t *
385get_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
417return_null:
418	if (defp != NULL)
419		(void) defclose_r(defp);
420
421	free_default_attrs(kva);
422	return (NULL);
423}
424