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