usr/src/lib/libsecdb/common/chkauthattr.c
changeset 12273 63678502e95e
parent 12195 cf3a8ea2dcfd
child 12471 10160519e417
--- a/usr/src/lib/libsecdb/common/chkauthattr.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/common/chkauthattr.c	Wed Apr 28 10:01:37 2010 +0200
@@ -22,14 +22,11 @@
  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+#include <alloca.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <limits.h>
 #include <pwd.h>
 #include <nss_dbdefs.h>
 #include <deflt.h>
@@ -37,115 +34,261 @@
 #include <prof_attr.h>
 #include <user_attr.h>
 
-
-static int _is_authorized(const char *, char *);
-static int _chk_policy_auth(const char *, const char *, char **, int *);
-static int _chkprof_for_auth(const char *, const char *, char **, int *);
-int
-chkauthattr(const char *authname, const char *username)
-{
-	int		auth_granted = 0;
-	char		*auths;
-	char		*profiles;
-	userattr_t	*user = NULL;
-	char		*chkedprof[MAXPROFS];
-	int		chkedprof_cnt = 0;
-	int		i;
-
-	if (authname == NULL || username == NULL)
-		return (0);
-
-	/* Check against AUTHS_GRANTED and PROFS_GRANTED in policy.conf */
-	auth_granted = _chk_policy_auth(authname, username, chkedprof,
-	    &chkedprof_cnt);
-	if (auth_granted)
-		goto exit;
-
-	if ((user = getusernam(username)) == NULL)
-		goto exit;
-
-	/* Check against authorizations listed in user_attr */
-	if ((auths = kva_match(user->attr, USERATTR_AUTHS_KW)) != NULL) {
-		auth_granted = _is_authorized(authname, auths);
-		if (auth_granted)
-			goto exit;
-	}
-
-	/* Check against authorizations specified by profiles */
-	if ((profiles = kva_match(user->attr, USERATTR_PROFILES_KW)) != NULL)
-		auth_granted = _chkprof_for_auth(profiles, authname,
-		    chkedprof, &chkedprof_cnt);
-
-exit:
-	/* free memory allocated for checked array */
-	for (i = 0; i < chkedprof_cnt; i++) {
-		free(chkedprof[i]);
+#define	COPYTOSTACK(dst, csrc)		{	\
+		size_t len = strlen(csrc) + 1;	\
+		dst = alloca(len);		\
+		(void) memcpy(dst, csrc, len);	\
 	}
 
-	if (user != NULL)
-		free_userattr(user);
+static kva_t *get_default_attrs(const char *);
+static void free_default_attrs(kva_t *);
 
-	return (auth_granted);
-}
+/*
+ * Enumeration functions for auths and profiles; the enumeration functions
+ * take a callback with four arguments:
+ *	const char *		profile name (or NULL unless wantattr is false)
+ *	kva_t *			attributes (or NULL unless wantattr is true)
+ *	void *			context
+ *	void *			pointer to the result
+ * When the call back returns non-zero, the enumeration ends.
+ * The function might be NULL but only for profiles as we are always collecting
+ * all the profiles.
+ * Both the auths and the profiles arguments may be NULL.
+ *
+ * These should be the only implementation of the algorithm of "finding me
+ * all the profiles/athorizations/keywords/etc.
+ */
 
-static int
-_chkprof_for_auth(const char *profs, const char *authname,
-    char **chkedprof, int *chkedprof_cnt)
-{
+#define	CONSUSER_PROFILE_KW		"consprofile"
+#define	DEF_LOCK_AFTER_RETRIES		"LOCK_AFTER_RETRIES="
 
-	char *prof, *lasts, *auths, *profiles;
-	profattr_t	*pa;
-	int		i;
-	int		checked = 0;
+static struct dfltplcy {
+	char *attr;
+	const char *defkw;
+} dfltply[] = {
+	/* CONSUSER MUST BE FIRST! */
+	{ CONSUSER_PROFILE_KW,			DEF_CONSUSER},
+	{ PROFATTR_AUTHS_KW,			DEF_AUTH},
+	{ PROFATTR_PROFS_KW,			DEF_PROF},
+	{ USERATTR_LIMPRIV_KW,			DEF_LIMITPRIV},
+	{ USERATTR_DFLTPRIV_KW,			DEF_DFLTPRIV},
+	{ USERATTR_LOCK_AFTER_RETRIES_KW,	DEF_LOCK_AFTER_RETRIES}
+};
 
-	for (prof = strtok_r((char *)profs, ",", &lasts); prof != NULL;
-	    prof = strtok_r(NULL, ",", &lasts)) {
+#define	NDFLTPLY	(sizeof (dfltply)/sizeof (struct dfltplcy))
+#define	GETCONSPROF(a)	(kva_match((a), CONSUSER_PROFILE_KW))
+#define	GETPROF(a)	(kva_match((a), PROFATTR_PROFS_KW))
 
-		checked = 0;
-		/* check if this profile has been checked */
-		for (i = 0; i < *chkedprof_cnt; i++) {
-			if (strcmp(chkedprof[i], prof) == 0) {
-				checked = 1;
-				break;
-			}
-		}
+/*
+ * Enumerate profiles from listed profiles.
+ */
+int
+_enum_common_p(const char *cprofiles,
+    int (*cb)(const char *, kva_t *, void *, void *),
+    void *ctxt, void *pres, boolean_t wantattr,
+    int *pcnt, char *profs[MAXPROFS])
+{
+	char *prof, *last;
+	char *profiles;
+	profattr_t *pa;
+	int i;
+	int res = 0;
 
-		if (!checked) {
+	if (cprofiles == NULL)
+		return (0);
 
-			chkedprof[*chkedprof_cnt] = strdup(prof);
-			*chkedprof_cnt = *chkedprof_cnt + 1;
+	if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == NULL)
+		return (0);
+
+	COPYTOSTACK(profiles, cprofiles)
+
+	while (prof = strtok_r(profiles, KV_SEPSTR, &last)) {
 
-			if ((pa = getprofnam(prof)) == NULL)
-				continue;
+		profiles = NULL;	/* For next iterations of strtok_r */
+
+		for (i = 0; i < *pcnt; i++)
+			if (strcmp(profs[i], prof) == 0)
+				goto cont;
+
+		if (*pcnt >= MAXPROFS)		/* oops: too many profs */
+			return (-1);
+
+		/* Add it */
+		profs[(*pcnt)++] = strdup(prof);
 
-			if ((auths = kva_match(pa->attr,
-			    PROFATTR_AUTHS_KW)) != NULL) {
-				if (_is_authorized(authname, auths)) {
-					free_profattr(pa);
-					return (1);
-				}
-			}
-			if ((profiles =
-			    kva_match(pa->attr, PROFATTR_PROFS_KW)) != NULL) {
-				/* Check for authorization in subprofiles */
-				if (_chkprof_for_auth(profiles, authname,
-				    chkedprof, chkedprof_cnt)) {
-					free_profattr(pa);
-					return (1);
-				}
+		if (strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0)
+			break;
+
+		/* find the profiles for this profile */
+		pa = getprofnam(prof);
+
+		if (cb != NULL && (!wantattr || pa != NULL && pa->attr != NULL))
+			res = cb(prof, pa ? pa->attr : NULL, ctxt, pres);
+
+		if (pa != NULL) {
+			if (res == 0 && pa->attr != NULL) {
+				res = _enum_common_p(GETPROF(pa->attr), cb,
+				    ctxt, pres, wantattr, pcnt, profs);
 			}
 			free_profattr(pa);
 		}
+		if (res != 0)
+			return (res);
+cont:
+		continue;
 	}
-	/* authorization not found in any profile */
-	return (0);
+	return (res);
+}
+
+/*
+ * Enumerate all attributes associated with a username and the profiles
+ * associated with the user.
+ */
+static int
+_enum_common(const char *username,
+    int (*cb)(const char *, kva_t *, void *, void *),
+    void *ctxt, void *pres, boolean_t wantattr)
+{
+	userattr_t *ua;
+	int res = 0;
+	int cnt = 0;
+	char *profs[MAXPROFS];
+	kva_t *kattrs;
+
+	if (cb == NULL)
+		return (-1);
+
+	ua = getusernam(username);
+
+	if (ua != NULL) {
+		if (ua->attr != NULL) {
+			if (wantattr)
+				res = cb(NULL, ua->attr, ctxt, pres);
+			if (res == 0) {
+				res = _enum_common_p(GETPROF(ua->attr),
+				    cb, ctxt, pres, wantattr, &cnt, profs);
+			}
+		}
+		free_userattr(ua);
+		if (res != 0)
+			return (res);
+	}
+
+	if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) &&
+	    (kattrs = get_default_attrs(username)) != NULL) {
+
+		res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres,
+		    wantattr, &cnt, profs);
+
+		if (res == 0) {
+			res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres,
+			    wantattr, &cnt, profs);
+		}
+
+		if (res == 0 && wantattr)
+			res = cb(NULL, kattrs, ctxt, pres);
+
+		free_default_attrs(kattrs);
+	}
+
+	free_proflist(profs, cnt);
+
+	return (res);
+}
+
+/*
+ * Enumerate profiles with a username argument.
+ */
+int
+_enum_profs(const char *username,
+    int (*cb)(const char *, kva_t *, void *, void *),
+    void *ctxt, void *pres)
+{
+	return (_enum_common(username, cb, ctxt, pres, B_FALSE));
+}
+
+/*
+ * Enumerate attributes with a username argument.
+ */
+int
+_enum_attrs(const char *username,
+    int (*cb)(const char *, kva_t *, void *, void *),
+    void *ctxt, void *pres)
+{
+	return (_enum_common(username, cb, ctxt, pres, B_TRUE));
+}
+
+
+/*
+ * Enumerate authorizations in the "auths" argument.
+ */
+static int
+_enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *),
+    void *ctxt, void *pres)
+{
+	char *auth, *last, *auths;
+	int res = 0;
+
+	if (cauths == NULL || cb == NULL)
+		return (0);
+
+	COPYTOSTACK(auths, cauths)
+
+	while (auth = strtok_r(auths, KV_SEPSTR, &last)) {
+		auths = NULL;		/* For next iterations of strtok_r */
+
+		res = cb(auth, ctxt, pres);
+
+		if (res != 0)
+			return (res);
+	}
+	return (res);
+}
+
+/*
+ * Magic struct and function to allow using the _enum_attrs functions to
+ * enumerate the authorizations.
+ */
+typedef struct ccomm2auth {
+	int (*cb)(const char *, void *, void *);
+	void *ctxt;
+} ccomm2auth;
+
+/*ARGSUSED*/
+static int
+comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres)
+{
+	ccomm2auth *ca = ctxt;
+	char *auths;
+
+	/* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */
+	auths = kva_match(attr, PROFATTR_AUTHS_KW);
+	return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres));
+}
+
+/*
+ * Enumerate authorizations for username.
+ */
+int
+_enum_auths(const char *username,
+    int (*cb)(const char *, void *, void *),
+    void *ctxt, void *pres)
+{
+	ccomm2auth c2a;
+
+	if (cb == NULL)
+		return (-1);
+
+	c2a.cb = cb;
+	c2a.ctxt = ctxt;
+
+	return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE));
 }
 
 int
 _auth_match(const char *pattern, const char *auth)
 {
 	size_t len;
-	char wildcard = KV_WILDCHAR;
 	char *grant;
 
 	len = strlen(pattern);
@@ -154,7 +297,7 @@
 	 * If the wildcard is not in the last position in the string, don't
 	 * match against it.
 	 */
-	if (pattern[len-1] != wildcard)
+	if (pattern[len-1] != KV_WILDCHAR)
 		return (0);
 
 	/*
@@ -173,66 +316,32 @@
 }
 
 static int
-_is_authorized(const char *authname, char *auths)
+_is_authorized(const char *auth, void *authname, void *res)
 {
-	int	found = 0;	/* have we got a match, yet */
-	char	wildcard = '*';
-	char	*auth;		/* current authorization being compared */
-	char	*buf;
-	char	*lasts;
+	int *resp = res;
 
-	buf = strdup(auths);
-	for (auth = strtok_r(auths, ",", &lasts); auth != NULL && !found;
-	    auth = strtok_r(NULL, ",", &lasts)) {
-		if (strcmp((char *)authname, auth) == 0) {
-			/* Exact match.  We're done. */
-			found = 1;
-		} else if (strchr(auth, wildcard) != NULL) {
-			if (_auth_match(auth, authname)) {
-				found = 1;
-				break;
-			}
-		}
+	if (strcmp(authname, auth) == 0 ||
+	    (strchr(auth, KV_WILDCHAR) != NULL &&
+	    _auth_match(auth, authname))) {
+		*resp = 1;
+		return (1);
 	}
 
-	free(buf);
-
-	return (found);
+	return (0);
 }
 
+int
+chkauthattr(const char *authname, const char *username)
+{
+	int		auth_granted = 0;
 
-/*
- * read /etc/security/policy.conf for AUTHS_GRANTED.
- * return 1 if found matching authname.
- * Otherwise, read PROFS_GRANTED to see if authname exists in any
- * default profiles.
- */
-static int
-_chk_policy_auth(const char *authname, const char *username, char **chkedprof,
-    int *chkedprof_cnt)
-{
-	char	*auths = NULL;
-	char	*profs = NULL;
-	int	ret = 1;
-
-	if (_get_user_defs(username, &auths, &profs) != 0)
+	if (authname == NULL || username == NULL)
 		return (0);
 
-	if (auths != NULL) {
-		if (_is_authorized(authname, auths))
-			goto exit;
-	}
+	(void) _enum_auths(username, _is_authorized, (char *)authname,
+	    &auth_granted);
 
-	if (profs != NULL) {
-		if (_chkprof_for_auth(profs, authname, chkedprof,
-		    chkedprof_cnt))
-			goto exit;
-	}
-	ret = 0;
-
-exit:
-	_free_user_defs(auths, profs);
-	return (ret);
+	return (auth_granted);
 }
 
 #define	CONSOLE_USER_LINK "/dev/vt/console_user"
@@ -257,77 +366,58 @@
 	return (pw.pw_uid == cons.st_uid);
 }
 
-
-int
-_get_user_defs(const char *user, char **def_auth, char **def_prof)
+static void
+free_default_attrs(kva_t *kva)
 {
-	char *cp;
-	char *profs;
-	void	*defp;
+	int i;
+
+	for (i = 0; i < kva->length; i++)
+		free(kva->data[i].value);
+
+	free(kva);
+}
+
+/*
+ * Return the default attributes; this are ignored when a STOP profile
+ * was found.
+ */
+static kva_t *
+get_default_attrs(const char *user)
+{
+	void *defp;
+	kva_t *kva;
+	int i;
 
-	if ((defp = defopen_r(AUTH_POLICY)) == NULL) {
-		if (def_auth != NULL) {
-			*def_auth = NULL;
-		}
-		if (def_prof != NULL) {
-			*def_prof = NULL;
-		}
-		return (-1);
+	kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY);
+
+	if (kva == NULL)
+		return (NULL);
+
+	kva->data = (kv_t *)(void *)&kva[1];
+	kva->length = 0;
+
+	if ((defp = defopen_r(AUTH_POLICY)) == NULL)
+		goto return_null;
+
+	for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) {
+		char *cp = defread_r(dfltply[i].defkw, defp);
+
+		if (cp == NULL)
+			continue;
+		if ((cp = strdup(cp)) == NULL)
+			goto return_null;
+
+		kva->data[kva->length].key = dfltply[i].attr;
+		kva->data[kva->length++].value = cp;
 	}
 
-	if (def_auth != NULL) {
-		if ((cp = defread_r(DEF_AUTH, defp)) != NULL) {
-			if ((*def_auth = strdup(cp)) == NULL) {
-				defclose_r(defp);
-				return (-1);
-			}
-		} else {
-			*def_auth = NULL;
-		}
-	}
-	if (def_prof != NULL) {
-		if (is_cons_user(user) &&
-		    (cp = defread_r(DEF_CONSUSER, defp)) != NULL) {
-			if ((*def_prof = strdup(cp)) == NULL) {
-				defclose_r(defp);
-				return (-1);
-			}
-		}
-		if ((cp = defread_r(DEF_PROF, defp)) != NULL) {
-			int	prof_len;
+	(void) defclose_r(defp);
+	return (kva);
 
-			if (*def_prof == NULL) {
-				if ((*def_prof = strdup(cp)) == NULL) {
-					defclose_r(defp);
-					return (-1);
-				}
-				defclose_r(defp);
-				return (0);
-			}
+return_null:
+	if (defp != NULL)
+		(void) defclose_r(defp);
 
-			/* concatenate def profs with "," separator */
-			prof_len = strlen(*def_prof) + strlen(cp) + 2;
-			if ((profs = malloc(prof_len)) == NULL) {
-				free(*def_prof);
-				*def_prof = NULL;
-				defclose_r(defp);
-				return (-1);
-			}
-			(void) snprintf(profs, prof_len, "%s,%s", *def_prof,
-			    cp);
-			free(*def_prof);
-			*def_prof = profs;
-		}
-	}
-
-	defclose_r(defp);
-	return (0);
+	free_default_attrs(kva);
+	return (NULL);
 }
-
-
-void
-_free_user_defs(char *def_auth, char *def_prof)
-{
-	free(def_auth);
-	free(def_prof);
-}