-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
pam_dumb_runtime_dir.c
96 lines (84 loc) · 2.87 KB
/
pam_dumb_runtime_dir.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
* pam_dumb_runtime_dir.c
*
* Creates an XDG_RUNTIME_DIR directory on login per the freedesktop.org
* base directory spec. Flaunts the spec and never removes it, even after
* last logout. This keeps things simple and predictable.
*
* The user is responsible for ensuring that the RUNTIME_DIR_PARENT directory,
* (/run/user by default) exists and is only writable by root.
*
* Copyright 2021 Isaac Freund
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <security/pam_modules.h>
int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
(void)flags;
(void)argc;
(void)argv;
const char *user;
if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
return PAM_SESSION_ERR;
}
struct passwd *pw = getpwnam(user);
if (pw == NULL) {
return PAM_SESSION_ERR;
}
/* The bit size of uintmax_t will always be larger than the number of
* bytes needed to print it. */
char buffer[sizeof("XDG_RUNTIME_DIR="RUNTIME_DIR_PARENT"/") +
sizeof(uintmax_t) * 8];
/* Valid UIDs are always positive even if POSIX allows the uid_t type
* itself to be signed. Therefore, we can convert to uintmax_t for
* safe formatting. */
int ret = snprintf(buffer, sizeof(buffer),
"XDG_RUNTIME_DIR="RUNTIME_DIR_PARENT"/%ju", (uintmax_t)pw->pw_uid);
assert(ret >= 0 && (size_t)ret < sizeof(buffer));
const char *path = buffer + sizeof("XDG_RUNTIME_DIR=") - 1;
if (mkdir(path, 0700) < 0) {
/* It's ok if the directory already exists, in that case we just
* ensure the mode is correct before we chown(). */
if (errno != EEXIST) {
return PAM_SESSION_ERR;
}
if (chmod(path, 0700) < 0) {
return PAM_SESSION_ERR;
}
}
if (chown(path, pw->pw_uid, pw->pw_gid) < 0) {
return PAM_SESSION_ERR;
}
if (pam_putenv(pamh, buffer) != PAM_SUCCESS) {
return PAM_SESSION_ERR;
}
return PAM_SUCCESS;
}
/* PAM requires all functions in a group to be defined, even if a noop is
* desired. Otherwise, PAM_MODULE_UNKNOWN is returned when the application
* calls pam_close_session(3). */
int pam_sm_close_session(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
(void)pamh;
(void)flags;
(void)argc;
(void)argv;
return PAM_SUCCESS;
}