xref: /freebsd/lib/libpam/modules/pam_xdg/pam_xdg.c (revision 06986e899972ac3a127ab2ab46196672d0e1e5b2)
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