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 static int _auth_match_noun(const char *, const char *, size_t, const char *); 86 87 int 88 _enum_common_p(const char *cprofiles, 89 int (*cb)(const char *, kva_t *, void *, void *), 90 void *ctxt, void *pres, boolean_t wantattr, 91 int *pcnt, char *profs[MAXPROFS]) 92 { 93 char *prof, *last; 94 char *profiles; 95 profattr_t *pa; 96 int i; 97 int res = 0; 98 99 if (cprofiles == NULL) 100 return (0); 101 102 if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0) 103 return (0); 104 105 COPYTOSTACK(profiles, cprofiles) 106 107 while (prof = strtok_r(profiles, KV_SEPSTR, &last)) { 108 109 profiles = NULL; /* For next iterations of strtok_r */ 110 111 for (i = 0; i < *pcnt; i++) 112 if (strcmp(profs[i], prof) == 0) 113 goto cont; 114 115 if (*pcnt >= MAXPROFS) /* oops: too many profs */ 116 return (-1); 117 118 /* Add it */ 119 profs[(*pcnt)++] = strdup(prof); 120 121 if (strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0) 122 break; 123 124 /* find the profiles for this profile */ 125 pa = getprofnam(prof); 126 127 if (cb != NULL && (!wantattr || pa != NULL && pa->attr != NULL)) 128 res = cb(prof, pa ? pa->attr : NULL, ctxt, pres); 129 130 if (pa != NULL) { 131 if (res == 0 && pa->attr != NULL) { 132 res = _enum_common_p(GETPROF(pa->attr), cb, 133 ctxt, pres, wantattr, pcnt, profs); 134 } 135 free_profattr(pa); 136 } 137 if (res != 0) 138 return (res); 139 cont: 140 continue; 141 } 142 return (res); 143 } 144 145 /* 146 * Enumerate all attributes associated with a username and the profiles 147 * associated with the user. 148 */ 149 static int 150 _enum_common(const char *username, 151 int (*cb)(const char *, kva_t *, void *, void *), 152 void *ctxt, void *pres, boolean_t wantattr) 153 { 154 userattr_t *ua; 155 int res = 0; 156 int cnt = 0; 157 char *profs[MAXPROFS]; 158 kva_t *kattrs; 159 160 if (cb == NULL) 161 return (-1); 162 163 ua = getusernam(username); 164 165 if (ua != NULL) { 166 if (ua->attr != NULL) { 167 if (wantattr) 168 res = cb(NULL, ua->attr, ctxt, pres); 169 if (res == 0) { 170 res = _enum_common_p(GETPROF(ua->attr), 171 cb, ctxt, pres, wantattr, &cnt, profs); 172 } 173 } 174 free_userattr(ua); 175 if (res != 0) { 176 free_proflist(profs, cnt); 177 return (res); 178 } 179 } 180 181 if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) && 182 (kattrs = get_default_attrs(username)) != NULL) { 183 184 res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres, 185 wantattr, &cnt, profs); 186 187 if (res == 0) { 188 res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres, 189 wantattr, &cnt, profs); 190 } 191 192 if (res == 0 && wantattr) 193 res = cb(NULL, kattrs, ctxt, pres); 194 195 free_default_attrs(kattrs); 196 } 197 198 free_proflist(profs, cnt); 199 200 return (res); 201 } 202 203 /* 204 * Enumerate profiles with a username argument. 205 */ 206 int 207 _enum_profs(const char *username, 208 int (*cb)(const char *, kva_t *, void *, void *), 209 void *ctxt, void *pres) 210 { 211 return (_enum_common(username, cb, ctxt, pres, B_FALSE)); 212 } 213 214 /* 215 * Enumerate attributes with a username argument. 216 */ 217 int 218 _enum_attrs(const char *username, 219 int (*cb)(const char *, kva_t *, void *, void *), 220 void *ctxt, void *pres) 221 { 222 return (_enum_common(username, cb, ctxt, pres, B_TRUE)); 223 } 224 225 226 /* 227 * Enumerate authorizations in the "auths" argument. 228 */ 229 static int 230 _enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *), 231 void *ctxt, void *pres) 232 { 233 char *auth, *last, *auths; 234 int res = 0; 235 236 if (cauths == NULL || cb == NULL) 237 return (0); 238 239 COPYTOSTACK(auths, cauths) 240 241 while (auth = strtok_r(auths, KV_SEPSTR, &last)) { 242 auths = NULL; /* For next iterations of strtok_r */ 243 244 res = cb(auth, ctxt, pres); 245 246 if (res != 0) 247 return (res); 248 } 249 return (res); 250 } 251 252 /* 253 * Magic struct and function to allow using the _enum_attrs functions to 254 * enumerate the authorizations. 255 */ 256 typedef struct ccomm2auth { 257 int (*cb)(const char *, void *, void *); 258 void *ctxt; 259 } ccomm2auth; 260 261 /*ARGSUSED*/ 262 static int 263 comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres) 264 { 265 ccomm2auth *ca = ctxt; 266 char *auths; 267 268 /* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */ 269 auths = kva_match(attr, PROFATTR_AUTHS_KW); 270 return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres)); 271 } 272 273 /* 274 * Enumerate authorizations for username. 275 */ 276 int 277 _enum_auths(const char *username, 278 int (*cb)(const char *, void *, void *), 279 void *ctxt, void *pres) 280 { 281 ccomm2auth c2a; 282 283 if (cb == NULL) 284 return (-1); 285 286 c2a.cb = cb; 287 c2a.ctxt = ctxt; 288 289 return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE)); 290 } 291 292 int 293 _auth_match_noun(const char *pattern, const char *auth, 294 size_t auth_len, const char *auth_noun) 295 { 296 size_t pattern_len; 297 char *grant; 298 char *pattern_noun; 299 char *slash; 300 301 pattern_len = strlen(pattern); 302 /* 303 * If the specified authorization has a trailing object 304 * and the current authorization we're checking also has 305 * a trailing object, the object names must match. 306 * 307 * If there is no object name failure, then we must 308 * check for an exact match of the two authorizations 309 */ 310 if (auth_noun != NULL) { 311 if ((slash = strchr(pattern, KV_OBJECTCHAR)) != NULL) { 312 pattern_noun = slash + 1; 313 pattern_len -= strlen(slash); 314 if (strcmp(pattern_noun, auth_noun) != 0) 315 return (0); 316 } else if ((auth_len == pattern_len) && 317 (strncmp(pattern, auth, pattern_len) == 0)) { 318 return (1); 319 } 320 } 321 322 /* 323 * If the wildcard is not in the last position in the string, don't 324 * match against it. 325 */ 326 if (pattern[pattern_len-1] != KV_WILDCHAR) 327 return (0); 328 329 /* 330 * If the strings are identical up to the wildcard and auth does not 331 * end in "grant", then we have a match. 332 */ 333 if (strncmp(pattern, auth, pattern_len - 1) == 0) { 334 grant = strrchr(auth, '.'); 335 if (grant != NULL) { 336 if (strncmp(grant + 1, "grant", 5) != 0) 337 return (1); 338 } 339 } 340 return (0); 341 } 342 343 int 344 _auth_match(const char *pattern, const char *auth) 345 { 346 return (_auth_match_noun(pattern, auth, strlen(auth), NULL)); 347 } 348 349 static int 350 _is_authorized(const char *auth, void *authname, void *res) 351 { 352 int *resp = res; 353 char *authname_noun; 354 char *slash; 355 size_t auth_len; 356 size_t noun_len; 357 358 auth_len = strlen(authname); 359 if ((slash = strchr(authname, KV_OBJECTCHAR)) != NULL) { 360 authname_noun = slash + 1; 361 noun_len = strlen(slash); 362 auth_len -= noun_len; 363 } else { 364 authname_noun = NULL; 365 } 366 367 if (strcmp(authname, auth) == 0) { 368 /* exact match, we're done */ 369 *resp = 1; 370 return (1); 371 } else if (noun_len || strchr(auth, KV_WILDCHAR) != NULL) { 372 if (_auth_match_noun(auth, authname, 373 auth_len, authname_noun)) { 374 *resp = 1; 375 return (1); 376 } 377 } 378 379 return (0); 380 } 381 382 int 383 chkauthattr(const char *authname, const char *username) 384 { 385 int auth_granted = 0; 386 387 if (authname == NULL || username == NULL) 388 return (0); 389 390 (void) _enum_auths(username, _is_authorized, (char *)authname, 391 &auth_granted); 392 393 return (auth_granted); 394 } 395 396 #define CONSOLE_USER_LINK "/dev/vt/console_user" 397 398 static int 399 is_cons_user(const char *user) 400 { 401 struct stat cons; 402 struct passwd pw; 403 char pwbuf[NSS_BUFLEN_PASSWD]; 404 405 if (user == NULL) { 406 return (0); 407 } 408 if (stat(CONSOLE_USER_LINK, &cons) == -1) { 409 return (0); 410 } 411 if (getpwnam_r(user, &pw, pwbuf, sizeof (pwbuf)) == NULL) { 412 return (0); 413 } 414 415 return (pw.pw_uid == cons.st_uid); 416 } 417 418 static void 419 free_default_attrs(kva_t *kva) 420 { 421 int i; 422 423 for (i = 0; i < kva->length; i++) 424 free(kva->data[i].value); 425 426 free(kva); 427 } 428 429 /* 430 * Return the default attributes; this are ignored when a STOP profile 431 * was found. 432 */ 433 static kva_t * 434 get_default_attrs(const char *user) 435 { 436 void *defp; 437 kva_t *kva; 438 int i; 439 440 kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY); 441 442 if (kva == NULL) 443 return (NULL); 444 445 kva->data = (kv_t *)(void *)&kva[1]; 446 kva->length = 0; 447 448 if ((defp = defopen_r(AUTH_POLICY)) == NULL) 449 goto return_null; 450 451 for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) { 452 char *cp = defread_r(dfltply[i].defkw, defp); 453 454 if (cp == NULL) 455 continue; 456 if ((cp = strdup(cp)) == NULL) 457 goto return_null; 458 459 kva->data[kva->length].key = dfltply[i].attr; 460 kva->data[kva->length++].value = cp; 461 } 462 463 (void) defclose_r(defp); 464 return (kva); 465 466 return_null: 467 if (defp != NULL) 468 (void) defclose_r(defp); 469 470 free_default_attrs(kva); 471 return (NULL); 472 } 473