forked from ports/contrib
pam_xdg: strip to minimum (cannot track sessions via PAM), thus graceful
This commit is contained in:
parent
28d6763c03
commit
f2193cf1ac
@ -1,7 +1,7 @@
|
|||||||
untrusted comment: verify with /etc/ports/contrib.pub
|
untrusted comment: verify with /etc/ports/contrib.pub
|
||||||
RWSagIOpLGJF3yVeUzlfQ7+UJq2gIuabqKJqhiWq7h2/UY5x8mlWVY7NEag9ndV9ypuodnfpLrP0QWzNjqO3eRJ1b5zTk3MRnAs=
|
RWSagIOpLGJF3/opxnSlpIKUNMt7/zCoADPQ4PYlOmbd2GckIrSxOZvjqNNRaw5n+mhVd/iOl35BH6C2CIKF12kK6df2J7zZ4Q8=
|
||||||
SHA256 (Pkgfile) = e1b2ba87fd768518b4f81f3f9fb1fcce6780b2538cded18600564532e86f6a05
|
SHA256 (Pkgfile) = ac39f667ad9c2778b25753a6265ef2705335afb9b5cde1f70d9cb86f9ee22076
|
||||||
SHA256 (.footprint) = 56d789b652e6167f5fb93e1e6d48243e13f598c6d9a72705a8e54a003574ba31
|
SHA256 (.footprint) = 56d789b652e6167f5fb93e1e6d48243e13f598c6d9a72705a8e54a003574ba31
|
||||||
SHA256 (pam_xdg.c) = 9125ac3749b087f78844953a1a43790055a62efa0b8c25bd8766e35b061ca58c
|
SHA256 (pam_xdg.c) = 81bfedeb798bc63d33f2b44874df0d796b439e93876a4a41f94d1ee26a001c38
|
||||||
SHA256 (pam_xdg.8) = 0f19e9f2437c6d0cb24465798ded6d6a3b2be07c012ee611648a4e4f1a21bbf1
|
SHA256 (pam_xdg.8) = 2929bcd6655d28127d386215d3d8c4fed6744b65c4866ac7e49d54cb438d9133
|
||||||
SHA256 (makefile) = 2466f499c3e84fd821176371fa9ff78143bf94b9ec09fd9e654b35613e4ead7d
|
SHA256 (makefile) = 2466f499c3e84fd821176371fa9ff78143bf94b9ec09fd9e654b35613e4ead7d
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# Maintainer: Steffen Nurpmeso, steffen at sdaoden dot eu
|
# Maintainer: Steffen Nurpmeso, steffen at sdaoden dot eu
|
||||||
|
|
||||||
name=pam_xdg
|
name=pam_xdg
|
||||||
version=20210130
|
version=20210131
|
||||||
release=1
|
release=1
|
||||||
source=($name.c $name.8 makefile)
|
source=($name.c $name.8 makefile)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.
|
.
|
||||||
.Dd January 30, 2021
|
.Dd January 31, 2021
|
||||||
.Dt PAM_XDG 8
|
.Dt PAM_XDG 8
|
||||||
.Os
|
.Os
|
||||||
.
|
.
|
||||||
@ -35,7 +35,7 @@
|
|||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.
|
.
|
||||||
.Nm
|
.Nm
|
||||||
is a PAM module that manages creation and deletion of the
|
is a PAM module that manages creation of the
|
||||||
.Ev XDG_RUNTIME_DIR
|
.Ev XDG_RUNTIME_DIR
|
||||||
directory, as well as injection of environment variables denoting all
|
directory, as well as injection of environment variables denoting all
|
||||||
directories specified by the
|
directories specified by the
|
||||||
@ -44,19 +44,17 @@ spec/\:basedir-\:spec-\:latest.html "XDG Base Directory Specification"
|
|||||||
into user sessions.
|
into user sessions.
|
||||||
.
|
.
|
||||||
.Pp
|
.Pp
|
||||||
When linked into the PAM system, the runtime directory will be created as
|
When linked into the PAM session system the runtime directory will be
|
||||||
.Ql /run/user/`id -u`
|
created once a user creates his or her first login session.
|
||||||
once a user creates his or her first login session, and it will be
|
|
||||||
removed recursively once the last such session ends.
|
|
||||||
Unless
|
Unless
|
||||||
.Ar rundir
|
.Ar rundir
|
||||||
was given all XDG related environment variables will be created in the
|
was given all XDG related environment variables will be created in all
|
||||||
user session with their default or computed values, otherwise only
|
user sessions with their default or computed values, otherwise only
|
||||||
.Ev XDG_RUNTIME_DIR .
|
.Ev XDG_RUNTIME_DIR .
|
||||||
If
|
If
|
||||||
.Ar notroot
|
.Ar notroot
|
||||||
was given the module will bypass itself for root account logins, that
|
was given the module will bypass itself for root account logins and
|
||||||
is, no actions will be performed.
|
perform no actions for root.
|
||||||
.
|
.
|
||||||
.Pp
|
.Pp
|
||||||
In order to make use of this script, place the following in the control
|
In order to make use of this script, place the following in the control
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
/*@ pam_xdg - manage XDG Base Directories (runtime dir life time, environment).
|
/*@ pam_xdg - manage XDG Base Directories (runtime dir life time, environment).
|
||||||
*@ Create /run/user/`id -u` when the first session is opened, and remove it
|
*@ Create /run/user/`id -u` when the first session is opened.
|
||||||
*@ again once the last is closed.
|
|
||||||
*@ It also creates according XDG_RUNTIME_DIR etc. environment variables in the
|
*@ It also creates according XDG_RUNTIME_DIR etc. environment variables in the
|
||||||
*@ user sessions, except when given the "runtime" option, in which case it
|
*@ user sessions, except when given the "runtime" option, in which case it
|
||||||
*@ only creates XDG_RUNTIME_DIR and not the others.
|
*@ only creates XDG_RUNTIME_DIR and not the others.
|
||||||
*@ Place for example in /etc/pam.d/common-session one of the following:
|
*@ Place for example in /etc/pam.d/common-session one of the following:
|
||||||
*@ session options pam_xdg.so [runtime] [notroot]
|
*@ session options pam_xdg.so [runtime] [notroot]
|
||||||
*@ Notes: - effectively needs ISO C99 as it uses strtoull(3).
|
*@ Notes: - according to XDG Base Directory Specification, v0.7.
|
||||||
*@ - according to XDG Base Directory Specification, v0.7.
|
*@ - Linux-only (i think).
|
||||||
*@ - Linux.
|
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Steffen Nurpmeso <steffen@sdaoden.eu>.
|
* Copyright (c) 2021 Steffen Nurpmeso <steffen@sdaoden.eu>.
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
@ -37,13 +35,9 @@
|
|||||||
/* */
|
/* */
|
||||||
#define a_XDG "pam_xdg"
|
#define a_XDG "pam_xdg"
|
||||||
|
|
||||||
#define a_RUNTIME_DIR_OUTER "/run" /* This must exist already */
|
#define a_RUNTIME_DIR_OUTER "/run" /* This must exist already */
|
||||||
#define a_RUNTIME_DIR_BASE "user" /* We create this as necessary, thus. */
|
#define a_RUNTIME_DIR_BASE "user" /* We create this as necessary, thus. */
|
||||||
|
#define a_RUNTIME_DIR_BASE_MODE 0755 /* 0711? */
|
||||||
#define a_LOCK_FILE "." a_XDG ".lck"
|
|
||||||
#define a_LOCK_TRIES 10
|
|
||||||
|
|
||||||
#define a_DAT_FILE "." a_XDG ".dat"
|
|
||||||
|
|
||||||
/* >8 -- 8< */
|
/* >8 -- 8< */
|
||||||
|
|
||||||
@ -55,13 +49,10 @@
|
|||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -82,23 +73,19 @@ static int a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc,
|
|||||||
static int
|
static int
|
||||||
a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
||||||
char uidbuf[sizeof "18446744073709551615"],
|
char uidbuf[sizeof "18446744073709551615"],
|
||||||
wbuf[(((sizeof("18446744073709551615") -1) * 2) |
|
wbuf[((sizeof("XDG_RUNTIME_DIR=") + sizeof(a_RUNTIME_DIR_OUTER) +
|
||||||
(sizeof("cd ..;rm -rf ") + sizeof("18446744073709551615")) |
|
|
||||||
(sizeof("XDG_RUNTIME_DIR=") + sizeof(a_RUNTIME_DIR_OUTER) +
|
|
||||||
sizeof(a_RUNTIME_DIR_BASE) + sizeof("18446744073709551615")) |
|
sizeof(a_RUNTIME_DIR_BASE) + sizeof("18446744073709551615")) |
|
||||||
(sizeof("XDG_CONFIG_DIRS=") + PATH_MAX)
|
(sizeof("XDG_CONFIG_DIRS=") + PATH_MAX)
|
||||||
) +1];
|
) +1];
|
||||||
struct flock flp;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
uint64_t sessions;
|
|
||||||
struct passwd *pwp;
|
struct passwd *pwp;
|
||||||
char const *emsg;
|
char const *emsg;
|
||||||
int cntrlfd, fd, cwdfd, only_runtime, notroot, res, uidbuflen;
|
int cwdfd, only_runtime, notroot, res, uidbuflen;
|
||||||
char const *user;
|
char const *user;
|
||||||
(void)flags;
|
(void)flags;
|
||||||
|
|
||||||
user = "<unset>";
|
user = "<unset>";
|
||||||
cntrlfd = fd = cwdfd = -1;
|
cwdfd = -1;
|
||||||
only_runtime = notroot = 0;
|
only_runtime = notroot = 0;
|
||||||
|
|
||||||
/* Command line */
|
/* Command line */
|
||||||
@ -114,7 +101,8 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
|||||||
goto jerr;
|
goto jerr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}else
|
||||||
|
goto jok; /* No longer used, session counting does not work */
|
||||||
|
|
||||||
/* We need the user we go for */
|
/* We need the user we go for */
|
||||||
if((res = pam_get_item(pamh, PAM_USER, (void const**)&user)
|
if((res = pam_get_item(pamh, PAM_USER, (void const**)&user)
|
||||||
@ -143,7 +131,7 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We try create the base directory once as necessary */
|
/* We try create the base directory once as necessary */
|
||||||
if(isopen){
|
/*if(isopen)*/{
|
||||||
res = 0;
|
res = 0;
|
||||||
while(fstatat(cwdfd, a_RUNTIME_DIR_BASE, &st, AT_SYMLINK_NOFOLLOW
|
while(fstatat(cwdfd, a_RUNTIME_DIR_BASE, &st, AT_SYMLINK_NOFOLLOW
|
||||||
) == -1){
|
) == -1){
|
||||||
@ -153,7 +141,7 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
|||||||
goto jerr;
|
goto jerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mkdirat(cwdfd, a_RUNTIME_DIR_BASE, 0711) == -1){
|
if(mkdirat(cwdfd, a_RUNTIME_DIR_BASE, a_RUNTIME_DIR_BASE_MODE) == -1){
|
||||||
emsg = "cannot create base directory "
|
emsg = "cannot create base directory "
|
||||||
a_RUNTIME_DIR_OUTER "/" a_RUNTIME_DIR_BASE;
|
a_RUNTIME_DIR_OUTER "/" a_RUNTIME_DIR_BASE;
|
||||||
goto jerr;
|
goto jerr;
|
||||||
@ -170,148 +158,47 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
|||||||
close(cwdfd);
|
close(cwdfd);
|
||||||
cwdfd = res;
|
cwdfd = res;
|
||||||
|
|
||||||
/* Landed in the runtime base dir, obtain our lock */
|
|
||||||
if((cntrlfd = openat(cwdfd, a_LOCK_FILE,
|
|
||||||
(O_CREAT | O_WRONLY | O_NOFOLLOW | O_NOCTTY),
|
|
||||||
(S_IRUSR | S_IWUSR))) == -1){
|
|
||||||
emsg = "cannot open control lock file";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(res = a_LOCK_TRIES;;){
|
|
||||||
memset(&flp, 0, sizeof flp);
|
|
||||||
flp.l_type = F_WRLCK;
|
|
||||||
flp.l_start = 0;
|
|
||||||
flp.l_whence = SEEK_SET;
|
|
||||||
flp.l_len = 0;
|
|
||||||
|
|
||||||
if(fcntl(cntrlfd, F_SETLKW, &flp) != -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(errno != EINTR){
|
|
||||||
emsg = "unexpected error obtaining lock on control lock file";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
if(--res == 0){
|
|
||||||
emsg = "cannot obtain lock on control lock file";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turn to user management */
|
/* Turn to user management */
|
||||||
uidbuflen = snprintf(uidbuf, sizeof(uidbuf), "%lu",
|
uidbuflen = snprintf(uidbuf, sizeof(uidbuf), "%lu",
|
||||||
(unsigned long)pwp->pw_uid);
|
(unsigned long)pwp->pw_uid);
|
||||||
|
|
||||||
/* We create the per-user directory on isopen time as necessary */
|
/* We create the per-user directory on isopen time as necessary */
|
||||||
for(res = 0;; ++res){
|
/*if(isopen)*/{
|
||||||
int nfd;
|
for(res = 0;; ++res){
|
||||||
|
int nfd;
|
||||||
|
|
||||||
if((nfd = openat(cwdfd, uidbuf, (O_PATH | O_DIRECTORY | O_NOFOLLOW))
|
if((nfd = openat(cwdfd, uidbuf, (O_PATH | O_DIRECTORY | O_NOFOLLOW))
|
||||||
) != -1){
|
) != -1){
|
||||||
close(cwdfd);
|
close(cwdfd);
|
||||||
cwdfd = nfd;
|
cwdfd = nfd;
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
if(errno == ENOENT){
|
|
||||||
if(!isopen)
|
|
||||||
goto jok;
|
|
||||||
if(res != 0)
|
|
||||||
goto jeurd;
|
|
||||||
}else{
|
|
||||||
jeurd:
|
|
||||||
emsg = "per user XDG_RUNTIME_DIR not accessible";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mkdirat(cwdfd, uidbuf, 0700) == -1){
|
|
||||||
emsg = "cannot create per user XDG_RUNTIME_DIR";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
if(fchownat(cwdfd, uidbuf, pwp->pw_uid, pwp->pw_gid, AT_SYMLINK_NOFOLLOW
|
|
||||||
) == -1){
|
|
||||||
emsg = "cannot chown(2) per user XDG_RUNTIME_DIR";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read session counter; be simple and assume 0 if non-existent, this should
|
|
||||||
* not happen in practice */
|
|
||||||
sessions = 0;
|
|
||||||
if((fd = openat(cwdfd, a_DAT_FILE, O_RDONLY)) != -1){
|
|
||||||
char *ep;
|
|
||||||
ssize_t r;
|
|
||||||
|
|
||||||
while((r = read(fd, wbuf, sizeof(wbuf) -1)) == -1){
|
|
||||||
if(errno != EINTR){
|
|
||||||
emsg = "I/O error while reading session counter";
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have written this as a valid POSIX text file, then, so chop tail */
|
|
||||||
if(r < 1 || (size_t)r >= (sizeof(wbuf) -1) / 2){
|
|
||||||
jecnt:
|
|
||||||
emsg = "session counter corrupted, ask administrator to remove "
|
|
||||||
a_RUNTIME_DIR_OUTER "/" a_RUNTIME_DIR_BASE "/YOUR-UID/"
|
|
||||||
a_DAT_FILE;
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
for(;;){
|
|
||||||
char c;
|
|
||||||
|
|
||||||
c = wbuf[(size_t)r - 1];
|
|
||||||
if(c == '\0' || c == '\n'){
|
|
||||||
if(--r == 0)
|
|
||||||
goto jecnt;
|
|
||||||
}else
|
|
||||||
break;
|
break;
|
||||||
|
}else{
|
||||||
|
if(errno == ENOENT){
|
||||||
|
if(!isopen)
|
||||||
|
goto jok;
|
||||||
|
if(res != 0)
|
||||||
|
goto jeurd;
|
||||||
|
}else{
|
||||||
|
jeurd:
|
||||||
|
emsg = "per user XDG_RUNTIME_DIR not accessible";
|
||||||
|
goto jerr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mkdirat(cwdfd, uidbuf, 0700) == -1){
|
||||||
|
emsg = "cannot create per user XDG_RUNTIME_DIR";
|
||||||
|
goto jerr;
|
||||||
|
}
|
||||||
|
if(fchownat(cwdfd, uidbuf, pwp->pw_uid, pwp->pw_gid,
|
||||||
|
AT_SYMLINK_NOFOLLOW) == -1){
|
||||||
|
emsg = "cannot chown(2) per user XDG_RUNTIME_DIR";
|
||||||
|
goto jerr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wbuf[(size_t)r] = '\0';
|
|
||||||
|
|
||||||
sessions = strtoull(wbuf, &ep, 10);
|
|
||||||
if(sessions == ULLONG_MAX || ep == wbuf || *ep != '\0')
|
|
||||||
goto jecnt;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isopen)
|
|
||||||
++sessions;
|
|
||||||
/* == 0 should never happen, but just handled it easily */
|
|
||||||
else if(sessions == 0 || --sessions == 0){
|
|
||||||
/* This is ridiculously simple, but everything else would be opposite */
|
|
||||||
char const cmd[] = "rm -rf " a_RUNTIME_DIR_OUTER "/"
|
|
||||||
a_RUNTIME_DIR_BASE "/";
|
|
||||||
|
|
||||||
memcpy(wbuf, cmd, sizeof(cmd) -1);
|
|
||||||
memcpy(&wbuf[sizeof(cmd) -1], uidbuf, uidbuflen +1);
|
|
||||||
res = system(wbuf);
|
|
||||||
if(!WIFEXITED(res) || WEXITSTATUS(res) != 0){
|
|
||||||
emsg = "unable to rm(1) -rf per user XDG_RUNTIME_DIR";
|
|
||||||
errno = EINVAL;
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
goto jok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write out session counter (as a valid POSIX text file) */
|
|
||||||
res = snprintf(wbuf, sizeof wbuf, "%llu\n", (unsigned long long)sessions);
|
|
||||||
|
|
||||||
if(((fd = openat(cwdfd, a_DAT_FILE,
|
|
||||||
(O_CREAT | O_TRUNC | O_WRONLY | O_SYNC | O_NOFOLLOW | O_NOCTTY),
|
|
||||||
(S_IRUSR | S_IWUSR))) == -1) || write(fd, wbuf, res) != res){
|
|
||||||
emsg = "cannot write session counter, ask administrator to remove "
|
|
||||||
a_RUNTIME_DIR_OUTER "/" a_RUNTIME_DIR_BASE "/YOUR-UID/"
|
|
||||||
a_DAT_FILE;
|
|
||||||
goto jerr;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
|
|
||||||
/* When opening, we want to put environment variables, too */
|
/* When opening, we want to put environment variables, too */
|
||||||
if(isopen){
|
/*if(isopen)*/{
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
/* XDG_RUNTIME_DIR */
|
/* XDG_RUNTIME_DIR */
|
||||||
@ -374,10 +261,6 @@ jecnt:
|
|||||||
jok:
|
jok:
|
||||||
res = PAM_SUCCESS;
|
res = PAM_SUCCESS;
|
||||||
jleave:
|
jleave:
|
||||||
if(fd != -1)
|
|
||||||
close(fd);
|
|
||||||
if(cntrlfd != -1)
|
|
||||||
close(cntrlfd);
|
|
||||||
if(cwdfd != -1)
|
if(cwdfd != -1)
|
||||||
close(cwdfd);
|
close(cwdfd);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user