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 * Copyright (c) 2013 RackTop Systems. 24 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <auth_attr.h> 31 #include <prof_attr.h> 32 #include <user_attr.h> 33 #include <project.h> 34 #include <secdb.h> 35 #include <pwd.h> 36 #include <unistd.h> 37 #include <priv.h> 38 #include <errno.h> 39 #include <ctype.h> 40 #include <nss.h> 41 #include <bsm/libbsm.h> 42 #include <tsol/label.h> 43 #include "funcs.h" 44 #include "messages.h" 45 #undef GROUP 46 #include "userdefs.h" 47 48 typedef struct ua_key { 49 const char *key; 50 const char *(*check)(const char *); 51 const char *errstr; 52 char *newvalue; 53 } ua_key_t; 54 55 static const char role[] = "role name"; 56 static const char prof[] = "profile name"; 57 static const char proj[] = "project name"; 58 static const char priv[] = "privilege set"; 59 static const char auth[] = "authorization"; 60 static const char type[] = "user type"; 61 static const char lock[] = "lock_after_retries value"; 62 static const char roleauth[] = "roleauth"; 63 static const char label[] = "label"; 64 static const char auditflags[] = "audit mask"; 65 static char auditerr[256]; 66 67 68 static const char *check_auth(const char *); 69 static const char *check_prof(const char *); 70 static const char *check_role(const char *); 71 static const char *check_proj(const char *); 72 static const char *check_privset(const char *); 73 static const char *check_type(const char *); 74 static const char *check_lock_after_retries(const char *); 75 static const char *check_roleauth(const char *); 76 static const char *check_label(const char *); 77 static const char *check_auditflags(const char *); 78 79 int nkeys; 80 81 static ua_key_t keys[] = { 82 /* First entry is always set correctly in main() */ 83 { USERATTR_TYPE_KW, check_type, type }, 84 { USERATTR_AUTHS_KW, check_auth, auth }, 85 { USERATTR_PROFILES_KW, check_prof, prof }, 86 { USERATTR_ROLES_KW, check_role, role }, 87 { USERATTR_DEFAULTPROJ_KW, check_proj, proj }, 88 { USERATTR_LIMPRIV_KW, check_privset, priv }, 89 { USERATTR_DFLTPRIV_KW, check_privset, priv }, 90 { USERATTR_LOCK_AFTER_RETRIES_KW, check_lock_after_retries, lock }, 91 { USERATTR_ROLEAUTH_KW, check_roleauth, roleauth }, 92 { USERATTR_CLEARANCE, check_label, label }, 93 { USERATTR_MINLABEL, check_label, label }, 94 { USERATTR_AUDIT_FLAGS_KW, check_auditflags, auditflags }, 95 }; 96 97 #define NKEYS (sizeof (keys)/sizeof (ua_key_t)) 98 99 /* 100 * Change a key, there are three different call sequences: 101 * 102 * key, value - key with option letter, value. 103 * NULL, value - -K key=value option. 104 */ 105 106 void 107 change_key(const char *key, char *value) 108 { 109 int i; 110 const char *res; 111 112 if (key == NULL) { 113 key = value; 114 value = strchr(value, '='); 115 /* Bad value */ 116 if (value == NULL) { 117 errmsg(M_INVALID_VALUE); 118 exit(EX_BADARG); 119 } 120 *value++ = '\0'; 121 } 122 123 for (i = 0; i < NKEYS; i++) { 124 if (strcmp(key, keys[i].key) == 0) { 125 if (keys[i].newvalue != NULL) { 126 /* Can't set a value twice */ 127 errmsg(M_REDEFINED_KEY, key); 128 exit(EX_BADARG); 129 } 130 131 if (keys[i].check != NULL && 132 (res = keys[i].check(value)) != NULL) { 133 errmsg(M_INVALID, res, keys[i].errstr); 134 exit(EX_BADARG); 135 } 136 keys[i].newvalue = value; 137 nkeys++; 138 return; 139 } 140 } 141 errmsg(M_INVALID_KEY, key); 142 exit(EX_BADARG); 143 } 144 145 /* 146 * Add the keys to the argument vector. 147 */ 148 void 149 addkey_args(char **argv, int *index) 150 { 151 int i; 152 153 for (i = 0; i < NKEYS; i++) { 154 const char *key = keys[i].key; 155 char *val = keys[i].newvalue; 156 size_t len; 157 char *arg; 158 159 if (val == NULL) 160 continue; 161 162 len = strlen(key) + strlen(val) + 2; 163 arg = malloc(len); 164 165 (void) snprintf(arg, len, "%s=%s", key, val); 166 argv[(*index)++] = "-K"; 167 argv[(*index)++] = arg; 168 } 169 } 170 171 /* 172 * Propose a default value for a key and get the actual value back. 173 * If the proposed default value is NULL, return the actual value set. 174 * The key argument is the user_attr key. 175 */ 176 char * 177 getsetdefval(const char *key, char *dflt) 178 { 179 int i; 180 181 for (i = 0; i < NKEYS; i++) 182 if (strcmp(keys[i].key, key) == 0) { 183 if (keys[i].newvalue != NULL) 184 return (keys[i].newvalue); 185 else 186 return (keys[i].newvalue = dflt); 187 } 188 return (NULL); 189 } 190 191 char * 192 getusertype(char *cmdname) 193 { 194 static char usertype[MAX_TYPE_LENGTH]; 195 char *cmd; 196 197 if ((cmd = strrchr(cmdname, '/'))) 198 ++cmd; 199 else 200 cmd = cmdname; 201 202 /* get user type based on the program name */ 203 if (strncmp(cmd, CMD_PREFIX_USER, 204 strlen(CMD_PREFIX_USER)) == 0) 205 strcpy(usertype, USERATTR_TYPE_NORMAL_KW); 206 else 207 strcpy(usertype, USERATTR_TYPE_NONADMIN_KW); 208 209 return (usertype); 210 } 211 212 int 213 is_role(char *usertype) 214 { 215 if (strcmp(usertype, USERATTR_TYPE_NONADMIN_KW) == 0) 216 return (1); 217 /* not a role */ 218 return (0); 219 } 220 221 /* 222 * Verifies the provided list of authorizations are all valid. 223 * 224 * Returns NULL if all authorization names are valid. 225 * Otherwise, returns the invalid authorization name 226 * 227 */ 228 static const char * 229 check_auth(const char *auths) 230 { 231 char *authname; 232 authattr_t *result; 233 char *tmp; 234 struct passwd *pw; 235 int have_grant = 0; 236 237 tmp = strdup(auths); 238 if (tmp == NULL) { 239 errmsg(M_NOSPACE); 240 exit(EX_FAILURE); 241 } 242 243 authname = strtok(tmp, AUTH_SEP); 244 pw = getpwuid(getuid()); 245 if (pw == NULL) { 246 return (authname); 247 } 248 249 while (authname != NULL) { 250 char *suffix; 251 char *authtoks; 252 253 /* Check if user has been granted this authorization */ 254 if (!chkauthattr(authname, pw->pw_name)) 255 return (authname); 256 257 /* Remove named object after slash */ 258 if ((suffix = index(authname, KV_OBJECTCHAR)) != NULL) 259 *suffix = '\0'; 260 261 /* Find the suffix */ 262 if ((suffix = rindex(authname, '.')) == NULL) 263 return (authname); 264 265 /* Check for existence in auth_attr */ 266 suffix++; 267 if (strcmp(suffix, KV_WILDCARD)) { /* Not a wildcard */ 268 result = getauthnam(authname); 269 if (result == NULL) { 270 /* can't find the auth */ 271 free_authattr(result); 272 return (authname); 273 } 274 free_authattr(result); 275 } 276 277 /* Check if user can delegate this authorization */ 278 if (strcmp(suffix, "grant")) { /* Not a grant option */ 279 authtoks = malloc(strlen(authname) + sizeof ("grant")); 280 strcpy(authtoks, authname); 281 have_grant = 0; 282 while ((suffix = rindex(authtoks, '.')) && 283 !have_grant) { 284 strcpy(suffix, ".grant"); 285 if (chkauthattr(authtoks, pw->pw_name)) 286 have_grant = 1; 287 else 288 *suffix = '\0'; 289 } 290 if (!have_grant) 291 return (authname); 292 } 293 authname = strtok(NULL, AUTH_SEP); 294 } 295 free(tmp); 296 return (NULL); 297 } 298 299 /* 300 * Verifies the provided list of profile names are valid. 301 * 302 * Returns NULL if all profile names are valid. 303 * Otherwise, returns the invalid profile name 304 * 305 */ 306 static const char * 307 check_prof(const char *profs) 308 { 309 char *profname; 310 profattr_t *result; 311 char *tmp; 312 313 tmp = strdup(profs); 314 if (tmp == NULL) { 315 errmsg(M_NOSPACE); 316 exit(EX_FAILURE); 317 } 318 319 profname = strtok(tmp, PROF_SEP); 320 while (profname != NULL) { 321 result = getprofnam(profname); 322 if (result == NULL) { 323 /* can't find the profile */ 324 return (profname); 325 } 326 free_profattr(result); 327 profname = strtok(NULL, PROF_SEP); 328 } 329 free(tmp); 330 return (NULL); 331 } 332 333 334 /* 335 * Verifies the provided list of role names are valid. 336 * 337 * Returns NULL if all role names are valid. 338 * Otherwise, returns the invalid role name 339 * 340 */ 341 static const char * 342 check_role(const char *roles) 343 { 344 char *rolename; 345 userattr_t *result; 346 char *utype; 347 char *tmp; 348 349 tmp = strdup(roles); 350 if (tmp == NULL) { 351 errmsg(M_NOSPACE); 352 exit(EX_FAILURE); 353 } 354 355 rolename = strtok(tmp, ROLE_SEP); 356 while (rolename != NULL) { 357 result = getusernam(rolename); 358 if (result == NULL) { 359 /* can't find the rolename */ 360 return (rolename); 361 } 362 /* Now, make sure it is a role */ 363 utype = kva_match(result->attr, USERATTR_TYPE_KW); 364 if (utype == NULL) { 365 /* no user type defined. not a role */ 366 free_userattr(result); 367 return (rolename); 368 } 369 if (strcmp(utype, USERATTR_TYPE_NONADMIN_KW) != 0) { 370 free_userattr(result); 371 return (rolename); 372 } 373 free_userattr(result); 374 rolename = strtok(NULL, ROLE_SEP); 375 } 376 free(tmp); 377 return (NULL); 378 } 379 380 static const char * 381 check_proj(const char *proj) 382 { 383 if (getprojidbyname(proj) < 0) { 384 return (proj); 385 } else { 386 return (NULL); 387 } 388 } 389 390 static const char * 391 check_privset(const char *pset) 392 { 393 priv_set_t *tmp; 394 const char *res; 395 396 tmp = priv_str_to_set(pset, ",", &res); 397 398 if (tmp != NULL) { 399 res = NULL; 400 priv_freeset(tmp); 401 } else if (res == NULL) 402 res = strerror(errno); 403 404 return (res); 405 } 406 407 static const char * 408 check_type(const char *type) 409 { 410 if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) != 0 && 411 strcmp(type, USERATTR_TYPE_NORMAL_KW) != 0) 412 return (type); 413 414 return (NULL); 415 } 416 417 static const char * 418 check_lock_after_retries(const char *keyval) 419 { 420 if (keyval != NULL) { 421 if (strcasecmp(keyval, USERATTR_LOCK_NO) != 0 && 422 strcasecmp(keyval, USERATTR_LOCK_YES) != 0 && 423 *keyval != '\0') { 424 return (keyval); 425 } 426 } 427 return (NULL); 428 } 429 430 static const char * 431 check_roleauth(const char *keyval) 432 { 433 if (keyval != NULL) { 434 if (strcasecmp(keyval, USERATTR_ROLEAUTH_USER) != 0 && 435 strcasecmp(keyval, USERATTR_ROLEAUTH_ROLE) != 0 && 436 *keyval != '\0') { 437 return (keyval); 438 } 439 } 440 return (NULL); 441 } 442 443 static const char * 444 check_label(const char *labelstr) 445 { 446 int err; 447 m_label_t *lbl = NULL; 448 449 if (!is_system_labeled()) 450 return (NULL); 451 452 err = str_to_label(labelstr, &lbl, MAC_LABEL, L_NO_CORRECTION, NULL); 453 m_label_free(lbl); 454 455 if (err == -1) 456 return (labelstr); 457 458 return (NULL); 459 } 460 461 static const char * 462 check_auditflags(const char *auditflags) 463 { 464 au_mask_t mask; 465 char *flags; 466 char *last = NULL; 467 char *err = "NULL"; 468 469 /* if deleting audit_flags */ 470 if (*auditflags == '\0') { 471 return (NULL); 472 } 473 474 if ((flags = _strdup_null((char *)auditflags)) == NULL) { 475 errmsg(M_NOSPACE); 476 exit(EX_FAILURE); 477 } 478 479 if (!__chkflags(_strtok_escape(flags, KV_AUDIT_DELIMIT, &last), &mask, 480 B_FALSE, &err)) { 481 (void) snprintf(auditerr, sizeof (auditerr), 482 "always mask \"%s\"", err); 483 free(flags); 484 return (auditerr); 485 } 486 if (!__chkflags(_strtok_escape(NULL, KV_AUDIT_DELIMIT, &last), &mask, 487 B_FALSE, &err)) { 488 (void) snprintf(auditerr, sizeof (auditerr), 489 "never mask \"%s\"", err); 490 free(flags); 491 return (auditerr); 492 } 493 if (last != NULL) { 494 (void) snprintf(auditerr, sizeof (auditerr), "\"%s\"", 495 auditflags); 496 free(flags); 497 return (auditerr); 498 } 499 free(flags); 500 501 return (NULL); 502 } 503