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.
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.
24 * Copyright (c) 2020, Felix Dörre
25 * All rights reserved.
28 #include <sys/dsl_crypt.h>
29 #include <sys/byteorder.h>
34 #include <sys/zio_crypt.h>
35 #include <openssl/evp.h>
38 #define PAM_SM_PASSWORD
39 #define PAM_SM_SESSION
40 #include <security/pam_modules.h>
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>
48 pam_syslog(pam_handle_t
*pamh
, int loglevel
, const char *fmt
, ...)
53 vsyslog(loglevel
, fmt
, args
);
56 #define MAP_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NOCORE
69 static const char PASSWORD_VAR_NAME
[] = "pam_zfs_key_authtok";
70 static const char OLD_PASSWORD_VAR_NAME
[] = "pam_zfs_key_oldauthtok";
72 static libzfs_handle_t
*g_zfs
;
74 static void destroy_pw(pam_handle_t
*pamh
, void *data
, int errcode
);
76 typedef int (*mlock_func_t
) (const void *, size_t);
84 * Try to mlock(2) or munlock(2) addr while handling EAGAIN by retrying ten
85 * times and sleeping 10 milliseconds in between for a total of 0.1
86 * seconds. lock_func must point to either mlock(2) or munlock(2).
89 try_lock(mlock_func_t lock_func
, const void *addr
, size_t len
)
93 useconds_t sleep_dur
= 10 * 1000;
95 if ((err
= (*lock_func
)(addr
, len
)) != EAGAIN
) {
98 for (int i
= retries
; i
> 0; --i
) {
99 (void) usleep(sleep_dur
);
100 if ((err
= (*lock_func
)(addr
, len
)) != EAGAIN
) {
108 static pw_password_t
*
109 alloc_pw_size(size_t len
)
111 pw_password_t
*pw
= malloc(sizeof (pw_password_t
));
117 * We use mmap(2) rather than malloc(3) since later on we mlock(2) the
118 * memory region. Since mlock(2) and munlock(2) operate on whole memory
119 * pages we should allocate a whole page here as mmap(2) does. Further
120 * this ensures that the addresses passed to mlock(2) an munlock(2) are
121 * on a page boundary as suggested by FreeBSD and required by some
122 * other implementations. Finally we avoid inadvertently munlocking
123 * memory mlocked by an concurrently running instance of us.
125 pw
->value
= mmap(NULL
, pw
->len
, PROT_READ
| PROT_WRITE
, MAP_FLAGS
,
128 if (pw
->value
== MAP_FAILED
) {
132 if (try_lock(mlock
, pw
->value
, pw
->len
) != 0) {
133 (void) munmap(pw
->value
, pw
->len
);
140 static pw_password_t
*
141 alloc_pw_string(const char *source
)
143 size_t len
= strlen(source
) + 1;
144 pw_password_t
*pw
= alloc_pw_size(len
);
149 memcpy(pw
->value
, source
, pw
->len
);
154 pw_free(pw_password_t
*pw
)
156 memset(pw
->value
, 0, pw
->len
);
157 if (try_lock(munlock
, pw
->value
, pw
->len
) == 0) {
158 (void) munmap(pw
->value
, pw
->len
);
163 static pw_password_t
*
164 pw_fetch(pam_handle_t
*pamh
, int tok
)
167 if (pam_get_authtok(pamh
, tok
, &token
, NULL
) != PAM_SUCCESS
) {
168 pam_syslog(pamh
, LOG_ERR
,
169 "couldn't get password from PAM stack");
173 pam_syslog(pamh
, LOG_ERR
,
174 "token from PAM stack is null");
177 return (alloc_pw_string(token
));
180 static const pw_password_t
*
181 pw_fetch_lazy(pam_handle_t
*pamh
, int tok
, const char *var_name
)
183 pw_password_t
*pw
= pw_fetch(pamh
, tok
);
187 int ret
= pam_set_data(pamh
, var_name
, pw
, destroy_pw
);
188 if (ret
!= PAM_SUCCESS
) {
190 pam_syslog(pamh
, LOG_ERR
, "pam_set_data failed");
196 static const pw_password_t
*
197 pw_get(pam_handle_t
*pamh
, int tok
, const char *var_name
)
199 const pw_password_t
*authtok
= NULL
;
200 int ret
= pam_get_data(pamh
, var_name
,
201 (const void**)(&authtok
));
202 if (ret
== PAM_SUCCESS
)
204 if (ret
== PAM_NO_MODULE_DATA
)
205 return (pw_fetch_lazy(pamh
, tok
, var_name
));
206 pam_syslog(pamh
, LOG_ERR
, "password not available");
211 pw_clear(pam_handle_t
*pamh
, const char *var_name
)
213 int ret
= pam_set_data(pamh
, var_name
, NULL
, NULL
);
214 if (ret
!= PAM_SUCCESS
) {
215 pam_syslog(pamh
, LOG_ERR
, "clearing password failed");
222 destroy_pw(pam_handle_t
*pamh
, void *data
, int errcode
)
224 (void) pamh
, (void) errcode
;
227 pw_free((pw_password_t
*)data
);
232 pam_zfs_init(pam_handle_t
*pamh
)
235 if ((g_zfs
= libzfs_init()) == NULL
) {
237 pam_syslog(pamh
, LOG_ERR
, "Zfs initialization error: %s",
238 libzfs_error_init(error
));
249 static pw_password_t
*
250 prepare_passphrase(pam_handle_t
*pamh
, zfs_handle_t
*ds
,
251 const char *passphrase
, nvlist_t
*nvlist
)
253 pw_password_t
*key
= alloc_pw_size(WRAPPING_KEY_LEN
);
259 if (nvlist
!= NULL
) {
260 int fd
= open("/dev/urandom", O_RDONLY
);
266 char *buf
= (char *)&salt
;
267 size_t bytes
= sizeof (uint64_t);
268 while (bytes_read
< bytes
) {
269 ssize_t len
= read(fd
, buf
+ bytes_read
, bytes
280 if (nvlist_add_uint64(nvlist
,
281 zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT
), salt
)) {
282 pam_syslog(pamh
, LOG_ERR
,
283 "failed to add salt to nvlist");
287 iters
= DEFAULT_PBKDF2_ITERATIONS
;
288 if (nvlist_add_uint64(nvlist
, zfs_prop_to_name(
289 ZFS_PROP_PBKDF2_ITERS
), iters
)) {
290 pam_syslog(pamh
, LOG_ERR
,
291 "failed to add iters to nvlist");
296 salt
= zfs_prop_get_int(ds
, ZFS_PROP_PBKDF2_SALT
);
297 iters
= zfs_prop_get_int(ds
, ZFS_PROP_PBKDF2_ITERS
);
301 if (!PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase
,
302 strlen(passphrase
), (uint8_t *)&salt
,
303 sizeof (uint64_t), iters
, WRAPPING_KEY_LEN
,
304 (uint8_t *)key
->value
)) {
305 pam_syslog(pamh
, LOG_ERR
, "pbkdf failed");
313 is_key_loaded(pam_handle_t
*pamh
, const char *ds_name
)
315 zfs_handle_t
*ds
= zfs_open(g_zfs
, ds_name
, ZFS_TYPE_FILESYSTEM
);
317 pam_syslog(pamh
, LOG_ERR
, "dataset %s not found", ds_name
);
320 int keystatus
= zfs_prop_get_int(ds
, ZFS_PROP_KEYSTATUS
);
322 return (keystatus
!= ZFS_KEYSTATUS_UNAVAILABLE
);
326 change_key(pam_handle_t
*pamh
, const char *ds_name
,
327 const char *passphrase
)
329 zfs_handle_t
*ds
= zfs_open(g_zfs
, ds_name
, ZFS_TYPE_FILESYSTEM
);
331 pam_syslog(pamh
, LOG_ERR
, "dataset %s not found", ds_name
);
334 nvlist_t
*nvlist
= fnvlist_alloc();
335 pw_password_t
*key
= prepare_passphrase(pamh
, ds
, passphrase
, nvlist
);
341 if (nvlist_add_string(nvlist
,
342 zfs_prop_to_name(ZFS_PROP_KEYLOCATION
),
344 pam_syslog(pamh
, LOG_ERR
, "nvlist_add failed for keylocation");
350 if (nvlist_add_uint64(nvlist
,
351 zfs_prop_to_name(ZFS_PROP_KEYFORMAT
),
352 ZFS_KEYFORMAT_PASSPHRASE
)) {
353 pam_syslog(pamh
, LOG_ERR
, "nvlist_add failed for keyformat");
359 int ret
= lzc_change_key(ds_name
, DCP_CMD_NEW_KEY
, nvlist
,
360 (uint8_t *)key
->value
, WRAPPING_KEY_LEN
);
363 pam_syslog(pamh
, LOG_ERR
, "change_key failed: %d", ret
);
374 decrypt_mount(pam_handle_t
*pamh
, const char *ds_name
,
375 const char *passphrase
, boolean_t noop
)
377 zfs_handle_t
*ds
= zfs_open(g_zfs
, ds_name
, ZFS_TYPE_FILESYSTEM
);
379 pam_syslog(pamh
, LOG_ERR
, "dataset %s not found", ds_name
);
382 pw_password_t
*key
= prepare_passphrase(pamh
, ds
, passphrase
, NULL
);
387 int ret
= lzc_load_key(ds_name
, noop
, (uint8_t *)key
->value
,
390 if (ret
&& ret
!= EEXIST
) {
391 pam_syslog(pamh
, LOG_ERR
, "load_key failed: %d", ret
);
398 ret
= zfs_mount(ds
, NULL
, 0);
400 pam_syslog(pamh
, LOG_ERR
, "mount failed: %d", ret
);
410 unmount_unload(pam_handle_t
*pamh
, const char *ds_name
, boolean_t force
)
412 zfs_handle_t
*ds
= zfs_open(g_zfs
, ds_name
, ZFS_TYPE_FILESYSTEM
);
414 pam_syslog(pamh
, LOG_ERR
, "dataset %s not found", ds_name
);
417 int ret
= zfs_unmount(ds
, NULL
, force
? MS_FORCE
: 0);
419 pam_syslog(pamh
, LOG_ERR
, "zfs_unmount failed with: %d", ret
);
424 ret
= lzc_unload_key(ds_name
);
426 pam_syslog(pamh
, LOG_ERR
, "unload_key failed with: %d", ret
);
442 const char *username
;
443 boolean_t unmount_and_unload
;
444 boolean_t force_unmount
;
445 boolean_t recursive_homes
;
449 zfs_key_config_load(pam_handle_t
*pamh
, zfs_key_config_t
*config
,
450 int argc
, const char **argv
)
452 config
->homes_prefix
= strdup("rpool/home");
453 if (config
->homes_prefix
== NULL
) {
454 pam_syslog(pamh
, LOG_ERR
, "strdup failure");
455 return (PAM_SERVICE_ERR
);
457 config
->runstatedir
= strdup(RUNSTATEDIR
"/pam_zfs_key");
458 if (config
->runstatedir
== NULL
) {
459 pam_syslog(pamh
, LOG_ERR
, "strdup failure");
460 free(config
->homes_prefix
);
461 return (PAM_SERVICE_ERR
);
464 if (pam_get_user(pamh
, &name
, NULL
) != PAM_SUCCESS
) {
465 pam_syslog(pamh
, LOG_ERR
,
466 "couldn't get username from PAM stack");
467 free(config
->runstatedir
);
468 free(config
->homes_prefix
);
469 return (PAM_SERVICE_ERR
);
471 struct passwd
*entry
= getpwnam(name
);
473 free(config
->runstatedir
);
474 free(config
->homes_prefix
);
475 return (PAM_USER_UNKNOWN
);
477 config
->uid_min
= 1000;
478 config
->uid_max
= MAXUID
;
479 config
->uid
= entry
->pw_uid
;
480 config
->username
= name
;
481 config
->unmount_and_unload
= B_TRUE
;
482 config
->force_unmount
= B_FALSE
;
483 config
->recursive_homes
= B_FALSE
;
484 config
->dsname
= NULL
;
485 config
->homedir
= NULL
;
486 for (int c
= 0; c
< argc
; c
++) {
487 if (strncmp(argv
[c
], "homes=", 6) == 0) {
488 free(config
->homes_prefix
);
489 config
->homes_prefix
= strdup(argv
[c
] + 6);
490 } else if (strncmp(argv
[c
], "runstatedir=", 12) == 0) {
491 free(config
->runstatedir
);
492 config
->runstatedir
= strdup(argv
[c
] + 12);
493 } else if (strncmp(argv
[c
], "uid_min=", 8) == 0) {
494 sscanf(argv
[c
] + 8, "%u", &config
->uid_min
);
495 } else if (strncmp(argv
[c
], "uid_max=", 8) == 0) {
496 sscanf(argv
[c
] + 8, "%u", &config
->uid_max
);
497 } else if (strcmp(argv
[c
], "nounmount") == 0) {
498 config
->unmount_and_unload
= B_FALSE
;
499 } else if (strcmp(argv
[c
], "forceunmount") == 0) {
500 config
->force_unmount
= B_TRUE
;
501 } else if (strcmp(argv
[c
], "recursive_homes") == 0) {
502 config
->recursive_homes
= B_TRUE
;
503 } else if (strcmp(argv
[c
], "prop_mountpoint") == 0) {
504 if (config
->homedir
== NULL
)
505 config
->homedir
= strdup(entry
->pw_dir
);
508 return (PAM_SUCCESS
);
512 zfs_key_config_free(zfs_key_config_t
*config
)
514 free(config
->homes_prefix
);
515 free(config
->runstatedir
);
516 free(config
->homedir
);
517 free(config
->dsname
);
521 find_dsname_by_prop_value(zfs_handle_t
*zhp
, void *data
)
523 zfs_type_t type
= zfs_get_type(zhp
);
524 zfs_key_config_t
*target
= data
;
525 char mountpoint
[ZFS_MAXPROPLEN
];
527 /* Skip any datasets whose type does not match */
528 if ((type
& ZFS_TYPE_FILESYSTEM
) == 0) {
533 /* Skip any datasets whose mountpoint does not match */
534 (void) zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
535 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
);
536 if (strcmp(target
->homedir
, mountpoint
) != 0) {
537 if (target
->recursive_homes
) {
538 (void) zfs_iter_filesystems_v2(zhp
, 0,
539 find_dsname_by_prop_value
, target
);
542 return (target
->dsname
!= NULL
);
545 target
->dsname
= strdup(zfs_get_name(zhp
));
551 zfs_key_config_get_dataset(zfs_key_config_t
*config
)
553 if (config
->homedir
!= NULL
&&
554 config
->homes_prefix
!= NULL
) {
555 if (strcmp(config
->homes_prefix
, "*") == 0) {
556 (void) zfs_iter_root(g_zfs
,
557 find_dsname_by_prop_value
, config
);
559 zfs_handle_t
*zhp
= zfs_open(g_zfs
,
560 config
->homes_prefix
, ZFS_TYPE_FILESYSTEM
);
562 pam_syslog(NULL
, LOG_ERR
,
563 "dataset %s not found",
564 config
->homes_prefix
);
568 (void) zfs_iter_filesystems_v2(zhp
, 0,
569 find_dsname_by_prop_value
, config
);
572 char *dsname
= config
->dsname
;
573 config
->dsname
= NULL
;
577 if (config
->homes_prefix
== NULL
) {
581 size_t len
= ZFS_MAX_DATASET_NAME_LEN
;
582 size_t total_len
= strlen(config
->homes_prefix
) + 1
583 + strlen(config
->username
);
584 if (total_len
> len
) {
587 char *ret
= malloc(len
+ 1);
592 (void) snprintf(ret
, len
+ 1, "%s/%s", config
->homes_prefix
,
598 zfs_key_config_modify_session_counter(pam_handle_t
*pamh
,
599 zfs_key_config_t
*config
, int delta
)
601 const char *runtime_path
= config
->runstatedir
;
602 if (mkdir(runtime_path
, S_IRWXU
) != 0 && errno
!= EEXIST
) {
603 pam_syslog(pamh
, LOG_ERR
, "Can't create runtime path: %d",
607 if (chown(runtime_path
, 0, 0) != 0) {
608 pam_syslog(pamh
, LOG_ERR
, "Can't chown runtime path: %d",
612 if (chmod(runtime_path
, S_IRWXU
) != 0) {
613 pam_syslog(pamh
, LOG_ERR
, "Can't chmod runtime path: %d",
619 if (asprintf(&counter_path
, "%s/%u", runtime_path
, config
->uid
) == -1)
622 const int fd
= open(counter_path
,
623 O_RDWR
| O_CLOEXEC
| O_CREAT
| O_NOFOLLOW
,
627 pam_syslog(pamh
, LOG_ERR
, "Can't open counter file: %d", errno
);
630 if (flock(fd
, LOCK_EX
) != 0) {
631 pam_syslog(pamh
, LOG_ERR
, "Can't lock counter file: %d", errno
);
637 int remaining
= sizeof (counter
) - 1;
639 counter
[sizeof (counter
) - 1] = 0;
640 while (remaining
> 0 && (ret
= read(fd
, pos
, remaining
)) > 0) {
645 long int counter_value
= strtol(counter
, NULL
, 10);
646 counter_value
+= delta
;
647 if (counter_value
< 0) {
650 lseek(fd
, 0, SEEK_SET
);
651 if (ftruncate(fd
, 0) != 0) {
652 pam_syslog(pamh
, LOG_ERR
, "Can't truncate counter file: %d",
657 snprintf(counter
, sizeof (counter
), "%ld", counter_value
);
658 remaining
= strlen(counter
);
660 while (remaining
> 0 && (ret
= write(fd
, pos
, remaining
)) > 0) {
665 return (counter_value
);
668 __attribute__((visibility("default")))
670 pam_sm_authenticate(pam_handle_t
*pamh
, int flags
,
671 int argc
, const char **argv
)
675 if (geteuid() != 0) {
676 pam_syslog(pamh
, LOG_ERR
,
677 "Cannot zfs_mount when not being root.");
678 return (PAM_SERVICE_ERR
);
680 zfs_key_config_t config
;
681 int config_err
= zfs_key_config_load(pamh
, &config
, argc
, argv
);
682 if (config_err
!= PAM_SUCCESS
) {
685 if (config
.uid
< config
.uid_min
|| config
.uid
> config
.uid_max
) {
686 zfs_key_config_free(&config
);
687 return (PAM_SERVICE_ERR
);
690 const pw_password_t
*token
= pw_fetch_lazy(pamh
,
691 PAM_AUTHTOK
, PASSWORD_VAR_NAME
);
693 zfs_key_config_free(&config
);
694 return (PAM_AUTH_ERR
);
696 if (pam_zfs_init(pamh
) != 0) {
697 zfs_key_config_free(&config
);
698 return (PAM_SERVICE_ERR
);
700 char *dataset
= zfs_key_config_get_dataset(&config
);
703 zfs_key_config_free(&config
);
704 return (PAM_SERVICE_ERR
);
706 if (decrypt_mount(pamh
, dataset
, token
->value
, B_TRUE
) == -1) {
709 zfs_key_config_free(&config
);
710 return (PAM_AUTH_ERR
);
714 zfs_key_config_free(&config
);
715 return (PAM_SUCCESS
);
718 __attribute__((visibility("default")))
720 pam_sm_setcred(pam_handle_t
*pamh
, int flags
,
721 int argc
, const char **argv
)
723 (void) pamh
, (void) flags
, (void) argc
, (void) argv
;
724 return (PAM_SUCCESS
);
727 __attribute__((visibility("default")))
729 pam_sm_chauthtok(pam_handle_t
*pamh
, int flags
,
730 int argc
, const char **argv
)
732 if (geteuid() != 0) {
733 pam_syslog(pamh
, LOG_ERR
,
734 "Cannot zfs_mount when not being root.");
735 return (PAM_PERM_DENIED
);
737 zfs_key_config_t config
;
738 if (zfs_key_config_load(pamh
, &config
, argc
, argv
) != PAM_SUCCESS
) {
739 return (PAM_SERVICE_ERR
);
741 if (config
.uid
< config
.uid_min
|| config
.uid
> config
.uid_max
) {
742 zfs_key_config_free(&config
);
743 return (PAM_SERVICE_ERR
);
745 const pw_password_t
*old_token
= pw_get(pamh
,
746 PAM_OLDAUTHTOK
, OLD_PASSWORD_VAR_NAME
);
748 if (pam_zfs_init(pamh
) != 0) {
749 zfs_key_config_free(&config
);
750 return (PAM_SERVICE_ERR
);
752 char *dataset
= zfs_key_config_get_dataset(&config
);
755 zfs_key_config_free(&config
);
756 return (PAM_SERVICE_ERR
);
759 pam_syslog(pamh
, LOG_ERR
,
760 "old password from PAM stack is null");
763 zfs_key_config_free(&config
);
764 return (PAM_SERVICE_ERR
);
766 if (decrypt_mount(pamh
, dataset
,
767 old_token
->value
, B_TRUE
) == -1) {
768 pam_syslog(pamh
, LOG_ERR
,
769 "old token mismatch");
772 zfs_key_config_free(&config
);
773 return (PAM_PERM_DENIED
);
777 if ((flags
& PAM_UPDATE_AUTHTOK
) != 0) {
778 const pw_password_t
*token
= pw_get(pamh
, PAM_AUTHTOK
,
781 pam_syslog(pamh
, LOG_ERR
, "new password unavailable");
783 zfs_key_config_free(&config
);
784 pw_clear(pamh
, OLD_PASSWORD_VAR_NAME
);
785 return (PAM_SERVICE_ERR
);
787 char *dataset
= zfs_key_config_get_dataset(&config
);
790 zfs_key_config_free(&config
);
791 pw_clear(pamh
, OLD_PASSWORD_VAR_NAME
);
792 pw_clear(pamh
, PASSWORD_VAR_NAME
);
793 return (PAM_SERVICE_ERR
);
795 int was_loaded
= is_key_loaded(pamh
, dataset
);
796 if (!was_loaded
&& decrypt_mount(pamh
, dataset
,
797 old_token
->value
, B_FALSE
) == -1) {
800 zfs_key_config_free(&config
);
801 pw_clear(pamh
, OLD_PASSWORD_VAR_NAME
);
802 pw_clear(pamh
, PASSWORD_VAR_NAME
);
803 return (PAM_SERVICE_ERR
);
805 int changed
= change_key(pamh
, dataset
, token
->value
);
807 unmount_unload(pamh
, dataset
, config
.force_unmount
);
811 zfs_key_config_free(&config
);
812 if (pw_clear(pamh
, OLD_PASSWORD_VAR_NAME
) == -1 ||
813 pw_clear(pamh
, PASSWORD_VAR_NAME
) == -1 || changed
== -1) {
814 return (PAM_SERVICE_ERR
);
817 zfs_key_config_free(&config
);
819 return (PAM_SUCCESS
);
823 pam_sm_open_session(pam_handle_t
*pamh
, int flags
,
824 int argc
, const char **argv
)
828 if (geteuid() != 0) {
829 pam_syslog(pamh
, LOG_ERR
,
830 "Cannot zfs_mount when not being root.");
831 return (PAM_SUCCESS
);
833 zfs_key_config_t config
;
834 if (zfs_key_config_load(pamh
, &config
, argc
, argv
) != PAM_SUCCESS
) {
835 return (PAM_SESSION_ERR
);
838 if (config
.uid
< config
.uid_min
|| config
.uid
> config
.uid_max
) {
839 zfs_key_config_free(&config
);
840 return (PAM_SUCCESS
);
843 int counter
= zfs_key_config_modify_session_counter(pamh
, &config
, 1);
845 zfs_key_config_free(&config
);
846 return (PAM_SUCCESS
);
849 const pw_password_t
*token
= pw_get(pamh
,
850 PAM_AUTHTOK
, PASSWORD_VAR_NAME
);
852 zfs_key_config_free(&config
);
853 return (PAM_SESSION_ERR
);
855 if (pam_zfs_init(pamh
) != 0) {
856 zfs_key_config_free(&config
);
857 return (PAM_SERVICE_ERR
);
859 char *dataset
= zfs_key_config_get_dataset(&config
);
862 zfs_key_config_free(&config
);
863 return (PAM_SERVICE_ERR
);
865 if (decrypt_mount(pamh
, dataset
, token
->value
, B_FALSE
) == -1) {
868 zfs_key_config_free(&config
);
869 return (PAM_SERVICE_ERR
);
873 zfs_key_config_free(&config
);
874 if (pw_clear(pamh
, PASSWORD_VAR_NAME
) == -1) {
875 return (PAM_SERVICE_ERR
);
877 return (PAM_SUCCESS
);
881 __attribute__((visibility("default")))
883 pam_sm_close_session(pam_handle_t
*pamh
, int flags
,
884 int argc
, const char **argv
)
888 if (geteuid() != 0) {
889 pam_syslog(pamh
, LOG_ERR
,
890 "Cannot zfs_mount when not being root.");
891 return (PAM_SUCCESS
);
893 zfs_key_config_t config
;
894 if (zfs_key_config_load(pamh
, &config
, argc
, argv
) != PAM_SUCCESS
) {
895 return (PAM_SESSION_ERR
);
897 if (config
.uid
< config
.uid_min
|| config
.uid
> config
.uid_max
) {
898 zfs_key_config_free(&config
);
899 return (PAM_SUCCESS
);
902 int counter
= zfs_key_config_modify_session_counter(pamh
, &config
, -1);
904 zfs_key_config_free(&config
);
905 return (PAM_SUCCESS
);
908 if (config
.unmount_and_unload
) {
909 if (pam_zfs_init(pamh
) != 0) {
910 zfs_key_config_free(&config
);
911 return (PAM_SERVICE_ERR
);
913 char *dataset
= zfs_key_config_get_dataset(&config
);
916 zfs_key_config_free(&config
);
917 return (PAM_SESSION_ERR
);
919 if (unmount_unload(pamh
, dataset
, config
.force_unmount
) == -1) {
922 zfs_key_config_free(&config
);
923 return (PAM_SESSION_ERR
);
929 zfs_key_config_free(&config
);
930 return (PAM_SUCCESS
);