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