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