16e69612dSEmmanuel Vadot /*-
26e69612dSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause
36e69612dSEmmanuel Vadot *
46e69612dSEmmanuel Vadot * Copyright (c) 2024 Beckhoff Automation GmbH & Co. KG
56e69612dSEmmanuel Vadot *
66e69612dSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
76e69612dSEmmanuel Vadot * modification, are permitted provided that the following conditions
86e69612dSEmmanuel Vadot * are met:
96e69612dSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
106e69612dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
116e69612dSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
126e69612dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
136e69612dSEmmanuel Vadot * documentation and/or other materials provided with the distribution.
146e69612dSEmmanuel Vadot *
156e69612dSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166e69612dSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176e69612dSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186e69612dSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196e69612dSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206e69612dSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216e69612dSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226e69612dSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236e69612dSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246e69612dSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256e69612dSEmmanuel Vadot * SUCH DAMAGE.
266e69612dSEmmanuel Vadot */
276e69612dSEmmanuel Vadot
286e69612dSEmmanuel Vadot #include <sys/stat.h>
296e69612dSEmmanuel Vadot #include <dirent.h>
306e69612dSEmmanuel Vadot #include <errno.h>
316e69612dSEmmanuel Vadot #include <fcntl.h>
326e69612dSEmmanuel Vadot #include <stdio.h>
336e69612dSEmmanuel Vadot #include <stdlib.h>
346e69612dSEmmanuel Vadot #include <string.h>
356e69612dSEmmanuel Vadot #include <unistd.h>
366e69612dSEmmanuel Vadot #include <pwd.h>
376e69612dSEmmanuel Vadot
386e69612dSEmmanuel Vadot #define PAM_SM_SESSION
396e69612dSEmmanuel Vadot
406e69612dSEmmanuel Vadot #include <security/pam_appl.h>
416e69612dSEmmanuel Vadot #include <security/pam_modules.h>
426e69612dSEmmanuel Vadot #include <security/pam_mod_misc.h>
436e69612dSEmmanuel Vadot
446e69612dSEmmanuel Vadot #define BASE_RUNTIME_DIR_PREFIX "/var/run/xdg"
456e69612dSEmmanuel Vadot #define RUNTIME_DIR_PREFIX runtime_dir_prefix != NULL ? runtime_dir_prefix : BASE_RUNTIME_DIR_PREFIX
466e69612dSEmmanuel Vadot
476e69612dSEmmanuel Vadot #define RUNTIME_DIR_PREFIX_MODE 0711
486e69612dSEmmanuel Vadot #define RUNTIME_DIR_MODE 0700 /* XDG spec */
496e69612dSEmmanuel Vadot
506e69612dSEmmanuel Vadot #define XDG_MAX_SESSION 100 /* Arbitrary limit because we need one */
516e69612dSEmmanuel Vadot
526e69612dSEmmanuel Vadot static int
_pam_xdg_open(pam_handle_t * pamh,int flags __unused,int argc __unused,const char * argv[]__unused)536e69612dSEmmanuel Vadot _pam_xdg_open(pam_handle_t *pamh, int flags __unused,
546e69612dSEmmanuel Vadot int argc __unused, const char *argv[] __unused)
556e69612dSEmmanuel Vadot {
566e69612dSEmmanuel Vadot struct passwd *passwd;
576e69612dSEmmanuel Vadot const char *user;
586e69612dSEmmanuel Vadot const char *runtime_dir_prefix;
596e69612dSEmmanuel Vadot struct stat sb;
606e69612dSEmmanuel Vadot char *runtime_dir = NULL;
616e69612dSEmmanuel Vadot char *xdg_session_file;
626e69612dSEmmanuel Vadot int rv, rt_dir_prefix, rt_dir, session_file, i;
636e69612dSEmmanuel Vadot
646e69612dSEmmanuel Vadot session_file = -1;
656e69612dSEmmanuel Vadot rt_dir_prefix = -1;
666e69612dSEmmanuel Vadot runtime_dir_prefix = openpam_get_option(pamh, "runtime_dir_prefix");
676e69612dSEmmanuel Vadot
686e69612dSEmmanuel Vadot /* Get user info */
696e69612dSEmmanuel Vadot rv = pam_get_item(pamh, PAM_USER, (const void **)&user);
70cca0ce62SAndre Albsmeier if (rv != PAM_SUCCESS || user == NULL) {
716e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't get user information");
726e69612dSEmmanuel Vadot goto out;
736e69612dSEmmanuel Vadot }
746e69612dSEmmanuel Vadot if ((passwd = getpwnam(user)) == NULL) {
756e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't get user information");
766e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
776e69612dSEmmanuel Vadot goto out;
786e69612dSEmmanuel Vadot }
796e69612dSEmmanuel Vadot
806e69612dSEmmanuel Vadot /* Open or create the base xdg directory */
816e69612dSEmmanuel Vadot rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
826e69612dSEmmanuel Vadot if (rt_dir_prefix < 0) {
836e69612dSEmmanuel Vadot rt_dir_prefix = mkdir(RUNTIME_DIR_PREFIX, RUNTIME_DIR_PREFIX_MODE);
846e69612dSEmmanuel Vadot if (rt_dir_prefix != 0) {
856e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't mkdir %s", RUNTIME_DIR_PREFIX);
866e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
876e69612dSEmmanuel Vadot goto out;
886e69612dSEmmanuel Vadot }
896e69612dSEmmanuel Vadot rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
906e69612dSEmmanuel Vadot }
916e69612dSEmmanuel Vadot
926e69612dSEmmanuel Vadot /* Open or create the user xdg directory */
936e69612dSEmmanuel Vadot rt_dir = openat(rt_dir_prefix, user, O_DIRECTORY | O_NOFOLLOW);
946e69612dSEmmanuel Vadot if (rt_dir < 0) {
956e69612dSEmmanuel Vadot rt_dir = mkdirat(rt_dir_prefix, user, RUNTIME_DIR_MODE);
966e69612dSEmmanuel Vadot if (rt_dir != 0) {
976e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("mkdir: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, rt_dir);
986e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
996e69612dSEmmanuel Vadot goto out;
1006e69612dSEmmanuel Vadot }
1016e69612dSEmmanuel Vadot rv = fchownat(rt_dir_prefix, user, passwd->pw_uid, passwd->pw_gid, 0);
1026e69612dSEmmanuel Vadot if (rv != 0) {
1036e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("fchownat: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, rv);
1046e69612dSEmmanuel Vadot rv = unlinkat(rt_dir_prefix, user, AT_REMOVEDIR);
1056e69612dSEmmanuel Vadot if (rv == -1)
1066e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("unlinkat: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, errno);
1076e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1086e69612dSEmmanuel Vadot goto out;
1096e69612dSEmmanuel Vadot }
1106e69612dSEmmanuel Vadot } else {
111*06986e89SOlivier Certner close(rt_dir);
1126e69612dSEmmanuel Vadot /* Check that the already create dir is correctly owned */
1136e69612dSEmmanuel Vadot rv = fstatat(rt_dir_prefix, user, &sb, 0);
1146e69612dSEmmanuel Vadot if (rv == -1) {
1156e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("fstatat %s/%s failed (%d)", RUNTIME_DIR_PREFIX, user, errno);
1166e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1176e69612dSEmmanuel Vadot goto out;
1186e69612dSEmmanuel Vadot }
1196e69612dSEmmanuel Vadot if (sb.st_uid != passwd->pw_uid ||
1206e69612dSEmmanuel Vadot sb.st_gid != passwd->pw_gid) {
1216e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("%s/%s isn't owned by %d:%d\n", RUNTIME_DIR_PREFIX, user, passwd->pw_uid, passwd->pw_gid);
1226e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1236e69612dSEmmanuel Vadot goto out;
1246e69612dSEmmanuel Vadot }
1256e69612dSEmmanuel Vadot /* Test directory mode */
1266e69612dSEmmanuel Vadot if ((sb.st_mode & 0x1FF) != RUNTIME_DIR_MODE) {
1276e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("%s/%s have wrong mode\n", RUNTIME_DIR_PREFIX, user);
1286e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1296e69612dSEmmanuel Vadot goto out;
1306e69612dSEmmanuel Vadot }
1316e69612dSEmmanuel Vadot }
1326e69612dSEmmanuel Vadot
1336e69612dSEmmanuel Vadot /* Setup the environment variable */
1342d2950c8SEmmanuel Vadot rv = asprintf(&runtime_dir, "XDG_RUNTIME_DIR=%s/%s", RUNTIME_DIR_PREFIX, user);
1352d2950c8SEmmanuel Vadot if (rv < 0) {
1362d2950c8SEmmanuel Vadot PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
1372d2950c8SEmmanuel Vadot rv = PAM_SESSION_ERR;
1382d2950c8SEmmanuel Vadot goto out;
1392d2950c8SEmmanuel Vadot }
1406e69612dSEmmanuel Vadot rv = pam_putenv(pamh, runtime_dir);
1416e69612dSEmmanuel Vadot if (rv != PAM_SUCCESS) {
1426e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("pam_putenv: failed (%d)", rv);
1436e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1446e69612dSEmmanuel Vadot goto out;
1456e69612dSEmmanuel Vadot }
1466e69612dSEmmanuel Vadot
1476e69612dSEmmanuel Vadot /* Setup the session count file */
1486e69612dSEmmanuel Vadot for (i = 0; i < XDG_MAX_SESSION; i++) {
1492d2950c8SEmmanuel Vadot rv = asprintf(&xdg_session_file, "%s/xdg_session.%d", user, i);
1502d2950c8SEmmanuel Vadot if (rv < 0) {
1512d2950c8SEmmanuel Vadot PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
1522d2950c8SEmmanuel Vadot rv = PAM_SESSION_ERR;
1532d2950c8SEmmanuel Vadot goto out;
1542d2950c8SEmmanuel Vadot }
1555acbe6d1SEmmanuel Vadot rv = 0;
1566e69612dSEmmanuel Vadot session_file = openat(rt_dir_prefix, xdg_session_file, O_CREAT | O_EXCL, RUNTIME_DIR_MODE);
1576e69612dSEmmanuel Vadot free(xdg_session_file);
1586e69612dSEmmanuel Vadot if (session_file >= 0)
1596e69612dSEmmanuel Vadot break;
1606e69612dSEmmanuel Vadot }
1616e69612dSEmmanuel Vadot if (session_file < 0) {
1626e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Too many sessions");
1636e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
1646e69612dSEmmanuel Vadot goto out;
1656e69612dSEmmanuel Vadot }
1666e69612dSEmmanuel Vadot
1676e69612dSEmmanuel Vadot out:
1686e69612dSEmmanuel Vadot if (session_file >= 0)
1696e69612dSEmmanuel Vadot close(session_file);
1706e69612dSEmmanuel Vadot if (rt_dir_prefix >= 0)
1716e69612dSEmmanuel Vadot close(rt_dir_prefix);
1726e69612dSEmmanuel Vadot
1736e69612dSEmmanuel Vadot if (runtime_dir)
1746e69612dSEmmanuel Vadot free(runtime_dir);
1756e69612dSEmmanuel Vadot return (rv);
1766e69612dSEmmanuel Vadot }
1776e69612dSEmmanuel Vadot
1786e69612dSEmmanuel Vadot static int
remove_dir(int fd)1796e69612dSEmmanuel Vadot remove_dir(int fd)
1806e69612dSEmmanuel Vadot {
1816e69612dSEmmanuel Vadot DIR *dirp;
1826e69612dSEmmanuel Vadot struct dirent *dp;
1836e69612dSEmmanuel Vadot
1846e69612dSEmmanuel Vadot dirp = fdopendir(fd);
1856e69612dSEmmanuel Vadot if (dirp == NULL)
1866e69612dSEmmanuel Vadot return (-1);
1876e69612dSEmmanuel Vadot
1886e69612dSEmmanuel Vadot while ((dp = readdir(dirp)) != NULL) {
1896e69612dSEmmanuel Vadot if (dp->d_type == DT_DIR) {
1906e69612dSEmmanuel Vadot int dirfd;
1916e69612dSEmmanuel Vadot
1926e69612dSEmmanuel Vadot if (strcmp(dp->d_name, ".") == 0 ||
1936e69612dSEmmanuel Vadot strcmp(dp->d_name, "..") == 0)
1946e69612dSEmmanuel Vadot continue;
1956e69612dSEmmanuel Vadot dirfd = openat(fd, dp->d_name, 0);
1966e69612dSEmmanuel Vadot remove_dir(dirfd);
1976e69612dSEmmanuel Vadot close(dirfd);
1986e69612dSEmmanuel Vadot unlinkat(fd, dp->d_name, AT_REMOVEDIR);
1996e69612dSEmmanuel Vadot continue;
2006e69612dSEmmanuel Vadot }
2016e69612dSEmmanuel Vadot unlinkat(fd, dp->d_name, 0);
2026e69612dSEmmanuel Vadot }
20356ec98a0SEmmanuel Vadot closedir(dirp);
2046e69612dSEmmanuel Vadot
2056e69612dSEmmanuel Vadot return (0);
2066e69612dSEmmanuel Vadot }
2076e69612dSEmmanuel Vadot
2086e69612dSEmmanuel Vadot static int
_pam_xdg_close(pam_handle_t * pamh __unused,int flags __unused,int argc __unused,const char * argv[]__unused)2096e69612dSEmmanuel Vadot _pam_xdg_close(pam_handle_t *pamh __unused, int flags __unused,
2106e69612dSEmmanuel Vadot int argc __unused, const char *argv[] __unused)
2116e69612dSEmmanuel Vadot {
2126e69612dSEmmanuel Vadot struct passwd *passwd;
2136e69612dSEmmanuel Vadot const char *user;
2146e69612dSEmmanuel Vadot const char *runtime_dir_prefix;
2156e69612dSEmmanuel Vadot struct stat sb;
2166e69612dSEmmanuel Vadot char *xdg_session_file;
2176e69612dSEmmanuel Vadot int rv, rt_dir_prefix, rt_dir, session_file, i;
2186e69612dSEmmanuel Vadot
2196e69612dSEmmanuel Vadot rt_dir = -1;
2206e69612dSEmmanuel Vadot rt_dir_prefix = -1;
2216e69612dSEmmanuel Vadot runtime_dir_prefix = openpam_get_option(pamh, "runtime_dir_prefix");
2226e69612dSEmmanuel Vadot
2236e69612dSEmmanuel Vadot /* Get user info */
2246e69612dSEmmanuel Vadot rv = pam_get_item(pamh, PAM_USER, (const void **)&user);
225cca0ce62SAndre Albsmeier if (rv != PAM_SUCCESS || user == NULL) {
2266e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't get user information");
2276e69612dSEmmanuel Vadot goto out;
2286e69612dSEmmanuel Vadot }
2296e69612dSEmmanuel Vadot if ((passwd = getpwnam(user)) == NULL) {
2306e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't get user information");
2316e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2326e69612dSEmmanuel Vadot goto out;
2336e69612dSEmmanuel Vadot }
2346e69612dSEmmanuel Vadot
2356e69612dSEmmanuel Vadot /* Open the xdg base directory */
2366e69612dSEmmanuel Vadot rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
2376e69612dSEmmanuel Vadot if (rt_dir_prefix < 0) {
2386e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("open: %s failed (%d)\n", runtime_dir_prefix, rt_dir_prefix);
2396e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2406e69612dSEmmanuel Vadot goto out;
2416e69612dSEmmanuel Vadot }
2426e69612dSEmmanuel Vadot /* Check that the already created dir is correctly owned */
2436e69612dSEmmanuel Vadot rv = fstatat(rt_dir_prefix, user, &sb, 0);
2446e69612dSEmmanuel Vadot if (rv == -1) {
2456e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("fstatat %s/%s failed (%d)", RUNTIME_DIR_PREFIX, user, errno);
2466e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2476e69612dSEmmanuel Vadot goto out;
2486e69612dSEmmanuel Vadot }
2496e69612dSEmmanuel Vadot if (sb.st_uid != passwd->pw_uid ||
2506e69612dSEmmanuel Vadot sb.st_gid != passwd->pw_gid) {
2516e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("%s/%s isn't owned by %d:%d\n", RUNTIME_DIR_PREFIX, user, passwd->pw_uid, passwd->pw_gid);
2526e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2536e69612dSEmmanuel Vadot goto out;
2546e69612dSEmmanuel Vadot }
2556e69612dSEmmanuel Vadot /* Test directory mode */
2566e69612dSEmmanuel Vadot if ((sb.st_mode & 0x1FF) != RUNTIME_DIR_MODE) {
2576e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("%s/%s have wrong mode\n", RUNTIME_DIR_PREFIX, user);
2586e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2596e69612dSEmmanuel Vadot goto out;
2606e69612dSEmmanuel Vadot }
2616e69612dSEmmanuel Vadot
2626e69612dSEmmanuel Vadot /* Open the user xdg directory */
2636e69612dSEmmanuel Vadot rt_dir = openat(rt_dir_prefix, user, O_DIRECTORY | O_NOFOLLOW);
2646e69612dSEmmanuel Vadot if (rt_dir < 0) {
2656e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("openat: %s/%s failed (%d)\n", RUNTIME_DIR_PREFIX, user, rt_dir_prefix);
2666e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2676e69612dSEmmanuel Vadot goto out;
2686e69612dSEmmanuel Vadot }
2696e69612dSEmmanuel Vadot
2706e69612dSEmmanuel Vadot /* Get the last session file created */
2716e69612dSEmmanuel Vadot for (i = XDG_MAX_SESSION; i >= 0; i--) {
2722d2950c8SEmmanuel Vadot rv = asprintf(&xdg_session_file, "%s/xdg_session.%d", user, i);
2732d2950c8SEmmanuel Vadot if (rv < 0) {
2742d2950c8SEmmanuel Vadot PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
2752d2950c8SEmmanuel Vadot rv = PAM_SESSION_ERR;
2762d2950c8SEmmanuel Vadot goto out;
2772d2950c8SEmmanuel Vadot }
2785acbe6d1SEmmanuel Vadot rv = 0;
2796e69612dSEmmanuel Vadot session_file = openat(rt_dir_prefix, xdg_session_file, 0);
2806e69612dSEmmanuel Vadot if (session_file >= 0) {
2816e69612dSEmmanuel Vadot unlinkat(rt_dir_prefix, xdg_session_file, 0);
2826e69612dSEmmanuel Vadot free(xdg_session_file);
2836e69612dSEmmanuel Vadot break;
2846e69612dSEmmanuel Vadot }
2856e69612dSEmmanuel Vadot free(xdg_session_file);
2866e69612dSEmmanuel Vadot }
2876e69612dSEmmanuel Vadot if (session_file < 0) {
2886e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't find session number\n");
2896e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
2906e69612dSEmmanuel Vadot goto out;
2916e69612dSEmmanuel Vadot }
2926e69612dSEmmanuel Vadot close(session_file);
2936e69612dSEmmanuel Vadot
2946e69612dSEmmanuel Vadot /* Final cleanup if last user session */
2956e69612dSEmmanuel Vadot if (i == 0) {
2966e69612dSEmmanuel Vadot remove_dir(rt_dir);
2976e69612dSEmmanuel Vadot if (unlinkat(rt_dir_prefix, user, AT_REMOVEDIR) != 0) {
2986e69612dSEmmanuel Vadot PAM_VERBOSE_ERROR("Can't cleanup %s/%s\n", runtime_dir_prefix, user);
2996e69612dSEmmanuel Vadot rv = PAM_SESSION_ERR;
3006e69612dSEmmanuel Vadot goto out;
3016e69612dSEmmanuel Vadot }
3026e69612dSEmmanuel Vadot }
3036e69612dSEmmanuel Vadot
3046e69612dSEmmanuel Vadot rv = PAM_SUCCESS;
3056e69612dSEmmanuel Vadot out:
3066e69612dSEmmanuel Vadot if (rt_dir >= 0)
3076e69612dSEmmanuel Vadot close(rt_dir);
3086e69612dSEmmanuel Vadot if (rt_dir_prefix >= 0)
3096e69612dSEmmanuel Vadot close(rt_dir_prefix);
3106e69612dSEmmanuel Vadot return (rv);
3116e69612dSEmmanuel Vadot }
3126e69612dSEmmanuel Vadot
3136e69612dSEmmanuel Vadot PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])3146e69612dSEmmanuel Vadot pam_sm_open_session(pam_handle_t *pamh, int flags,
3156e69612dSEmmanuel Vadot int argc, const char *argv[])
3166e69612dSEmmanuel Vadot {
3176e69612dSEmmanuel Vadot
3186e69612dSEmmanuel Vadot return (_pam_xdg_open(pamh, flags, argc, argv));
3196e69612dSEmmanuel Vadot }
3206e69612dSEmmanuel Vadot
3216e69612dSEmmanuel Vadot PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])3226e69612dSEmmanuel Vadot pam_sm_close_session(pam_handle_t *pamh, int flags,
3236e69612dSEmmanuel Vadot int argc, const char *argv[])
3246e69612dSEmmanuel Vadot {
3256e69612dSEmmanuel Vadot
3266e69612dSEmmanuel Vadot return (_pam_xdg_close(pamh, flags, argc, argv));
3276e69612dSEmmanuel Vadot }
3286e69612dSEmmanuel Vadot
3296e69612dSEmmanuel Vadot PAM_MODULE_ENTRY("pam_xdg");
330