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