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
|
||||
RWSagIOpLGJF3yVeUzlfQ7+UJq2gIuabqKJqhiWq7h2/UY5x8mlWVY7NEag9ndV9ypuodnfpLrP0QWzNjqO3eRJ1b5zTk3MRnAs=
|
||||
SHA256 (Pkgfile) = e1b2ba87fd768518b4f81f3f9fb1fcce6780b2538cded18600564532e86f6a05
|
||||
RWSagIOpLGJF3/opxnSlpIKUNMt7/zCoADPQ4PYlOmbd2GckIrSxOZvjqNNRaw5n+mhVd/iOl35BH6C2CIKF12kK6df2J7zZ4Q8=
|
||||
SHA256 (Pkgfile) = ac39f667ad9c2778b25753a6265ef2705335afb9b5cde1f70d9cb86f9ee22076
|
||||
SHA256 (.footprint) = 56d789b652e6167f5fb93e1e6d48243e13f598c6d9a72705a8e54a003574ba31
|
||||
SHA256 (pam_xdg.c) = 9125ac3749b087f78844953a1a43790055a62efa0b8c25bd8766e35b061ca58c
|
||||
SHA256 (pam_xdg.8) = 0f19e9f2437c6d0cb24465798ded6d6a3b2be07c012ee611648a4e4f1a21bbf1
|
||||
SHA256 (pam_xdg.c) = 81bfedeb798bc63d33f2b44874df0d796b439e93876a4a41f94d1ee26a001c38
|
||||
SHA256 (pam_xdg.8) = 2929bcd6655d28127d386215d3d8c4fed6744b65c4866ac7e49d54cb438d9133
|
||||
SHA256 (makefile) = 2466f499c3e84fd821176371fa9ff78143bf94b9ec09fd9e654b35613e4ead7d
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Maintainer: Steffen Nurpmeso, steffen at sdaoden dot eu
|
||||
|
||||
name=pam_xdg
|
||||
version=20210130
|
||||
version=20210131
|
||||
release=1
|
||||
source=($name.c $name.8 makefile)
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.
|
||||
.Dd January 30, 2021
|
||||
.Dd January 31, 2021
|
||||
.Dt PAM_XDG 8
|
||||
.Os
|
||||
.
|
||||
@ -35,7 +35,7 @@
|
||||
.Sh DESCRIPTION
|
||||
.
|
||||
.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
|
||||
directory, as well as injection of environment variables denoting all
|
||||
directories specified by the
|
||||
@ -44,19 +44,17 @@ spec/\:basedir-\:spec-\:latest.html "XDG Base Directory Specification"
|
||||
into user sessions.
|
||||
.
|
||||
.Pp
|
||||
When linked into the PAM system, the runtime directory will be created as
|
||||
.Ql /run/user/`id -u`
|
||||
once a user creates his or her first login session, and it will be
|
||||
removed recursively once the last such session ends.
|
||||
When linked into the PAM session system the runtime directory will be
|
||||
created once a user creates his or her first login session.
|
||||
Unless
|
||||
.Ar rundir
|
||||
was given all XDG related environment variables will be created in the
|
||||
user session with their default or computed values, otherwise only
|
||||
was given all XDG related environment variables will be created in all
|
||||
user sessions with their default or computed values, otherwise only
|
||||
.Ev XDG_RUNTIME_DIR .
|
||||
If
|
||||
.Ar notroot
|
||||
was given the module will bypass itself for root account logins, that
|
||||
is, no actions will be performed.
|
||||
was given the module will bypass itself for root account logins and
|
||||
perform no actions for root.
|
||||
.
|
||||
.Pp
|
||||
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).
|
||||
*@ Create /run/user/`id -u` when the first session is opened, and remove it
|
||||
*@ again once the last is closed.
|
||||
*@ Create /run/user/`id -u` when the first session is opened.
|
||||
*@ It also creates according XDG_RUNTIME_DIR etc. environment variables in the
|
||||
*@ user sessions, except when given the "runtime" option, in which case it
|
||||
*@ only creates XDG_RUNTIME_DIR and not the others.
|
||||
*@ Place for example in /etc/pam.d/common-session one of the following:
|
||||
*@ session options pam_xdg.so [runtime] [notroot]
|
||||
*@ Notes: - effectively needs ISO C99 as it uses strtoull(3).
|
||||
*@ - according to XDG Base Directory Specification, v0.7.
|
||||
*@ - Linux.
|
||||
*@ Notes: - according to XDG Base Directory Specification, v0.7.
|
||||
*@ - Linux-only (i think).
|
||||
*
|
||||
* Copyright (c) 2021 Steffen Nurpmeso <steffen@sdaoden.eu>.
|
||||
* SPDX-License-Identifier: ISC
|
||||
@ -37,13 +35,9 @@
|
||||
/* */
|
||||
#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_LOCK_FILE "." a_XDG ".lck"
|
||||
#define a_LOCK_TRIES 10
|
||||
|
||||
#define a_DAT_FILE "." a_XDG ".dat"
|
||||
#define a_RUNTIME_DIR_BASE_MODE 0755 /* 0711? */
|
||||
|
||||
/* >8 -- 8< */
|
||||
|
||||
@ -55,13 +49,10 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -82,23 +73,19 @@ static int a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc,
|
||||
static int
|
||||
a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
||||
char uidbuf[sizeof "18446744073709551615"],
|
||||
wbuf[(((sizeof("18446744073709551615") -1) * 2) |
|
||||
(sizeof("cd ..;rm -rf ") + sizeof("18446744073709551615")) |
|
||||
(sizeof("XDG_RUNTIME_DIR=") + sizeof(a_RUNTIME_DIR_OUTER) +
|
||||
wbuf[((sizeof("XDG_RUNTIME_DIR=") + sizeof(a_RUNTIME_DIR_OUTER) +
|
||||
sizeof(a_RUNTIME_DIR_BASE) + sizeof("18446744073709551615")) |
|
||||
(sizeof("XDG_CONFIG_DIRS=") + PATH_MAX)
|
||||
) +1];
|
||||
struct flock flp;
|
||||
struct stat st;
|
||||
uint64_t sessions;
|
||||
struct passwd *pwp;
|
||||
char const *emsg;
|
||||
int cntrlfd, fd, cwdfd, only_runtime, notroot, res, uidbuflen;
|
||||
int cwdfd, only_runtime, notroot, res, uidbuflen;
|
||||
char const *user;
|
||||
(void)flags;
|
||||
|
||||
user = "<unset>";
|
||||
cntrlfd = fd = cwdfd = -1;
|
||||
cwdfd = -1;
|
||||
only_runtime = notroot = 0;
|
||||
|
||||
/* Command line */
|
||||
@ -114,7 +101,8 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
||||
goto jerr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
goto jok; /* No longer used, session counting does not work */
|
||||
|
||||
/* We need the user we go for */
|
||||
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 */
|
||||
if(isopen){
|
||||
/*if(isopen)*/{
|
||||
res = 0;
|
||||
while(fstatat(cwdfd, a_RUNTIME_DIR_BASE, &st, AT_SYMLINK_NOFOLLOW
|
||||
) == -1){
|
||||
@ -153,7 +141,7 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
||||
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 "
|
||||
a_RUNTIME_DIR_OUTER "/" a_RUNTIME_DIR_BASE;
|
||||
goto jerr;
|
||||
@ -170,148 +158,47 @@ a_xdg(int isopen, pam_handle_t *pamh, int flags, int argc, const char **argv){
|
||||
close(cwdfd);
|
||||
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 */
|
||||
uidbuflen = snprintf(uidbuf, sizeof(uidbuf), "%lu",
|
||||
(unsigned long)pwp->pw_uid);
|
||||
|
||||
/* We create the per-user directory on isopen time as necessary */
|
||||
for(res = 0;; ++res){
|
||||
int nfd;
|
||||
/*if(isopen)*/{
|
||||
for(res = 0;; ++res){
|
||||
int nfd;
|
||||
|
||||
if((nfd = openat(cwdfd, uidbuf, (O_PATH | O_DIRECTORY | O_NOFOLLOW))
|
||||
) != -1){
|
||||
close(cwdfd);
|
||||
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
|
||||
if((nfd = openat(cwdfd, uidbuf, (O_PATH | O_DIRECTORY | O_NOFOLLOW))
|
||||
) != -1){
|
||||
close(cwdfd);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
if(isopen){
|
||||
/*if(isopen)*/{
|
||||
char *cp;
|
||||
|
||||
/* XDG_RUNTIME_DIR */
|
||||
@ -374,10 +261,6 @@ jecnt:
|
||||
jok:
|
||||
res = PAM_SUCCESS;
|
||||
jleave:
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
if(cntrlfd != -1)
|
||||
close(cntrlfd);
|
||||
if(cwdfd != -1)
|
||||
close(cwdfd);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user