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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <nss_dbdefs.h> 30 #include <pwd.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <syslog.h> 34 #include <unistd.h> 35 #include <auth_attr.h> 36 #include <deflt.h> 37 #include <priv.h> 38 #include <secdb.h> 39 #include <user_attr.h> 40 #include <sys/task.h> 41 #include <libintl.h> 42 #include <project.h> 43 #include <errno.h> 44 45 #include <bsm/adt.h> 46 #include <bsm/adt_event.h> /* adt_get_auid() */ 47 48 #include <security/pam_appl.h> 49 #include <security/pam_modules.h> 50 #include <security/pam_impl.h> 51 52 #define PROJECT "project=" 53 #define PROJSZ (sizeof (PROJECT) - 1) 54 55 /* 56 * unix_cred - PAM auth modules must contain both pam_sm_authenticate 57 * and pam_sm_setcred. Some other auth module is responsible 58 * for authentication (e.g., pam_unix_auth.so), this module 59 * only implements pam_sm_setcred so that the authentication 60 * can be separated without knowledge of the Solaris Unix style 61 * credential setting. 62 * Solaris Unix style credential setting includes initializing 63 * the audit characteristics if not already initialized and 64 * setting the user's default and limit privileges. 65 */ 66 67 /* 68 * unix_cred - pam_sm_authenticate 69 * 70 * Returns PAM_IGNORE. 71 */ 72 73 /*ARGSUSED*/ 74 int 75 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 76 { 77 return (PAM_IGNORE); 78 } 79 80 /* 81 * Obtain a privilege set "keyname" from userattr; if none is present, 82 * fall back to the default, "defname". 83 */ 84 static int 85 getset(char *keyname, char *defname, userattr_t *ua, priv_set_t **res) 86 { 87 char *str; 88 priv_set_t *tmp; 89 90 if ((ua == NULL || ua->attr == NULL || 91 (str = kva_match(ua->attr, keyname)) == NULL) && 92 (str = defread(defname)) == NULL) 93 return (0); 94 95 tmp = priv_str_to_set(str, ",", NULL); 96 97 if (tmp == NULL) { 98 syslog(LOG_AUTH|LOG_ERR, 99 "pam_setcred: bad privilege specification: %s\n", str); 100 priv_freeset(tmp); 101 return (-1); 102 } 103 *res = tmp; 104 return (0); 105 } 106 107 /* 108 * unix_cred - pam_sm_setcred 109 * 110 * Entry flags = PAM_ESTABLISH_CRED, set up Solaris Unix cred. 111 * PAM_DELETE_CRED, NOP, return PAM_SUCCESS. 112 * PAM_REINITIALIZE_CRED, set up Solaris Unix cred, 113 * or merge the current context with the new 114 * user. 115 * PAM_REFRESH_CRED, set up Solaris Unix cred. 116 * PAM_SILENT, print no messages to user. 117 * 118 * Returns PAM_SUCCESS, if all successful. 119 * PAM_CRED_ERR, if unable to set credentials. 120 * PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find 121 * user in databases. 122 * PAM_SYSTEM_ERR, if no valid flag, or unable to get/set 123 * user's audit state. 124 */ 125 126 int 127 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 128 { 129 int i; 130 int debug = 0; 131 uint_t nowarn = flags & PAM_SILENT; 132 int ret = PAM_SUCCESS; 133 char *user; 134 char *ruser; 135 char *rhost; 136 char *tty; 137 au_id_t auid; 138 adt_session_data_t *ah; 139 adt_termid_t *termid = NULL; 140 userattr_t *ua; 141 priv_set_t *lim, *def; 142 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 143 char buf[PROJECT_BUFSZ]; 144 struct project proj, *pproj; 145 int error; 146 char *projname; 147 char *kvs; 148 struct passwd pwd; 149 char pwbuf[NSS_BUFLEN_PASSWD]; 150 151 for (i = 0; i < argc; i++) { 152 if (strcmp(argv[i], "debug") == 0) 153 debug = 1; 154 else if (strcmp(argv[i], "nowarn") == 0) 155 nowarn |= 1; 156 } 157 158 if (debug) 159 syslog(LOG_AUTH | LOG_DEBUG, 160 "pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)", 161 flags, argc); 162 163 (void) pam_get_item(pamh, PAM_USER, (void **)&user); 164 165 if (user == NULL || *user == '\0') { 166 syslog(LOG_AUTH | LOG_ERR, 167 "pam_unix_cred: USER NULL or empty!\n"); 168 return (PAM_USER_UNKNOWN); 169 } 170 (void) pam_get_item(pamh, PAM_RUSER, (void **)&ruser); 171 (void) pam_get_item(pamh, PAM_RHOST, (void **)&rhost); 172 (void) pam_get_item(pamh, PAM_TTY, (void **)&tty); 173 if (debug) 174 syslog(LOG_AUTH | LOG_DEBUG, 175 "pam_unix_cred: user = %s, ruser = %s, rhost = %s, " 176 "tty = %s", user, 177 (ruser == NULL) ? "NULL" : (*ruser == '\0') ? "ZERO" : 178 ruser, 179 (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" : 180 rhost, 181 (tty == NULL) ? "NULL" : (*tty == '\0') ? "ZERO" : 182 tty); 183 184 /* validate flags */ 185 switch (flags & (PAM_ESTABLISH_CRED | PAM_DELETE_CRED | 186 PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED)) { 187 case 0: 188 /* set default flag */ 189 flags |= PAM_ESTABLISH_CRED; 190 break; 191 case PAM_ESTABLISH_CRED: 192 case PAM_REINITIALIZE_CRED: 193 case PAM_REFRESH_CRED: 194 break; 195 case PAM_DELETE_CRED: 196 return (PAM_SUCCESS); 197 default: 198 syslog(LOG_AUTH | LOG_ERR, 199 "pam_unix_cred: invalid flags %x", flags); 200 return (PAM_SYSTEM_ERR); 201 } 202 203 /* 204 * if auditing on and process audit state not set, 205 * setup audit context for process. 206 */ 207 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { 208 syslog(LOG_AUTH | LOG_ERR, 209 "pam_unix_cred: cannot create start audit session %m"); 210 return (PAM_SYSTEM_ERR); 211 } 212 adt_get_auid(ah, &auid); 213 if (debug) { 214 int auditstate; 215 216 if (auditon(A_GETCOND, (caddr_t)&auditstate, 217 sizeof (auditstate)) != 0) { 218 auditstate = AUC_DISABLED; 219 } 220 syslog(LOG_AUTH | LOG_DEBUG, 221 "pam_unix_cred: state = %d, auid = %d", auditstate, 222 auid); 223 } 224 if (getpwnam_r(user, &pwd, pwbuf, sizeof (pwbuf)) == NULL) { 225 syslog(LOG_AUTH | LOG_ERR, 226 "pam_unix_cred: cannot get passwd entry for user = %s", 227 user); 228 ret = PAM_USER_UNKNOWN; 229 goto adt_done; 230 } 231 232 if ((auid == AU_NOAUDITID) && 233 (flags & PAM_ESTABLISH_CRED)) { 234 struct passwd rpwd; 235 char rpwbuf[NSS_BUFLEN_PASSWD]; 236 237 if ((rhost == NULL || *rhost == '\0')) { 238 if (adt_load_ttyname(tty, &termid) != 0) { 239 syslog(LOG_AUTH | LOG_ERR, 240 "pam_unix_cred: cannot load ttyname %m"); 241 ret = PAM_SYSTEM_ERR; 242 goto adt_done; 243 } 244 } else { 245 if (adt_load_hostname(rhost, &termid) != 0) { 246 syslog(LOG_AUTH | LOG_ERR, 247 "pam_unix_cred: cannot load hostname %m"); 248 ret = PAM_SYSTEM_ERR; 249 goto adt_done; 250 } 251 } 252 if ((ruser != NULL) && (*ruser != '\0') && 253 (getpwnam_r(ruser, &rpwd, rpwbuf, 254 sizeof (rpwbuf)) != NULL)) { 255 /* 256 * set up the initial audit for user coming 257 * from another user 258 */ 259 if (adt_set_user(ah, rpwd.pw_uid, rpwd.pw_gid, 260 rpwd.pw_uid, rpwd.pw_gid, termid, ADT_NEW) != 0) { 261 syslog(LOG_AUTH | LOG_ERR, 262 "pam_unix_cred: cannot set ruser audit " 263 "%m"); 264 ret = PAM_SYSTEM_ERR; 265 goto adt_done; 266 } 267 if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, 268 pwd.pw_uid, pwd.pw_gid, NULL, 269 ADT_UPDATE) != 0) { 270 syslog(LOG_AUTH | LOG_ERR, 271 "pam_unix_cred: cannot merge user audit " 272 "%m"); 273 ret = PAM_SYSTEM_ERR; 274 goto adt_done; 275 } 276 if (debug) { 277 syslog(LOG_AUTH | LOG_DEBUG, 278 "pam_unix_cred: new audit set for %d:%d", 279 rpwd.pw_uid, pwd.pw_uid); 280 } 281 } else { 282 /* 283 * No remote user or remote user is not a local 284 * user, no remote attribution, set up the initial 285 * audit as for direct user login 286 */ 287 if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, 288 pwd.pw_uid, pwd.pw_gid, termid, ADT_NEW) != 0) { 289 syslog(LOG_AUTH | LOG_ERR, 290 "pam_unix_cred: cannot set user audit %m"); 291 ret = PAM_SYSTEM_ERR; 292 goto adt_done; 293 } 294 } 295 if (adt_set_proc(ah) != 0) { 296 syslog(LOG_AUTH | LOG_ERR, 297 "pam_unix_cred: cannot set process audit %m"); 298 ret = PAM_CRED_ERR; 299 goto adt_done; 300 } 301 if (debug) { 302 syslog(LOG_AUTH | LOG_DEBUG, 303 "pam_unix_cred: new audit set for %d", 304 pwd.pw_uid); 305 } 306 } else if ((auid != AU_NOAUDITID) && 307 (flags & PAM_REINITIALIZE_CRED)) { 308 if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid, 309 pwd.pw_gid, NULL, ADT_UPDATE) != 0) { 310 syslog(LOG_AUTH | LOG_ERR, 311 "pam_unix_cred: cannot set user audit %m"); 312 ret = PAM_SYSTEM_ERR; 313 goto adt_done; 314 } 315 if (adt_set_proc(ah) != 0) { 316 syslog(LOG_AUTH | LOG_ERR, 317 "pam_unix_cred: cannot set process audit %m"); 318 ret = PAM_CRED_ERR; 319 goto adt_done; 320 } 321 if (debug) { 322 syslog(LOG_AUTH | LOG_DEBUG, 323 "pam_unix_cred: audit merged for %d:%d", 324 auid, pwd.pw_uid); 325 } 326 } else if (debug) { 327 syslog(LOG_AUTH | LOG_DEBUG, 328 "pam_unix_cred: audit already set for %d", auid); 329 } 330 adt_done: 331 if (termid != NULL) 332 free(termid); 333 if (adt_end_session(ah) != 0) { 334 syslog(LOG_AUTH | LOG_ERR, 335 "pam_unix_cred: unable to end audit session"); 336 } 337 338 if (ret != PAM_SUCCESS) 339 return (ret); 340 341 /* Initialize the user's project */ 342 (void) pam_get_item(pamh, PAM_RESOURCE, (void **)&kvs); 343 if (kvs != NULL) { 344 char *tmp, *lasts, *tok; 345 346 kvs = tmp = strdup(kvs); 347 if (kvs == NULL) 348 return (PAM_BUF_ERR); 349 350 while ((tok = strtok_r(tmp, ";", &lasts)) != NULL) { 351 if (strncmp(tok, PROJECT, PROJSZ) == 0) { 352 projname = tok + PROJSZ; 353 break; 354 } 355 tmp = NULL; 356 } 357 } else { 358 projname = NULL; 359 } 360 361 if (projname == NULL || *projname == '\0') { 362 pproj = getdefaultproj(user, &proj, (void *)&buf, 363 PROJECT_BUFSZ); 364 } else { 365 pproj = getprojbyname(projname, &proj, (void *)&buf, 366 PROJECT_BUFSZ); 367 } 368 /* projname points into kvs, so this is the first opportunity to free */ 369 if (kvs != NULL) 370 free(kvs); 371 if (pproj == NULL) { 372 syslog(LOG_AUTH | LOG_ERR, 373 "pam_unix_cred: no default project for user %s", user); 374 if (!nowarn) { 375 (void) snprintf(messages[0], sizeof (messages[0]), 376 dgettext(TEXT_DOMAIN, "No default project!")); 377 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 378 1, messages, NULL); 379 } 380 return (PAM_SYSTEM_ERR); 381 } 382 if ((error = setproject(proj.pj_name, user, TASK_NORMAL)) != 0) { 383 kva_t *kv_array; 384 385 switch (error) { 386 case SETPROJ_ERR_TASK: 387 if (errno == EAGAIN) { 388 syslog(LOG_AUTH | LOG_ERR, 389 "pam_unix_cred: project \"%s\" resource " 390 "control limit has been reached", 391 proj.pj_name); 392 (void) snprintf(messages[0], 393 sizeof (messages[0]), dgettext( 394 TEXT_DOMAIN, 395 "Resource control limit has been " 396 "reached")); 397 } else { 398 syslog(LOG_AUTH | LOG_ERR, 399 "pam_unix_cred: user %s could not join " 400 "project \"%s\": %m", user, proj.pj_name); 401 (void) snprintf(messages[0], 402 sizeof (messages[0]), dgettext( 403 TEXT_DOMAIN, 404 "Could not join default project")); 405 } 406 if (!nowarn) 407 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, 408 messages, NULL); 409 break; 410 case SETPROJ_ERR_POOL: 411 (void) snprintf(messages[0], sizeof (messages[0]), 412 dgettext(TEXT_DOMAIN, 413 "Could not bind to resource pool")); 414 switch (errno) { 415 case EACCES: 416 syslog(LOG_AUTH | LOG_ERR, 417 "pam_unix_cred: project \"%s\" could not " 418 "bind to resource pool: No resource pool " 419 "accepting default bindings exists", 420 proj.pj_name); 421 (void) snprintf(messages[1], 422 sizeof (messages[1]), 423 dgettext(TEXT_DOMAIN, 424 "No resource pool accepting " 425 "default bindings exists")); 426 break; 427 case ESRCH: 428 syslog(LOG_AUTH | LOG_ERR, 429 "pam_unix_cred: project \"%s\" could not " 430 "bind to resource pool: The resource pool " 431 "is unknown", proj.pj_name); 432 (void) snprintf(messages[1], 433 sizeof (messages[1]), 434 dgettext(TEXT_DOMAIN, 435 "The specified resource pool " 436 "is unknown")); 437 break; 438 default: 439 (void) snprintf(messages[1], 440 sizeof (messages[1]), 441 dgettext(TEXT_DOMAIN, 442 "Failure during pool binding")); 443 syslog(LOG_AUTH | LOG_ERR, 444 "pam_unix_cred: project \"%s\" could not " 445 "bind to resource pool: %m", proj.pj_name); 446 } 447 if (!nowarn) 448 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 449 2, messages, NULL); 450 break; 451 default: 452 /* 453 * Resource control assignment failed. Unlike 454 * newtask(1m), we treat this as an error. 455 */ 456 if (error < 0) { 457 /* 458 * This isn't supposed to happen, but in 459 * case it does, this error message 460 * doesn't use error as an index, like 461 * the others might. 462 */ 463 syslog(LOG_AUTH | LOG_ERR, 464 "pam_unix_cred: unkwown error joining " 465 "project \"%s\" (%d)", proj.pj_name, error); 466 (void) snprintf(messages[0], 467 sizeof (messages[0]), 468 dgettext(TEXT_DOMAIN, 469 "unkwown error joining project \"%s\"" 470 " (%d)"), proj.pj_name, error); 471 } else if ((kv_array = _str2kva(proj.pj_attr, KV_ASSIGN, 472 KV_DELIMITER)) != NULL) { 473 syslog(LOG_AUTH | LOG_ERR, 474 "pam_unix_cred: %s resource control " 475 "assignment failed for project \"%s\"", 476 kv_array->data[error - 1].key, 477 proj.pj_name); 478 (void) snprintf(messages[0], 479 sizeof (messages[0]), 480 dgettext(TEXT_DOMAIN, 481 "%s resource control assignment failed for " 482 "project \"%s\""), 483 kv_array->data[error - 1].key, 484 proj.pj_name); 485 _kva_free(kv_array); 486 } else { 487 syslog(LOG_AUTH | LOG_ERR, 488 "pam_unix_cred: resource control " 489 "assignment failed for project \"%s\"" 490 "attribute %d", proj.pj_name, error); 491 (void) snprintf(messages[0], 492 sizeof (messages[0]), 493 dgettext(TEXT_DOMAIN, 494 "resource control assignment failed for " 495 "project \"%s\" attribute %d"), 496 proj.pj_name, error); 497 } 498 if (!nowarn) 499 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 500 1, messages, NULL); 501 } 502 return (PAM_SYSTEM_ERR); 503 } 504 505 ua = getusernam(user); 506 507 (void) defopen(AUTH_POLICY); 508 509 def = lim = NULL; 510 511 if (getset(USERATTR_LIMPRIV_KW, DEF_LIMITPRIV, ua, &lim) != 0 || 512 getset(USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV, ua, &def) != 0) { 513 ret = PAM_SYSTEM_ERR; 514 goto out; 515 } 516 517 if (def == NULL) { 518 def = priv_str_to_set("basic", ",", NULL); 519 if (pathconf("/", _PC_CHOWN_RESTRICTED) == -1) 520 (void) priv_addset(def, PRIV_FILE_CHOWN_SELF); 521 } 522 /* 523 * We set privilege awareness here so that I gets copied to 524 * P & E when the final setuid(uid) happens. 525 */ 526 (void) setpflags(PRIV_AWARE, 1); 527 if (setppriv(PRIV_SET, PRIV_INHERITABLE, def) != 0) { 528 syslog(LOG_AUTH | LOG_ERR, 529 "pam_setcred: setppriv(defaultpriv) failed: %m"); 530 ret = PAM_CRED_ERR; 531 } 532 533 if (lim != NULL) { 534 /* 535 * In order not to suprise certain applications, we 536 * need to retain privilege awareness and thus we must 537 * also set P and E. 538 */ 539 if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0 || 540 setppriv(PRIV_SET, PRIV_PERMITTED, lim) != 0) { 541 syslog(LOG_AUTH | LOG_ERR, 542 "pam_setcred: setppriv(limitpriv) failed: %m"); 543 ret = PAM_CRED_ERR; 544 } 545 } 546 (void) setpflags(PRIV_AWARE, 0); 547 548 out: 549 (void) defopen(NULL); 550 551 if (ua != NULL) 552 free_userattr(ua); 553 if (lim != NULL) 554 priv_freeset(lim); 555 if (def != NULL) 556 priv_freeset(def); 557 558 return (ret); 559 } 560