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