Allow disabling of unmapped I/O on FreeBSD
[zfs.git] / contrib / pam_zfs_key / pam_zfs_key.c
blob0856c7534f0d93082f0370e00daae685916e33b2
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.
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>
30 #include <libzfs.h>
32 #include <syslog.h>
34 #include <sys/zio_crypt.h>
35 #include <openssl/evp.h>
37 #define PAM_SM_AUTH
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 #elif defined(__FreeBSD__)
45 #include <security/pam_appl.h>
46 static void
47 pam_syslog(pam_handle_t *pamh, int loglevel, const char *fmt, ...)
49 va_list args;
50 va_start(args, fmt);
51 vsyslog(loglevel, fmt, args);
52 va_end(args);
54 #endif
56 #include <string.h>
58 #include <fcntl.h>
59 #include <sys/stat.h>
60 #include <sys/file.h>
61 #include <sys/wait.h>
62 #include <pwd.h>
64 #include <sys/mman.h>
66 static const char PASSWORD_VAR_NAME[] = "pam_zfs_key_authtok";
68 static libzfs_handle_t *g_zfs;
70 static void destroy_pw(pam_handle_t *pamh, void *data, int errcode);
72 typedef struct {
73 size_t len;
74 char *value;
75 } pw_password_t;
77 static pw_password_t *
78 alloc_pw_size(size_t len)
80 pw_password_t *pw = malloc(sizeof (pw_password_t));
81 if (!pw) {
82 return (NULL);
84 pw->len = len;
86 * The use of malloc() triggers a spurious gcc 11 -Wmaybe-uninitialized
87 * warning in the mlock() function call below, so use calloc().
89 pw->value = calloc(len, 1);
90 if (!pw->value) {
91 free(pw);
92 return (NULL);
94 mlock(pw->value, pw->len);
95 return (pw);
98 static pw_password_t *
99 alloc_pw_string(const char *source)
101 pw_password_t *pw = malloc(sizeof (pw_password_t));
102 if (!pw) {
103 return (NULL);
105 pw->len = strlen(source) + 1;
107 * The use of malloc() triggers a spurious gcc 11 -Wmaybe-uninitialized
108 * warning in the mlock() function call below, so use calloc().
110 pw->value = calloc(pw->len, 1);
111 if (!pw->value) {
112 free(pw);
113 return (NULL);
115 mlock(pw->value, pw->len);
116 memcpy(pw->value, source, pw->len);
117 return (pw);
120 static void
121 pw_free(pw_password_t *pw)
123 bzero(pw->value, pw->len);
124 munlock(pw->value, pw->len);
125 free(pw->value);
126 free(pw);
129 static pw_password_t *
130 pw_fetch(pam_handle_t *pamh)
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);
138 if (!token) {
139 pam_syslog(pamh, LOG_ERR,
140 "token from PAM stack is null");
141 return (NULL);
143 return (alloc_pw_string(token));
146 static const pw_password_t *
147 pw_fetch_lazy(pam_handle_t *pamh)
149 pw_password_t *pw = pw_fetch(pamh);
150 if (pw == NULL) {
151 return (NULL);
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);
159 return (pw);
162 static const pw_password_t *
163 pw_get(pam_handle_t *pamh)
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);
176 static int
177 pw_clear(pam_handle_t *pamh)
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);
184 return (0);
187 static void
188 destroy_pw(pam_handle_t *pamh, void *data, int errcode)
190 if (data != NULL) {
191 pw_free((pw_password_t *)data);
195 static int
196 pam_zfs_init(pam_handle_t *pamh)
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));
204 return (error);
207 static void
208 pam_zfs_free(void)
210 libzfs_fini(g_zfs);
213 static pw_password_t *
214 prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
215 const char *passphrase, nvlist_t *nvlist)
217 pw_password_t *key = alloc_pw_size(WRAPPING_KEY_LEN);
218 if (!key) {
219 return (NULL);
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);
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);
240 bytes_read += len;
242 close(fd);
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);
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);
259 } else {
260 salt = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_SALT);
261 iters = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_ITERS);
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);
273 return (key);
276 static int
277 is_key_loaded(pam_handle_t *pamh, const char *ds_name)
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);
284 int keystatus = zfs_prop_get_int(ds, ZFS_PROP_KEYSTATUS);
285 zfs_close(ds);
286 return (keystatus != ZFS_KEYSTATUS_UNAVAILABLE);
289 static int
290 change_key(pam_handle_t *pamh, const char *ds_name,
291 const char *passphrase)
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);
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);
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);
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);
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);
332 nvlist_free(nvlist);
333 zfs_close(ds);
334 return (0);
337 static int
338 decrypt_mount(pam_handle_t *pamh, const char *ds_name,
339 const char *passphrase)
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);
346 pw_password_t *key = prepare_passphrase(pamh, ds, passphrase, NULL);
347 if (key == NULL) {
348 zfs_close(ds);
349 return (-1);
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);
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);
365 zfs_close(ds);
366 return (0);
369 static int
370 unmount_unload(pam_handle_t *pamh, const char *ds_name)
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);
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);
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);
390 zfs_close(ds);
391 return (0);
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;
404 static int
405 zfs_key_config_load(pam_handle_t *pamh, zfs_key_config_t *config,
406 int argc, const char **argv)
408 config->homes_prefix = strdup("rpool/home");
409 if (config->homes_prefix == NULL) {
410 pam_syslog(pamh, LOG_ERR, "strdup failure");
411 return (-1);
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);
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);
427 struct passwd *entry = getpwnam(name);
428 if (!entry) {
429 free(config->runstatedir);
430 free(config->homes_prefix);
431 return (-1);
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);
451 return (0);
454 static void
455 zfs_key_config_free(zfs_key_config_t *config)
457 free(config->homes_prefix);
458 free(config->runstatedir);
459 free(config->homedir);
460 free(config->dsname);
463 static int
464 find_dsname_by_prop_value(zfs_handle_t *zhp, void *data)
466 zfs_type_t type = zfs_get_type(zhp);
467 zfs_key_config_t *target = data;
468 char mountpoint[ZFS_MAXPROPLEN];
470 /* Skip any datasets whose type does not match */
471 if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
472 zfs_close(zhp);
473 return (0);
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);
484 target->dsname = strdup(zfs_get_name(zhp));
485 zfs_close(zhp);
486 return (1);
489 static char *
490 zfs_key_config_get_dataset(zfs_key_config_t *config)
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);
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);
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);
517 char *ret = malloc(len + 1);
518 if (!ret) {
519 return (NULL);
521 ret[0] = 0;
522 strcat(ret, config->homes_prefix);
523 strcat(ret, "/");
524 strcat(ret, config->username);
525 return (ret);
528 static int
529 zfs_key_config_modify_session_counter(pam_handle_t *pamh,
530 zfs_key_config_t *config, int delta)
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);
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);
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);
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);
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);
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);
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;
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;
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);
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;
600 close(fd);
601 return (counter_value);
604 __attribute__((visibility("default")))
605 PAM_EXTERN int
606 pam_sm_authenticate(pam_handle_t *pamh, int flags,
607 int argc, const char **argv)
609 if (pw_fetch_lazy(pamh) == NULL) {
610 return (PAM_AUTH_ERR);
613 return (PAM_SUCCESS);
616 __attribute__((visibility("default")))
617 PAM_EXTERN int
618 pam_sm_setcred(pam_handle_t *pamh, int flags,
619 int argc, const char **argv)
621 return (PAM_SUCCESS);
624 __attribute__((visibility("default")))
625 PAM_EXTERN int
626 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
627 int argc, const char **argv)
629 if (geteuid() != 0) {
630 pam_syslog(pamh, LOG_ERR,
631 "Cannot zfs_mount when not being root.");
632 return (PAM_PERM_DENIED);
634 zfs_key_config_t config;
635 if (zfs_key_config_load(pamh, &config, argc, argv) == -1) {
636 return (PAM_SERVICE_ERR);
638 if (config.uid < 1000) {
639 zfs_key_config_free(&config);
640 return (PAM_SUCCESS);
643 if (pam_zfs_init(pamh) != 0) {
644 zfs_key_config_free(&config);
645 return (PAM_SERVICE_ERR);
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);
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);
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);
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);
676 if (pam_zfs_init(pamh) != 0) {
677 zfs_key_config_free(&config);
678 return (PAM_SERVICE_ERR);
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);
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);
692 free(dataset);
693 pam_zfs_free();
694 zfs_key_config_free(&config);
695 if (pw_clear(pamh) == -1) {
696 return (PAM_SERVICE_ERR);
698 } else {
699 zfs_key_config_free(&config);
701 return (PAM_SUCCESS);
704 PAM_EXTERN int
705 pam_sm_open_session(pam_handle_t *pamh, int flags,
706 int argc, const char **argv)
708 if (geteuid() != 0) {
709 pam_syslog(pamh, LOG_ERR,
710 "Cannot zfs_mount when not being root.");
711 return (PAM_SUCCESS);
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);
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);
726 const pw_password_t *token = pw_get(pamh);
727 if (token == NULL) {
728 zfs_key_config_free(&config);
729 return (PAM_SESSION_ERR);
731 if (pam_zfs_init(pamh) != 0) {
732 zfs_key_config_free(&config);
733 return (PAM_SERVICE_ERR);
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);
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);
747 free(dataset);
748 pam_zfs_free();
749 zfs_key_config_free(&config);
750 if (pw_clear(pamh) == -1) {
751 return (PAM_SERVICE_ERR);
753 return (PAM_SUCCESS);
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)
762 if (geteuid() != 0) {
763 pam_syslog(pamh, LOG_ERR,
764 "Cannot zfs_mount when not being root.");
765 return (PAM_SUCCESS);
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);
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);
780 if (config.unmount_and_unload) {
781 if (pam_zfs_init(pamh) != 0) {
782 zfs_key_config_free(&config);
783 return (PAM_SERVICE_ERR);
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);
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);
797 free(dataset);
798 pam_zfs_free();
801 zfs_key_config_free(&config);
802 return (PAM_SUCCESS);