1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions are met: 4 * * Redistributions of source code must retain the above copyright 5 * notice, this list of conditions and the following disclaimer. 6 * * Redistributions in binary form must reproduce the above copyright 7 * notice, this list of conditions and the following disclaimer in the 8 * documentation and/or other materials provided with the distribution. 9 * * Neither the name of the <organization> nor the 10 * names of its contributors may be used to endorse or promote products 11 * derived from this software without specific prior written permission. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * Copyright (c) 2020, Felix Dörre 25 * All rights reserved. 26 */ 27 28 #include <sys/dsl_crypt.h> 29 #include <sys/byteorder.h> 30 #include <libzfs.h> 31 32 #include <syslog.h> 33 34 #include <sys/zio_crypt.h> 35 #include <openssl/evp.h> 36 37 #define PAM_SM_AUTH 38 #define PAM_SM_PASSWORD 39 #define PAM_SM_SESSION 40 #include <security/pam_modules.h> 41 42 #if defined(__linux__) 43 #include <security/pam_ext.h> 44 #define MAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS 45 #elif defined(__FreeBSD__) 46 #include <security/pam_appl.h> 47 static void 48 pam_syslog(pam_handle_t *pamh, int loglevel, const char *fmt, ...) 49 { 50 va_list args; 51 va_start(args, fmt); 52 vsyslog(loglevel, fmt, args); 53 va_end(args); 54 } 55 #define MAP_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NOCORE 56 #endif 57 58 #include <string.h> 59 #include <unistd.h> 60 #include <fcntl.h> 61 #include <sys/stat.h> 62 #include <sys/file.h> 63 #include <sys/wait.h> 64 #include <pwd.h> 65 66 #include <sys/mman.h> 67 68 static const char PASSWORD_VAR_NAME[] = "pam_zfs_key_authtok"; 69 70 static libzfs_handle_t *g_zfs; 71 72 static void destroy_pw(pam_handle_t *pamh, void *data, int errcode); 73 74 typedef int (*mlock_func_t) (const void *, size_t); 75 76 typedef struct { 77 size_t len; 78 char *value; 79 } pw_password_t; 80 81 /* 82 * Try to mlock(2) or munlock(2) addr while handling EAGAIN by retrying ten 83 * times and sleeping 10 milliseconds in between for a total of 0.1 84 * seconds. lock_func must point to either mlock(2) or munlock(2). 85 */ 86 static int 87 try_lock(mlock_func_t lock_func, const void *addr, size_t len) 88 { 89 int err; 90 int retries = 10; 91 useconds_t sleep_dur = 10 * 1000; 92 93 if ((err = (*lock_func)(addr, len)) != EAGAIN) { 94 return (err); 95 } 96 for (int i = retries; i > 0; --i) { 97 (void) usleep(sleep_dur); 98 if ((err = (*lock_func)(addr, len)) != EAGAIN) { 99 break; 100 } 101 } 102 return (err); 103 } 104 105 106 static pw_password_t * 107 alloc_pw_size(size_t len) 108 { 109 pw_password_t *pw = malloc(sizeof (pw_password_t)); 110 if (!pw) { 111 return (NULL); 112 } 113 pw->len = len; 114 /* 115 * We use mmap(2) rather than malloc(3) since later on we mlock(2) the 116 * memory region. Since mlock(2) and munlock(2) operate on whole memory 117 * pages we should allocate a whole page here as mmap(2) does. Further 118 * this ensures that the addresses passed to mlock(2) an munlock(2) are 119 * on a page boundary as suggested by FreeBSD and required by some 120 * other implementations. Finally we avoid inadvertently munlocking 121 * memory mlocked by an concurrently running instance of us. 122 */ 123 pw->value = mmap(NULL, pw->len, PROT_READ | PROT_WRITE, MAP_FLAGS, 124 -1, 0); 125 126 if (pw->value == MAP_FAILED) { 127 free(pw); 128 return (NULL); 129 } 130 if (try_lock(mlock, pw->value, pw->len) != 0) { 131 (void) munmap(pw->value, pw->len); 132 free(pw); 133 return (NULL); 134 } 135 return (pw); 136 } 137 138 static pw_password_t * 139 alloc_pw_string(const char *source) 140 { 141 size_t len = strlen(source) + 1; 142 pw_password_t *pw = alloc_pw_size(len); 143 144 if (!pw) { 145 return (NULL); 146 } 147 memcpy(pw->value, source, pw->len); 148 return (pw); 149 } 150 151 static void 152 pw_free(pw_password_t *pw) 153 { 154 bzero(pw->value, pw->len); 155 if (try_lock(munlock, pw->value, pw->len) == 0) { 156 (void) munmap(pw->value, pw->len); 157 } 158 free(pw); 159 } 160 161 static pw_password_t * 162 pw_fetch(pam_handle_t *pamh) 163 { 164 const char *token; 165 if (pam_get_authtok(pamh, PAM_AUTHTOK, &token, NULL) != PAM_SUCCESS) { 166 pam_syslog(pamh, LOG_ERR, 167 "couldn't get password from PAM stack"); 168 return (NULL); 169 } 170 if (!token) { 171 pam_syslog(pamh, LOG_ERR, 172 "token from PAM stack is null"); 173 return (NULL); 174 } 175 return (alloc_pw_string(token)); 176 } 177 178 static const pw_password_t * 179 pw_fetch_lazy(pam_handle_t *pamh) 180 { 181 pw_password_t *pw = pw_fetch(pamh); 182 if (pw == NULL) { 183 return (NULL); 184 } 185 int ret = pam_set_data(pamh, PASSWORD_VAR_NAME, pw, destroy_pw); 186 if (ret != PAM_SUCCESS) { 187 pw_free(pw); 188 pam_syslog(pamh, LOG_ERR, "pam_set_data failed"); 189 return (NULL); 190 } 191 return (pw); 192 } 193 194 static const pw_password_t * 195 pw_get(pam_handle_t *pamh) 196 { 197 const pw_password_t *authtok = NULL; 198 int ret = pam_get_data(pamh, PASSWORD_VAR_NAME, 199 (const void**)(&authtok)); 200 if (ret == PAM_SUCCESS) 201 return (authtok); 202 if (ret == PAM_NO_MODULE_DATA) 203 return (pw_fetch_lazy(pamh)); 204 pam_syslog(pamh, LOG_ERR, "password not available"); 205 return (NULL); 206 } 207 208 static int 209 pw_clear(pam_handle_t *pamh) 210 { 211 int ret = pam_set_data(pamh, PASSWORD_VAR_NAME, NULL, NULL); 212 if (ret != PAM_SUCCESS) { 213 pam_syslog(pamh, LOG_ERR, "clearing password failed"); 214 return (-1); 215 } 216 return (0); 217 } 218 219 static void 220 destroy_pw(pam_handle_t *pamh, void *data, int errcode) 221 { 222 if (data != NULL) { 223 pw_free((pw_password_t *)data); 224 } 225 } 226 227 static int 228 pam_zfs_init(pam_handle_t *pamh) 229 { 230 int error = 0; 231 if ((g_zfs = libzfs_init()) == NULL) { 232 error = errno; 233 pam_syslog(pamh, LOG_ERR, "Zfs initialization error: %s", 234 libzfs_error_init(error)); 235 } 236 return (error); 237 } 238 239 static void 240 pam_zfs_free(void) 241 { 242 libzfs_fini(g_zfs); 243 } 244 245 static pw_password_t * 246 prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds, 247 const char *passphrase, nvlist_t *nvlist) 248 { 249 pw_password_t *key = alloc_pw_size(WRAPPING_KEY_LEN); 250 if (!key) { 251 return (NULL); 252 } 253 uint64_t salt; 254 uint64_t iters; 255 if (nvlist != NULL) { 256 int fd = open("/dev/urandom", O_RDONLY); 257 if (fd < 0) { 258 pw_free(key); 259 return (NULL); 260 } 261 int bytes_read = 0; 262 char *buf = (char *)&salt; 263 size_t bytes = sizeof (uint64_t); 264 while (bytes_read < bytes) { 265 ssize_t len = read(fd, buf + bytes_read, bytes 266 - bytes_read); 267 if (len < 0) { 268 close(fd); 269 pw_free(key); 270 return (NULL); 271 } 272 bytes_read += len; 273 } 274 close(fd); 275 276 if (nvlist_add_uint64(nvlist, 277 zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt)) { 278 pam_syslog(pamh, LOG_ERR, 279 "failed to add salt to nvlist"); 280 pw_free(key); 281 return (NULL); 282 } 283 iters = DEFAULT_PBKDF2_ITERATIONS; 284 if (nvlist_add_uint64(nvlist, zfs_prop_to_name( 285 ZFS_PROP_PBKDF2_ITERS), iters)) { 286 pam_syslog(pamh, LOG_ERR, 287 "failed to add iters to nvlist"); 288 pw_free(key); 289 return (NULL); 290 } 291 } else { 292 salt = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_SALT); 293 iters = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_ITERS); 294 } 295 296 salt = LE_64(salt); 297 if (!PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase, 298 strlen(passphrase), (uint8_t *)&salt, 299 sizeof (uint64_t), iters, WRAPPING_KEY_LEN, 300 (uint8_t *)key->value)) { 301 pam_syslog(pamh, LOG_ERR, "pbkdf failed"); 302 pw_free(key); 303 return (NULL); 304 } 305 return (key); 306 } 307 308 static int 309 is_key_loaded(pam_handle_t *pamh, const char *ds_name) 310 { 311 zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM); 312 if (ds == NULL) { 313 pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name); 314 return (-1); 315 } 316 int keystatus = zfs_prop_get_int(ds, ZFS_PROP_KEYSTATUS); 317 zfs_close(ds); 318 return (keystatus != ZFS_KEYSTATUS_UNAVAILABLE); 319 } 320 321 static int 322 change_key(pam_handle_t *pamh, const char *ds_name, 323 const char *passphrase) 324 { 325 zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM); 326 if (ds == NULL) { 327 pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name); 328 return (-1); 329 } 330 nvlist_t *nvlist = fnvlist_alloc(); 331 pw_password_t *key = prepare_passphrase(pamh, ds, passphrase, nvlist); 332 if (key == NULL) { 333 nvlist_free(nvlist); 334 zfs_close(ds); 335 return (-1); 336 } 337 if (nvlist_add_string(nvlist, 338 zfs_prop_to_name(ZFS_PROP_KEYLOCATION), 339 "prompt")) { 340 pam_syslog(pamh, LOG_ERR, "nvlist_add failed for keylocation"); 341 pw_free(key); 342 nvlist_free(nvlist); 343 zfs_close(ds); 344 return (-1); 345 } 346 if (nvlist_add_uint64(nvlist, 347 zfs_prop_to_name(ZFS_PROP_KEYFORMAT), 348 ZFS_KEYFORMAT_PASSPHRASE)) { 349 pam_syslog(pamh, LOG_ERR, "nvlist_add failed for keyformat"); 350 pw_free(key); 351 nvlist_free(nvlist); 352 zfs_close(ds); 353 return (-1); 354 } 355 int ret = lzc_change_key(ds_name, DCP_CMD_NEW_KEY, nvlist, 356 (uint8_t *)key->value, WRAPPING_KEY_LEN); 357 pw_free(key); 358 if (ret) { 359 pam_syslog(pamh, LOG_ERR, "change_key failed: %d", ret); 360 nvlist_free(nvlist); 361 zfs_close(ds); 362 return (-1); 363 } 364 nvlist_free(nvlist); 365 zfs_close(ds); 366 return (0); 367 } 368 369 static int 370 decrypt_mount(pam_handle_t *pamh, const char *ds_name, 371 const char *passphrase) 372 { 373 zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM); 374 if (ds == NULL) { 375 pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name); 376 return (-1); 377 } 378 pw_password_t *key = prepare_passphrase(pamh, ds, passphrase, NULL); 379 if (key == NULL) { 380 zfs_close(ds); 381 return (-1); 382 } 383 int ret = lzc_load_key(ds_name, B_FALSE, (uint8_t *)key->value, 384 WRAPPING_KEY_LEN); 385 pw_free(key); 386 if (ret) { 387 pam_syslog(pamh, LOG_ERR, "load_key failed: %d", ret); 388 zfs_close(ds); 389 return (-1); 390 } 391 ret = zfs_mount(ds, NULL, 0); 392 if (ret) { 393 pam_syslog(pamh, LOG_ERR, "mount failed: %d", ret); 394 zfs_close(ds); 395 return (-1); 396 } 397 zfs_close(ds); 398 return (0); 399 } 400 401 static int 402 unmount_unload(pam_handle_t *pamh, const char *ds_name) 403 { 404 zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM); 405 if (ds == NULL) { 406 pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name); 407 return (-1); 408 } 409 int ret = zfs_unmount(ds, NULL, 0); 410 if (ret) { 411 pam_syslog(pamh, LOG_ERR, "zfs_unmount failed with: %d", ret); 412 zfs_close(ds); 413 return (-1); 414 } 415 416 ret = lzc_unload_key(ds_name); 417 if (ret) { 418 pam_syslog(pamh, LOG_ERR, "unload_key failed with: %d", ret); 419 zfs_close(ds); 420 return (-1); 421 } 422 zfs_close(ds); 423 return (0); 424 } 425 426 typedef struct { 427 char *homes_prefix; 428 char *runstatedir; 429 char *homedir; 430 char *dsname; 431 uid_t uid; 432 const char *username; 433 int unmount_and_unload; 434 } zfs_key_config_t; 435 436 static int 437 zfs_key_config_load(pam_handle_t *pamh, zfs_key_config_t *config, 438 int argc, const char **argv) 439 { 440 config->homes_prefix = strdup("rpool/home"); 441 if (config->homes_prefix == NULL) { 442 pam_syslog(pamh, LOG_ERR, "strdup failure"); 443 return (-1); 444 } 445 config->runstatedir = strdup(RUNSTATEDIR "/pam_zfs_key"); 446 if (config->runstatedir == NULL) { 447 pam_syslog(pamh, LOG_ERR, "strdup failure"); 448 free(config->homes_prefix); 449 return (-1); 450 } 451 const char *name; 452 if (pam_get_user(pamh, &name, NULL) != PAM_SUCCESS) { 453 pam_syslog(pamh, LOG_ERR, 454 "couldn't get username from PAM stack"); 455 free(config->runstatedir); 456 free(config->homes_prefix); 457 return (-1); 458 } 459 struct passwd *entry = getpwnam(name); 460 if (!entry) { 461 free(config->runstatedir); 462 free(config->homes_prefix); 463 return (-1); 464 } 465 config->uid = entry->pw_uid; 466 config->username = name; 467 config->unmount_and_unload = 1; 468 config->dsname = NULL; 469 config->homedir = NULL; 470 for (int c = 0; c < argc; c++) { 471 if (strncmp(argv[c], "homes=", 6) == 0) { 472 free(config->homes_prefix); 473 config->homes_prefix = strdup(argv[c] + 6); 474 } else if (strncmp(argv[c], "runstatedir=", 12) == 0) { 475 free(config->runstatedir); 476 config->runstatedir = strdup(argv[c] + 12); 477 } else if (strcmp(argv[c], "nounmount") == 0) { 478 config->unmount_and_unload = 0; 479 } else if (strcmp(argv[c], "prop_mountpoint") == 0) { 480 config->homedir = strdup(entry->pw_dir); 481 } 482 } 483 return (0); 484 } 485 486 static void 487 zfs_key_config_free(zfs_key_config_t *config) 488 { 489 free(config->homes_prefix); 490 free(config->runstatedir); 491 free(config->homedir); 492 free(config->dsname); 493 } 494 495 static int 496 find_dsname_by_prop_value(zfs_handle_t *zhp, void *data) 497 { 498 zfs_type_t type = zfs_get_type(zhp); 499 zfs_key_config_t *target = data; 500 char mountpoint[ZFS_MAXPROPLEN]; 501 502 /* Skip any datasets whose type does not match */ 503 if ((type & ZFS_TYPE_FILESYSTEM) == 0) { 504 zfs_close(zhp); 505 return (0); 506 } 507 508 /* Skip any datasets whose mountpoint does not match */ 509 (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 510 sizeof (mountpoint), NULL, NULL, 0, B_FALSE); 511 if (strcmp(target->homedir, mountpoint) != 0) { 512 zfs_close(zhp); 513 return (0); 514 } 515 516 target->dsname = strdup(zfs_get_name(zhp)); 517 zfs_close(zhp); 518 return (1); 519 } 520 521 static char * 522 zfs_key_config_get_dataset(zfs_key_config_t *config) 523 { 524 if (config->homedir != NULL && 525 config->homes_prefix != NULL) { 526 zfs_handle_t *zhp = zfs_open(g_zfs, config->homes_prefix, 527 ZFS_TYPE_FILESYSTEM); 528 if (zhp == NULL) { 529 pam_syslog(NULL, LOG_ERR, "dataset %s not found", 530 config->homes_prefix); 531 zfs_close(zhp); 532 return (NULL); 533 } 534 535 (void) zfs_iter_filesystems(zhp, find_dsname_by_prop_value, 536 config); 537 zfs_close(zhp); 538 char *dsname = config->dsname; 539 config->dsname = NULL; 540 return (dsname); 541 } 542 543 size_t len = ZFS_MAX_DATASET_NAME_LEN; 544 size_t total_len = strlen(config->homes_prefix) + 1 545 + strlen(config->username); 546 if (total_len > len) { 547 return (NULL); 548 } 549 char *ret = malloc(len + 1); 550 if (!ret) { 551 return (NULL); 552 } 553 ret[0] = 0; 554 strcat(ret, config->homes_prefix); 555 strcat(ret, "/"); 556 strcat(ret, config->username); 557 return (ret); 558 } 559 560 static int 561 zfs_key_config_modify_session_counter(pam_handle_t *pamh, 562 zfs_key_config_t *config, int delta) 563 { 564 const char *runtime_path = config->runstatedir; 565 if (mkdir(runtime_path, S_IRWXU) != 0 && errno != EEXIST) { 566 pam_syslog(pamh, LOG_ERR, "Can't create runtime path: %d", 567 errno); 568 return (-1); 569 } 570 if (chown(runtime_path, 0, 0) != 0) { 571 pam_syslog(pamh, LOG_ERR, "Can't chown runtime path: %d", 572 errno); 573 return (-1); 574 } 575 if (chmod(runtime_path, S_IRWXU) != 0) { 576 pam_syslog(pamh, LOG_ERR, "Can't chmod runtime path: %d", 577 errno); 578 return (-1); 579 } 580 size_t runtime_path_len = strlen(runtime_path); 581 size_t counter_path_len = runtime_path_len + 1 + 10; 582 char *counter_path = malloc(counter_path_len + 1); 583 if (!counter_path) { 584 return (-1); 585 } 586 counter_path[0] = 0; 587 strcat(counter_path, runtime_path); 588 snprintf(counter_path + runtime_path_len, counter_path_len, "/%d", 589 config->uid); 590 const int fd = open(counter_path, 591 O_RDWR | O_CLOEXEC | O_CREAT | O_NOFOLLOW, 592 S_IRUSR | S_IWUSR); 593 free(counter_path); 594 if (fd < 0) { 595 pam_syslog(pamh, LOG_ERR, "Can't open counter file: %d", errno); 596 return (-1); 597 } 598 if (flock(fd, LOCK_EX) != 0) { 599 pam_syslog(pamh, LOG_ERR, "Can't lock counter file: %d", errno); 600 close(fd); 601 return (-1); 602 } 603 char counter[20]; 604 char *pos = counter; 605 int remaining = sizeof (counter) - 1; 606 int ret; 607 counter[sizeof (counter) - 1] = 0; 608 while (remaining > 0 && (ret = read(fd, pos, remaining)) > 0) { 609 remaining -= ret; 610 pos += ret; 611 } 612 *pos = 0; 613 long int counter_value = strtol(counter, NULL, 10); 614 counter_value += delta; 615 if (counter_value < 0) { 616 counter_value = 0; 617 } 618 lseek(fd, 0, SEEK_SET); 619 if (ftruncate(fd, 0) != 0) { 620 pam_syslog(pamh, LOG_ERR, "Can't truncate counter file: %d", 621 errno); 622 close(fd); 623 return (-1); 624 } 625 snprintf(counter, sizeof (counter), "%ld", counter_value); 626 remaining = strlen(counter); 627 pos = counter; 628 while (remaining > 0 && (ret = write(fd, pos, remaining)) > 0) { 629 remaining -= ret; 630 pos += ret; 631 } 632 close(fd); 633 return (counter_value); 634 } 635 636 __attribute__((visibility("default"))) 637 PAM_EXTERN int 638 pam_sm_authenticate(pam_handle_t *pamh, int flags, 639 int argc, const char **argv) 640 { 641 if (pw_fetch_lazy(pamh) == NULL) { 642 return (PAM_AUTH_ERR); 643 } 644 645 return (PAM_SUCCESS); 646 } 647 648 __attribute__((visibility("default"))) 649 PAM_EXTERN int 650 pam_sm_setcred(pam_handle_t *pamh, int flags, 651 int argc, const char **argv) 652 { 653 return (PAM_SUCCESS); 654 } 655 656 __attribute__((visibility("default"))) 657 PAM_EXTERN int 658 pam_sm_chauthtok(pam_handle_t *pamh, int flags, 659 int argc, const char **argv) 660 { 661 if (geteuid() != 0) { 662 pam_syslog(pamh, LOG_ERR, 663 "Cannot zfs_mount when not being root."); 664 return (PAM_PERM_DENIED); 665 } 666 zfs_key_config_t config; 667 if (zfs_key_config_load(pamh, &config, argc, argv) == -1) { 668 return (PAM_SERVICE_ERR); 669 } 670 if (config.uid < 1000) { 671 zfs_key_config_free(&config); 672 return (PAM_SUCCESS); 673 } 674 { 675 if (pam_zfs_init(pamh) != 0) { 676 zfs_key_config_free(&config); 677 return (PAM_SERVICE_ERR); 678 } 679 char *dataset = zfs_key_config_get_dataset(&config); 680 if (!dataset) { 681 pam_zfs_free(); 682 zfs_key_config_free(&config); 683 return (PAM_SERVICE_ERR); 684 } 685 int key_loaded = is_key_loaded(pamh, dataset); 686 if (key_loaded == -1) { 687 free(dataset); 688 pam_zfs_free(); 689 zfs_key_config_free(&config); 690 return (PAM_SERVICE_ERR); 691 } 692 free(dataset); 693 pam_zfs_free(); 694 if (! key_loaded) { 695 pam_syslog(pamh, LOG_ERR, 696 "key not loaded, returning try_again"); 697 zfs_key_config_free(&config); 698 return (PAM_PERM_DENIED); 699 } 700 } 701 702 if ((flags & PAM_UPDATE_AUTHTOK) != 0) { 703 const pw_password_t *token = pw_get(pamh); 704 if (token == NULL) { 705 zfs_key_config_free(&config); 706 return (PAM_SERVICE_ERR); 707 } 708 if (pam_zfs_init(pamh) != 0) { 709 zfs_key_config_free(&config); 710 return (PAM_SERVICE_ERR); 711 } 712 char *dataset = zfs_key_config_get_dataset(&config); 713 if (!dataset) { 714 pam_zfs_free(); 715 zfs_key_config_free(&config); 716 return (PAM_SERVICE_ERR); 717 } 718 if (change_key(pamh, dataset, token->value) == -1) { 719 free(dataset); 720 pam_zfs_free(); 721 zfs_key_config_free(&config); 722 return (PAM_SERVICE_ERR); 723 } 724 free(dataset); 725 pam_zfs_free(); 726 zfs_key_config_free(&config); 727 if (pw_clear(pamh) == -1) { 728 return (PAM_SERVICE_ERR); 729 } 730 } else { 731 zfs_key_config_free(&config); 732 } 733 return (PAM_SUCCESS); 734 } 735 736 PAM_EXTERN int 737 pam_sm_open_session(pam_handle_t *pamh, int flags, 738 int argc, const char **argv) 739 { 740 if (geteuid() != 0) { 741 pam_syslog(pamh, LOG_ERR, 742 "Cannot zfs_mount when not being root."); 743 return (PAM_SUCCESS); 744 } 745 zfs_key_config_t config; 746 zfs_key_config_load(pamh, &config, argc, argv); 747 if (config.uid < 1000) { 748 zfs_key_config_free(&config); 749 return (PAM_SUCCESS); 750 } 751 752 int counter = zfs_key_config_modify_session_counter(pamh, &config, 1); 753 if (counter != 1) { 754 zfs_key_config_free(&config); 755 return (PAM_SUCCESS); 756 } 757 758 const pw_password_t *token = pw_get(pamh); 759 if (token == NULL) { 760 zfs_key_config_free(&config); 761 return (PAM_SESSION_ERR); 762 } 763 if (pam_zfs_init(pamh) != 0) { 764 zfs_key_config_free(&config); 765 return (PAM_SERVICE_ERR); 766 } 767 char *dataset = zfs_key_config_get_dataset(&config); 768 if (!dataset) { 769 pam_zfs_free(); 770 zfs_key_config_free(&config); 771 return (PAM_SERVICE_ERR); 772 } 773 if (decrypt_mount(pamh, dataset, token->value) == -1) { 774 free(dataset); 775 pam_zfs_free(); 776 zfs_key_config_free(&config); 777 return (PAM_SERVICE_ERR); 778 } 779 free(dataset); 780 pam_zfs_free(); 781 zfs_key_config_free(&config); 782 if (pw_clear(pamh) == -1) { 783 return (PAM_SERVICE_ERR); 784 } 785 return (PAM_SUCCESS); 786 787 } 788 789 __attribute__((visibility("default"))) 790 PAM_EXTERN int 791 pam_sm_close_session(pam_handle_t *pamh, int flags, 792 int argc, const char **argv) 793 { 794 if (geteuid() != 0) { 795 pam_syslog(pamh, LOG_ERR, 796 "Cannot zfs_mount when not being root."); 797 return (PAM_SUCCESS); 798 } 799 zfs_key_config_t config; 800 zfs_key_config_load(pamh, &config, argc, argv); 801 if (config.uid < 1000) { 802 zfs_key_config_free(&config); 803 return (PAM_SUCCESS); 804 } 805 806 int counter = zfs_key_config_modify_session_counter(pamh, &config, -1); 807 if (counter != 0) { 808 zfs_key_config_free(&config); 809 return (PAM_SUCCESS); 810 } 811 812 if (config.unmount_and_unload) { 813 if (pam_zfs_init(pamh) != 0) { 814 zfs_key_config_free(&config); 815 return (PAM_SERVICE_ERR); 816 } 817 char *dataset = zfs_key_config_get_dataset(&config); 818 if (!dataset) { 819 pam_zfs_free(); 820 zfs_key_config_free(&config); 821 return (PAM_SESSION_ERR); 822 } 823 if (unmount_unload(pamh, dataset) == -1) { 824 free(dataset); 825 pam_zfs_free(); 826 zfs_key_config_free(&config); 827 return (PAM_SESSION_ERR); 828 } 829 free(dataset); 830 pam_zfs_free(); 831 } 832 833 zfs_key_config_free(&config); 834 return (PAM_SUCCESS); 835 } 836