- Update 0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch
with bsc#1231699 improvements for security fix CVE-2024-47191 OBS-URL: https://build.opensuse.org/package/show/security/oath-toolkit?expand=0&rev=41
This commit is contained in:
commit
f3299b3ea7
23
.gitattributes
vendored
Normal file
23
.gitattributes
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
## Default LFS
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.bsp filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.gem filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
*.lz filter=lfs diff=lfs merge=lfs -text
|
||||
*.lzma filter=lfs diff=lfs merge=lfs -text
|
||||
*.obscpio filter=lfs diff=lfs merge=lfs -text
|
||||
*.oxt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.rpm filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.txz filter=lfs diff=lfs merge=lfs -text
|
||||
*.whl filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.osc
|
914
0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch
Normal file
914
0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch
Normal file
@ -0,0 +1,914 @@
|
||||
From 345ae06e0f698bdb1e9b4529e5a882f12df04426 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Gerstner <matthias.gerstner@suse.de>
|
||||
Date: Wed, 16 Oct 2024 09:58:35 +0200
|
||||
Subject: [PATCH] usersfile: fix potential security issues in PAM module
|
||||
|
||||
With the addition of the possibility to place a usersfile also into
|
||||
a user's home directory via variable expansion of ${HOME} and ${USER} in
|
||||
the `usersfile=` path specification, security issues sneaked in. The PAM
|
||||
process usually runs with root privileges. The file operations in an
|
||||
unprivileged user's home directory follow symlinks both when reading and
|
||||
creating files, allowing for a potential local root exploit, because of
|
||||
the `fchown()` performed on the newly created usersfile.
|
||||
|
||||
The situation is not that easy to fix, since the current PAM module
|
||||
configuration does not indicate explicitly whether the usersfile will be
|
||||
placed in an unprivileged or in a privileged location. It is advisable
|
||||
to drop privileges to the owner of the usersfile, if we're running as
|
||||
root. To determine the ownership of the usersfile, it first has to be
|
||||
opened in a safe way, though.
|
||||
|
||||
This change addresses the issue by introducing a usersfile_ctx datatype
|
||||
which holds state information about the target usersfile. The new
|
||||
function `safe_open_usersfile()` will open the target path in a safe
|
||||
way, rejecting any symlinks on the way. The function also rejects any
|
||||
world-writable directories or files, which would generally be a bad idea
|
||||
to have in the usersfile path.
|
||||
|
||||
The global `umask()` alteration is dropped in favor of using an unnamed
|
||||
temporary file to achieve the proper file permissions of a newly created
|
||||
usersfile. Since the target mode is 0600, the umask would need to be
|
||||
really awkward anyway to change the outcome. `fchown()` is no longer
|
||||
called on the new file, assuming we are already running with the correct
|
||||
credentials.
|
||||
|
||||
The locking logic of the existing code is incomplete, because the
|
||||
initial reading of the usersfile is performed without locking. Only
|
||||
during updating of the file, the lock is obtained. I believe this can
|
||||
lead to inconsistencies. Also the current code unlinks the lockfile
|
||||
after its use, which opens a race condition making the lock again
|
||||
unreliable.
|
||||
|
||||
The creation of the lockfile in the directory containing the usersfile
|
||||
is somewhat unfortunate. Lockfiles are runtime state data that should go
|
||||
into /run or a shared sticky-bit directory. It is unclear whether mixed
|
||||
root and non-root accesses need to be synchronized (probably). An
|
||||
advantage of using the location of the usersfile is that if the
|
||||
usersfile should be placed on a network share (NFS, CIFS), that the
|
||||
locking can theoretically happen across the network.
|
||||
|
||||
This patch aims to make the locking complete by acquiring it before
|
||||
parsing the actual usersfile. To prevent cluttering of users' home
|
||||
directories no separate lockfile is used anymore, but the usersfile
|
||||
itself it used for locking. This involves some extra complexity, since
|
||||
even after acquiring the lock, the actual usersfile on disk might have
|
||||
been replaced by a new one in the meantime. This situation needs to be
|
||||
detected and recovered from.
|
||||
|
||||
In the PAM module context the unprivileged user could try to DoS the
|
||||
privileged PAM stack, by taking the lock and never releasing it.
|
||||
Therefore a polling loop is implemented that fails after 15 seconds of
|
||||
failing to obtain the lock. Unfortunately there exists no lock with
|
||||
timeout API, thus it needs to be polled.
|
||||
|
||||
Instead of the POSIX compatible fcntl(F_SETLK) locking API this patch
|
||||
switches to the Linux specific fcntl(F_OFD_SETLK) locking. The reason
|
||||
for this is that locks obtained with F_SETLK cannot be inherited to
|
||||
child processes, which we need to do now. flock() would also have been
|
||||
an alternative, but it has unfortunate properties if the lockfile should
|
||||
be located on a network file system.
|
||||
|
||||
This is a follow-up version of the patch that addresses a few
|
||||
shortcomings of the originally shared patch:
|
||||
|
||||
- setgroups() is invoked to drop supplementary group membership. Without
|
||||
this the forked process wrongly retains the root group membership.
|
||||
Since the privilege drop is only an additional hardening measure, the
|
||||
original patch should still prove safe.
|
||||
- the usersfile is checked for additional hard-links; if the link count
|
||||
is not zero, then the file is rejected. This prevents possible hard
|
||||
link attacks on the end of the unprivileged user. With the Linux
|
||||
kernel sysctl protected_hardlinks set to 1 (the usual default on most
|
||||
distributions), this attack will not work either way.
|
||||
- O_NOCTTY has been added to the open() call of the usersfile. This
|
||||
makes this aspect explicit, although the code already checks that the
|
||||
file is a regular file, so the situation shouldn't arise in the first
|
||||
place.
|
||||
---
|
||||
liboath/errors.c | 7 +-
|
||||
liboath/oath.h.in | 8 +-
|
||||
liboath/usersfile.c | 706 ++++++++++++++++++++++++++++++++++++--------
|
||||
3 files changed, 593 insertions(+), 128 deletions(-)
|
||||
|
||||
diff --git a/liboath/errors.c b/liboath/errors.c
|
||||
index c1725f9..67ed008 100644
|
||||
--- a/liboath/errors.c
|
||||
+++ b/liboath/errors.c
|
||||
@@ -58,7 +58,12 @@ static const err_t errors[] = {
|
||||
ERR (OATH_FILE_SYNC_ERROR, "System error when syncing file to disk"),
|
||||
ERR (OATH_FILE_CLOSE_ERROR, "System error when closing file"),
|
||||
ERR (OATH_FILE_CHOWN_ERROR, "System error when changing file ownership"),
|
||||
- ERR (OATH_FILE_STAT_ERROR, "System error when getting file status")
|
||||
+ ERR (OATH_FILE_STAT_ERROR, "System error when getting file status"),
|
||||
+ ERR (OATH_FILE_OPEN_ERROR, "System error trying to open file"),
|
||||
+ ERR (OATH_FORK_ERROR, "System error when forking a process"),
|
||||
+ ERR (OATH_WAIT_ERROR, "System error when waiting for a process"),
|
||||
+ ERR (OATH_SETUID_ERROR, "System error when setting process UID"),
|
||||
+ ERR (OATH_SETGID_ERROR, "System error when setting process GID")
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/liboath/oath.h.in b/liboath/oath.h.in
|
||||
index b8b4fbd..5ad7045 100644
|
||||
--- a/liboath/oath.h.in
|
||||
+++ b/liboath/oath.h.in
|
||||
@@ -152,9 +152,15 @@ extern "C"
|
||||
OATH_FILE_CLOSE_ERROR = -25,
|
||||
OATH_FILE_CHOWN_ERROR = -26,
|
||||
OATH_FILE_STAT_ERROR = -27,
|
||||
+ OATH_FILE_OPEN_ERROR = -28,
|
||||
+ OATH_FORK_ERROR = -29,
|
||||
+ OATH_WAIT_ERROR = -30,
|
||||
+ OATH_SETUID_ERROR = -31,
|
||||
+ OATH_SETGID_ERROR = -32,
|
||||
+ OATH_SETGROUPS_ERROR = -33,
|
||||
/* When adding anything here, update OATH_LAST_ERROR, errors.c
|
||||
and tests/tst_errors.c. */
|
||||
- OATH_LAST_ERROR = -27
|
||||
+ OATH_LAST_ERROR = -34
|
||||
} oath_rc;
|
||||
|
||||
/* Global */
|
||||
diff --git a/liboath/usersfile.c b/liboath/usersfile.c
|
||||
index 3b139d1..c9625f4 100644
|
||||
--- a/liboath/usersfile.c
|
||||
+++ b/liboath/usersfile.c
|
||||
@@ -29,10 +29,239 @@
|
||||
#include <unistd.h> /* For ssize_t. */
|
||||
#include <fcntl.h> /* For fcntl. */
|
||||
#include <errno.h> /* For errno. */
|
||||
+#include <limits.h> /* For PATH_MAX & friends. */
|
||||
#include <sys/stat.h> /* For S_IRUSR, S_IWUSR. */
|
||||
+#include <sys/wait.h> /* For wait */
|
||||
+#include <sys/stat.h> /* For stat */
|
||||
+#include <grp.h> /* For setgroups */
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
+struct usersfile_ctx {
|
||||
+ const char *path;
|
||||
+ const char *basename; /* basename of path, points into `path` */
|
||||
+ int parent_fd; /* file descriptor for the parent directory of the usersfile */
|
||||
+ int fd; /* file descriptor for the usersfile */
|
||||
+ struct stat st; /* stat information for the usersfile */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Upgrade a file descriptor opened with O_PATH to a fully functional file
|
||||
+ * descriptor.
|
||||
+ *
|
||||
+ * To achieve this the file is reopened via /proc, which is supported by the
|
||||
+ * Linux kernel. `fd` needs to point to the currently open file descriptor. On
|
||||
+ * success it will be replaced by the new upgraded file descriptor, while the
|
||||
+ * original file descriptor will be closed.
|
||||
+ *
|
||||
+ * `flags` are passed to `open()` for the new file descriptor.
|
||||
+ */
|
||||
+static int
|
||||
+reopen_path_fd (int *fd, int flags)
|
||||
+{
|
||||
+ /* we need to open /proc/self/fd/<int>, so the path won't get too long here */
|
||||
+ char proc_path[128];
|
||||
+ int res = snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", *fd);
|
||||
+
|
||||
+ if (res < 0 || res >= sizeof(proc_path))
|
||||
+ return OATH_PRINTF_ERROR;
|
||||
+
|
||||
+ int newfd = open(proc_path, flags);
|
||||
+
|
||||
+ if (newfd < 0)
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ close(*fd);
|
||||
+ *fd = newfd;
|
||||
+ return OATH_OK;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+init_usersfile_ctx(struct usersfile_ctx *ctx, const char *path)
|
||||
+{
|
||||
+ ctx->path = path;
|
||||
+ ctx->basename = NULL;
|
||||
+ ctx->parent_fd = -1;
|
||||
+ ctx->fd = -1;
|
||||
+ memset(&ctx->st, 0, sizeof(ctx->st));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+destroy_usersfile_ctx(struct usersfile_ctx *ctx)
|
||||
+{
|
||||
+ if (ctx->parent_fd != -1)
|
||||
+ {
|
||||
+ close (ctx->parent_fd);
|
||||
+ ctx->parent_fd = -1;
|
||||
+ }
|
||||
+
|
||||
+ if (ctx->fd != -1)
|
||||
+ {
|
||||
+ close (ctx->fd);
|
||||
+ ctx->fd = -1;
|
||||
+ }
|
||||
+
|
||||
+ /* reset everything but keep the path so it might be reused */
|
||||
+ init_usersfile_ctx(ctx, ctx->path);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Obtain a lock for the usersfile. The lock is placed on the usersfile itself
|
||||
+ * as found in `ctx->fd`
|
||||
+ *
|
||||
+ * On success the lock on `ctx->fd` has been correctly obtained.
|
||||
+ */
|
||||
+static int
|
||||
+lock_usersfile (struct usersfile_ctx *ctx)
|
||||
+{
|
||||
+ /*
|
||||
+ * There exist three file locking APIs:
|
||||
+ *
|
||||
+ * - flock(): this would be the simplest API, but it doesn't properly support
|
||||
+ * network file systems like NFS, which then causes a transparent fallback
|
||||
+ * to fcntl() file locking.
|
||||
+ * - fcntl using F_SETLCK & friends: this lock is not based on the open file
|
||||
+ * description and thus cannot be inherited to child processes, which we
|
||||
+ * need to do.
|
||||
+ * - fcntl using F_OFD_SETLCK & friends: this is a Linux specific lock that
|
||||
+ * _is_ based on the open file description. It seems like the best bet for
|
||||
+ * our scenario.
|
||||
+ *
|
||||
+ * Since we are potentially running in PAM module context, we have to
|
||||
+ * take a local DoS scenario into account here, where the unprivileged user
|
||||
+ * holds the lock, preventing us from ever getting it.
|
||||
+ *
|
||||
+ * There's no file locking API supporting a timeout (except for using a
|
||||
+ * SIGALRM timer to interrupt the system call). Using asynchronous signals
|
||||
+ * in a library is not so great. Thus make a best effort polling attempt:
|
||||
+ *
|
||||
+ * `F_OFD_SETLK` polls for the lock. If we cannot get it, sleep half a
|
||||
+ * second and retry. Do this for at max 15 seconds, else fail.
|
||||
+ */
|
||||
+
|
||||
+ struct flock fl;
|
||||
+ memset(&fl, 0, sizeof(fl));
|
||||
+ /* lock the entire file with a write lock */
|
||||
+ fl.l_type = F_WRLCK;
|
||||
+ fl.l_whence = SEEK_SET;
|
||||
+ fl.l_start = 0;
|
||||
+ fl.l_len = 0;
|
||||
+
|
||||
+ for (int i = 0; i < 30; i++) {
|
||||
+ if (fcntl(ctx->fd, F_OFD_SETLK, &fl) == 0)
|
||||
+ return OATH_OK;
|
||||
+
|
||||
+ if (errno == EACCES || errno == EAGAIN)
|
||||
+ usleep(1000 * 500);
|
||||
+ else
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return OATH_FILE_LOCK_ERROR;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * After traversing all directory path elements this function actually opens
|
||||
+ * the target usersfile. `ctx->parent_fd` must be valid.
|
||||
+ *
|
||||
+ * This function takes care of the locking logic, which is a bit complicated,
|
||||
+ * since we use the usersfile itself for locking. This is done, because we
|
||||
+ * don't want to clutter arbitrary directories with lockfiles, possibly making
|
||||
+ * the locking also less robust (e.g. if users delete them interactively).
|
||||
+ *
|
||||
+ * Since we don't actually write to the usersfile, but replace it atomically,
|
||||
+ * to prevent any inconsistent state to ever be stored to disk, we need a
|
||||
+ * recovery mechanism if we obtain a lock on the file, but the file has
|
||||
+ * already been replaced by a new version. This situation is detected by
|
||||
+ * opening the file again after the lock has been placed and comparing the
|
||||
+ * inode numbers. If they no longer match, then the new file has to be locked
|
||||
+ * instead.
|
||||
+ *
|
||||
+ * On successful return ctx->fd will be valid and locked and ctx->st will
|
||||
+ * contain the current stat information for the usersfile.
|
||||
+ */
|
||||
+static int
|
||||
+finish_open_usersfile (struct usersfile_ctx *ctx)
|
||||
+{
|
||||
+ const int oflags = O_RDONLY|O_PATH|O_CLOEXEC|O_NOFOLLOW;
|
||||
+ ctx->fd = openat(ctx->parent_fd, ctx->basename, oflags);
|
||||
+
|
||||
+ if (ctx->fd < 0)
|
||||
+ return errno == ENOENT ? OATH_NO_SUCH_FILE : OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ if (fstat(ctx->fd, &ctx->st) != 0)
|
||||
+ return OATH_FILE_STAT_ERROR;
|
||||
+
|
||||
+ /* don't allow hard-linked files, which would allow to fool our logic -
|
||||
+ * this can only happen if protected_hardlinks is disabled in the kernel,
|
||||
+ * though */
|
||||
+ if (ctx->st.st_nlink > 1)
|
||||
+ {
|
||||
+ close(ctx->fd);
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ /* lock and retry opening until all is consistent, abort after a couple of
|
||||
+ * times, it's unlikely that we race all the time (could be a DoS attempt) */
|
||||
+ for (int i = 0; i < 5; i++)
|
||||
+ {
|
||||
+ /* deny world-writable or special usersfile */
|
||||
+ if ((ctx->st.st_mode & S_IWOTH) != 0 || !S_ISREG(ctx->st.st_mode))
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ /* we need to open it read-write for write-locking it via fcntl(),
|
||||
+ * otherwise we wouldn't need write access for the file, since we'll
|
||||
+ * atomically replace it with a new one. */
|
||||
+ int err = reopen_path_fd(&ctx->fd, O_RDWR|O_CLOEXEC|O_NOCTTY);
|
||||
+ if (err != OATH_OK)
|
||||
+ return err;
|
||||
+
|
||||
+ err = lock_usersfile(ctx);
|
||||
+ if (err != OATH_OK)
|
||||
+ return err;
|
||||
+
|
||||
+ /*
|
||||
+ * we now own a lock on the usersfile, but another process might already
|
||||
+ * have replaced the file in question by new version. Thus we need to
|
||||
+ * check whether the file is still there and is the same as the one we
|
||||
+ * have opened. Otherwise a race occurred an we need to retry.
|
||||
+ */
|
||||
+ int check_fd = openat(ctx->parent_fd, ctx->basename, oflags);
|
||||
+ struct stat check_st;
|
||||
+ err = fstat(check_fd, &check_st);
|
||||
+ if (err != OATH_OK)
|
||||
+ {
|
||||
+ close(check_fd);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ /* comparing the inode should be enough, since parent_fd didn't change,
|
||||
+ * so it should be the same file system */
|
||||
+ if (ctx->st.st_ino != check_st.st_ino)
|
||||
+ {
|
||||
+ /* race occurred, retry using the new FD */
|
||||
+ close(ctx->fd);
|
||||
+ ctx->fd = check_fd;
|
||||
+ memcpy(&ctx->st, &check_st, sizeof(ctx->st));
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* we own the lock and the file is still in place, we did it */
|
||||
+ close(check_fd);
|
||||
+
|
||||
+ /* now also reopen the parent directory FD, so it can be used for
|
||||
+ * fsync() later on. */
|
||||
+ err = reopen_path_fd(&ctx->parent_fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
+ if (err != OATH_OK)
|
||||
+ return err;
|
||||
+
|
||||
+ return OATH_OK;
|
||||
+ }
|
||||
+
|
||||
+ /* maximum number of locking attempts exceeded */
|
||||
+ return OATH_FILE_LOCK_ERROR;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
parse_type (const char *str, unsigned *digits, unsigned *totpstepsize)
|
||||
{
|
||||
@@ -298,8 +527,92 @@ update_usersfile2 (const char *username,
|
||||
return OATH_OK;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * create a new file in the directory referred to by ctx->parent_fd. A unique
|
||||
+ * filename will be selected and written out to `newname`.
|
||||
+ */
|
||||
+static int
|
||||
+create_new_usersfile(struct usersfile_ctx *ctx, char *newname)
|
||||
+{
|
||||
+ int err = OATH_OK;
|
||||
+ newname[0] = '\0';
|
||||
+
|
||||
+ /* create an unnamed temporary file, this way we can fix the file mode
|
||||
+ without anybody else being able to access the file */
|
||||
+ int fd = openat(ctx->parent_fd, ".", O_TMPFILE|O_WRONLY|O_CLOEXEC, 0600);
|
||||
+ if (fd < 0)
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ /* make sure the mode is as we want it, since umask might have changed the outcome. */
|
||||
+ if (fchmod(fd, 0600) != 0)
|
||||
+ {
|
||||
+ err = OATH_FILE_CHOWN_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* there's nothing like mkostmpat() where we can use our parent_fd.
|
||||
+ * tmpname() & friends are deprecated and also not fully suitable here.
|
||||
+ *
|
||||
+ * what we're actually missing here is an additional flag LINKAT_REPLACE
|
||||
+ * which would allow to atomically replace the original file, instead of
|
||||
+ * using renameat(). This doesn't exist yet, though.
|
||||
+ *
|
||||
+ * linkat() doesn't follow symlinks or overwrite files, so we're safe here
|
||||
+ * against any shenanigans. The user owning parent_fd can try to guess the
|
||||
+ * filename we're using here and thus DoS us. Setup an arbitrary limit of
|
||||
+ * creation attempts to prevent an infinite loop in such situations. Such a
|
||||
+ * bad actor would then only DoS itself, preventing login.
|
||||
+ *
|
||||
+ * Shared world-writable directories should never be used for the usersfile,
|
||||
+ * this would be a configuration error, thus we don't try to protect against
|
||||
+ * such scenarios.
|
||||
+ *
|
||||
+ * An alternative would be using rand(), but then we'd need to also seed it,
|
||||
+ * with possible process wide side effects, which is also not great.
|
||||
+ */
|
||||
+
|
||||
+ int ret = snprintf(newname, NAME_MAX, "%s.new.%d", ctx->basename, getpid());
|
||||
+ if (ret < 0 || ret >= NAME_MAX)
|
||||
+ {
|
||||
+ err = OATH_PRINTF_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* we need to specify /proc/self/fd/<int>, so the path won't get too long here */
|
||||
+ char proc_path[128];
|
||||
+ ret = snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd);
|
||||
+ if (ret < 0 || ret >= NAME_MAX)
|
||||
+ {
|
||||
+ err = OATH_PRINTF_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* we cannot reliably use AT_EMPTY_PATH here, since it can require the
|
||||
+ * CAP_DAC_READ_SEARCH capability when running as non-root. Starting with
|
||||
+ * kernel 6.10 this requirement has been softened, but we need to stay
|
||||
+ * backward compatible. Linking the magic link in /proc into the directory
|
||||
+ * works without extra capabilities.
|
||||
+ * For this workaround to function AT_SYMLINK_FOLLOW _must_ be specified
|
||||
+ * so this is a conscious decision.
|
||||
+ */
|
||||
+ if (linkat(AT_FDCWD, proc_path, ctx->parent_fd, newname, AT_SYMLINK_FOLLOW))
|
||||
+ {
|
||||
+ err = OATH_FILE_CREATE_ERROR;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ if (err != OATH_OK)
|
||||
+ {
|
||||
+ if (fd >= 0)
|
||||
+ close(fd);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return fd;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
-update_usersfile (const char *usersfile,
|
||||
+update_usersfile (struct usersfile_ctx *ctx,
|
||||
const char *username,
|
||||
const char *otp,
|
||||
FILE *infh,
|
||||
@@ -307,9 +620,7 @@ update_usersfile (const char *usersfile,
|
||||
size_t *n, char *timestamp, uint64_t new_moving_factor,
|
||||
size_t skipped_users)
|
||||
{
|
||||
- FILE *outfh, *lockfh;
|
||||
int rc;
|
||||
- char *newfilename, *lockfile;
|
||||
|
||||
/* Rewind input file. */
|
||||
{
|
||||
@@ -321,112 +632,236 @@ update_usersfile (const char *usersfile,
|
||||
clearerr (infh);
|
||||
}
|
||||
|
||||
- /* Open lockfile. */
|
||||
- {
|
||||
- int l;
|
||||
+ char newfilename[NAME_MAX];
|
||||
|
||||
- l = asprintf (&lockfile, "%s.lock", usersfile);
|
||||
- if (lockfile == NULL || ((size_t) l) != strlen (usersfile) + 5)
|
||||
- return OATH_PRINTF_ERROR;
|
||||
+ /* Open the "new" file. We aim for atomic replacement of the old file to
|
||||
+ * address possible power failure or system lockup scenarios. */
|
||||
+ int outfd = create_new_usersfile(ctx, newfilename);
|
||||
+ if (outfd < 0)
|
||||
+ {
|
||||
+ return outfd;
|
||||
+ }
|
||||
|
||||
- lockfh = fopen (lockfile, "w");
|
||||
- if (!lockfh)
|
||||
- {
|
||||
- free (lockfile);
|
||||
- return OATH_FILE_CREATE_ERROR;
|
||||
- }
|
||||
- }
|
||||
+ FILE *outfh = fdopen (outfd, "w");
|
||||
+ if (!outfh)
|
||||
+ {
|
||||
+ rc = OATH_FILE_CREATE_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- /* Lock the lockfile. */
|
||||
- {
|
||||
- struct flock l;
|
||||
+ /* ownership has been transferred to outfh */
|
||||
+ outfd = -1;
|
||||
|
||||
- memset (&l, 0, sizeof (l));
|
||||
- l.l_whence = SEEK_SET;
|
||||
- l.l_start = 0;
|
||||
- l.l_len = 0;
|
||||
- l.l_type = F_WRLCK;
|
||||
+ /* Create the new usersfile content. */
|
||||
+ rc = update_usersfile2 (username, otp, infh, outfh, lineptr, n,
|
||||
+ timestamp, new_moving_factor, skipped_users);
|
||||
|
||||
- while ((rc = fcntl (fileno (lockfh), F_SETLKW, &l)) < 0 && errno == EINTR)
|
||||
- continue;
|
||||
- if (rc == -1)
|
||||
- {
|
||||
- fclose (lockfh);
|
||||
- free (lockfile);
|
||||
- return OATH_FILE_LOCK_ERROR;
|
||||
- }
|
||||
+ if (rc != OATH_OK)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* On success, flush the buffers. */
|
||||
+ if (fflush (outfh) != 0) {
|
||||
+ rc = OATH_FILE_FLUSH_ERROR;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
- /* Open the "new" file. */
|
||||
- {
|
||||
- int l;
|
||||
+ /* On success, sync the disks. */
|
||||
+ if (fsync (fileno (outfh)) != 0) {
|
||||
+ rc = OATH_FILE_SYNC_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- l = asprintf (&newfilename, "%s.new", usersfile);
|
||||
- if (newfilename == NULL || ((size_t) l) != strlen (usersfile) + 4)
|
||||
- {
|
||||
- fclose (lockfh);
|
||||
- free (lockfile);
|
||||
- return OATH_PRINTF_ERROR;
|
||||
- }
|
||||
-
|
||||
- outfh = fopen (newfilename, "w");
|
||||
- if (!outfh)
|
||||
- {
|
||||
- free (newfilename);
|
||||
- fclose (lockfh);
|
||||
- free (lockfile);
|
||||
- return OATH_FILE_CREATE_ERROR;
|
||||
- }
|
||||
+ /* On success, replace the usersfile with the new copy.
|
||||
+ * This does not follow symlinks in the target, the target will always be
|
||||
+ * replaced.
|
||||
+ * */
|
||||
+ if (renameat (ctx->parent_fd, newfilename, ctx->parent_fd, ctx->basename) != 0) {
|
||||
+ rc = OATH_FILE_RENAME_ERROR;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
- /* Create the new usersfile content. */
|
||||
- rc = update_usersfile2 (username, otp, infh, outfh, lineptr, n,
|
||||
- timestamp, new_moving_factor, skipped_users);
|
||||
+ /* this name no longer exists now */
|
||||
+ newfilename[0] = '\0';
|
||||
|
||||
- /* Preserve ownership of the new usersfile file */
|
||||
- {
|
||||
- struct stat insb;
|
||||
+ /* make sure the directory is also synced such that directory inodes are written out */
|
||||
+ if (fsync(ctx->parent_fd) != 0) {
|
||||
+ rc = OATH_FILE_SYNC_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- if (rc == OATH_OK && fstat (fileno (infh), &insb) == -1)
|
||||
- rc = OATH_FILE_STAT_ERROR;
|
||||
+out:
|
||||
+ if (outfd >= 0)
|
||||
+ close(outfd);
|
||||
+ if (outfh)
|
||||
+ fclose(outfh);
|
||||
+ if (rc != OATH_OK && newfilename[0])
|
||||
+ unlinkat(ctx->parent_fd, newfilename, 0);
|
||||
+ return rc;
|
||||
+}
|
||||
|
||||
- if (rc == OATH_OK
|
||||
- && fchown (fileno (outfh), insb.st_uid, insb.st_gid) != 0)
|
||||
- rc = OATH_FILE_CHOWN_ERROR;
|
||||
- }
|
||||
+static int
|
||||
+oath_process_usersfile (struct usersfile_ctx *ctx,
|
||||
+ const char *username,
|
||||
+ const char *otp,
|
||||
+ size_t window,
|
||||
+ const char *passwd, time_t *last_otp)
|
||||
+{
|
||||
+ FILE *infh;
|
||||
+ char *line = NULL;
|
||||
+ size_t n = 0;
|
||||
+ uint64_t new_moving_factor;
|
||||
+ int rc;
|
||||
+ size_t skipped_users;
|
||||
|
||||
- /* On success, flush the buffers. */
|
||||
- if (rc == OATH_OK && fflush (outfh) != 0)
|
||||
- rc = OATH_FILE_FLUSH_ERROR;
|
||||
+ infh = fdopen (ctx->fd, "r");
|
||||
+ if (infh == NULL)
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
|
||||
- /* On success, sync the disks. */
|
||||
- if (rc == OATH_OK && fsync (fileno (outfh)) != 0)
|
||||
- rc = OATH_FILE_SYNC_ERROR;
|
||||
+ /* ownership has been transferred to the FILE stream now */
|
||||
+ ctx->fd = -1;
|
||||
|
||||
- /* Close the file regardless of success. */
|
||||
- if (fclose (outfh) != 0)
|
||||
- rc = OATH_FILE_CLOSE_ERROR;
|
||||
+ rc = parse_usersfile (username, otp, window, passwd, last_otp,
|
||||
+ infh, &line, &n, &new_moving_factor, &skipped_users);
|
||||
|
||||
- /* On success, overwrite the usersfile with the new copy. */
|
||||
- if (rc == OATH_OK && rename (newfilename, usersfile) != 0)
|
||||
- rc = OATH_FILE_RENAME_ERROR;
|
||||
+ if (rc == OATH_OK)
|
||||
+ {
|
||||
+ char timestamp[30];
|
||||
+ size_t max = sizeof (timestamp);
|
||||
+ struct tm now;
|
||||
+ time_t t;
|
||||
+ size_t l;
|
||||
|
||||
- /* Something has failed, don't leave garbage lying around. */
|
||||
- if (rc != OATH_OK)
|
||||
- unlink (newfilename);
|
||||
+ if (time (&t) == (time_t) - 1)
|
||||
+ return OATH_TIME_ERROR;
|
||||
+
|
||||
+ if (localtime_r (&t, &now) == NULL)
|
||||
+ return OATH_TIME_ERROR;
|
||||
|
||||
- free (newfilename);
|
||||
+ l = strftime (timestamp, max, TIME_FORMAT_STRING, &now);
|
||||
+ if (l != 20)
|
||||
+ return OATH_TIME_ERROR;
|
||||
+
|
||||
+ rc = update_usersfile (ctx, username, otp, infh,
|
||||
+ &line, &n, timestamp, new_moving_factor,
|
||||
+ skipped_users);
|
||||
+ }
|
||||
|
||||
- /* Complete, close the lockfile */
|
||||
- if (fclose (lockfh) != 0)
|
||||
- rc = OATH_FILE_CLOSE_ERROR;
|
||||
- if (unlink (lockfile) != 0)
|
||||
- rc = OATH_FILE_UNLINK_ERROR;
|
||||
- free (lockfile);
|
||||
+ free (line);
|
||||
+ fclose (infh);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Safely open `ctx->path`, filling all the other fields in `ctx` from it. On
|
||||
+ * error destroy_usersfile_ctx() is invoked for `ctx`.
|
||||
+ *
|
||||
+ * When operating with raised privileges we cannot know the ownership of
|
||||
+ * `ctx->path` in advance, thus we need to carefully open the path. Any
|
||||
+ * symbolic links in the path will be rejected for simplicity reasons.
|
||||
+ *
|
||||
+ * Every path element will be extracted step-by-step and opened by passing the
|
||||
+ * `O_PATH` flag. This is the safest approach which prevents any side effects
|
||||
+ * that might result from opening e.g. FIFO special files, symlinks or device
|
||||
+ * files.
|
||||
+ *
|
||||
+ * Once the final path element has been reached and verified, the file
|
||||
+ * descriptors have to be upgraded to regular ones without the `O_PATH`
|
||||
+ * property, for being able to use them for regular file operations.
|
||||
+ *
|
||||
+ * NOTE: a similar result can be achieved by using openat2() and passing
|
||||
+ * RESOLVE_NO_SYMLINKS, but the system call is not yet wrapped in Glibc, which
|
||||
+ * makes it hard to use it.
|
||||
+ */
|
||||
+static int
|
||||
+safe_open_usersfile (struct usersfile_ctx *ctx)
|
||||
+{
|
||||
+ int err = OATH_OK;
|
||||
+
|
||||
+ /* reject relative paths */
|
||||
+ if (ctx->path[0] != '/')
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ ctx->parent_fd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
+ if (ctx->parent_fd < 0)
|
||||
+ return OATH_FILE_OPEN_ERROR;
|
||||
+
|
||||
+ char *path_start = strdup (ctx->path);
|
||||
+ if (!path_start) {
|
||||
+ err = OATH_MALLOC_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ char *element = path_start;
|
||||
+
|
||||
+ while (true)
|
||||
+ {
|
||||
+ /* ignore any extra leading slashes */
|
||||
+ while (element[0] == '/')
|
||||
+ element++;
|
||||
+
|
||||
+ /* end of path has been reached (trailing slashes? shouldn't really happen) */
|
||||
+ if (!element[0])
|
||||
+ {
|
||||
+ err = OATH_FILE_OPEN_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ char *sep = strpbrk(element, "/");
|
||||
+
|
||||
+ /* intermediate path (directory) element */
|
||||
+ if (sep)
|
||||
+ {
|
||||
+ *sep = '\0';
|
||||
+
|
||||
+ ctx->fd = openat(ctx->parent_fd, element, O_RDONLY|O_PATH|O_CLOEXEC|O_NOFOLLOW|O_DIRECTORY);
|
||||
+
|
||||
+ if (ctx->fd < 0)
|
||||
+ {
|
||||
+ err = errno == ENOENT ? OATH_NO_SUCH_FILE : OATH_FILE_OPEN_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (fstat(ctx->fd, &ctx->st) != 0)
|
||||
+ {
|
||||
+ err = OATH_FILE_STAT_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* If we encounter any world-writable components, refuse the path.
|
||||
+ * This prevents any unwise configurations like placing the file into
|
||||
+ * /var/tmp or a dedicated world-writable sticky-bit directory from
|
||||
+ * working. */
|
||||
+ if (ctx->st.st_mode & S_IWOTH)
|
||||
+ {
|
||||
+ err = OATH_FILE_OPEN_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ close(ctx->parent_fd);
|
||||
+ ctx->parent_fd = ctx->fd;
|
||||
+ ctx->fd = -1;
|
||||
+ element = sep + 1;
|
||||
+ }
|
||||
+ /* final path element has been encountered */
|
||||
+ else
|
||||
+ {
|
||||
+ ctx->basename = ctx->path + (element - path_start);
|
||||
+ err = finish_open_usersfile(ctx);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+out:
|
||||
+ if (err != OATH_OK)
|
||||
+ {
|
||||
+ destroy_usersfile_ctx(ctx);
|
||||
+ }
|
||||
+ free (path_start);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* oath_authenticate_usersfile:
|
||||
* @usersfile: string with user credential filename, in UsersFile format
|
||||
@@ -460,52 +895,71 @@ oath_authenticate_usersfile (const char *usersfile,
|
||||
size_t window,
|
||||
const char *passwd, time_t *last_otp)
|
||||
{
|
||||
- FILE *infh;
|
||||
- char *line = NULL;
|
||||
- size_t n = 0;
|
||||
- uint64_t new_moving_factor;
|
||||
int rc;
|
||||
- size_t skipped_users;
|
||||
-
|
||||
- infh = fopen (usersfile, "r");
|
||||
- if (!infh)
|
||||
- return OATH_NO_SUCH_FILE;
|
||||
-
|
||||
- rc = parse_usersfile (username, otp, window, passwd, last_otp,
|
||||
- infh, &line, &n, &new_moving_factor, &skipped_users);
|
||||
-
|
||||
- if (rc == OATH_OK)
|
||||
+ struct usersfile_ctx ctx;
|
||||
+ init_usersfile_ctx(&ctx, usersfile);
|
||||
+
|
||||
+ rc = safe_open_usersfile (&ctx);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ /* if user is not root we cannot change credentials,
|
||||
+ just run _oath_authenticate_usersfile normally in this case.
|
||||
+ Similarly if the file is owned by root, we don't need to change
|
||||
+ credentials. */
|
||||
+ if (geteuid () != 0 || ctx.st.st_uid == 0)
|
||||
{
|
||||
- char timestamp[30];
|
||||
- size_t max = sizeof (timestamp);
|
||||
- struct tm now;
|
||||
- time_t t;
|
||||
- size_t l;
|
||||
- mode_t old_umask;
|
||||
-
|
||||
- if (time (&t) == (time_t) - 1)
|
||||
- return OATH_TIME_ERROR;
|
||||
-
|
||||
- if (localtime_r (&t, &now) == NULL)
|
||||
- return OATH_TIME_ERROR;
|
||||
-
|
||||
- l = strftime (timestamp, max, TIME_FORMAT_STRING, &now);
|
||||
- if (l != 20)
|
||||
- return OATH_TIME_ERROR;
|
||||
-
|
||||
- old_umask = umask (~(S_IRUSR | S_IWUSR));
|
||||
-
|
||||
- rc = update_usersfile (usersfile, username, otp, infh,
|
||||
- &line, &n, timestamp, new_moving_factor,
|
||||
- skipped_users);
|
||||
-
|
||||
- umask (old_umask);
|
||||
+ rc = oath_process_usersfile (&ctx, username, otp, window, passwd, last_otp);
|
||||
+ destroy_usersfile_ctx(&ctx);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
- free (line);
|
||||
- fclose (infh);
|
||||
+ /* else spawn a new process so we can drop privileges to the owner of the
|
||||
+ * file, to be on the safe side when operating in a directory owned by
|
||||
+ * non-root. */
|
||||
+ pid_t cpid = fork ();
|
||||
+ if (cpid < 0)
|
||||
+ {
|
||||
+ destroy_usersfile_ctx(&ctx);
|
||||
+ return OATH_FORK_ERROR;
|
||||
+ }
|
||||
|
||||
- return rc;
|
||||
+ if (cpid == 0)
|
||||
+ {
|
||||
+ /* child */
|
||||
+ if (setgroups(0, NULL) != 0)
|
||||
+ exit (abs(OATH_SETGROUPS_ERROR));
|
||||
+ if (setgid (ctx.st.st_gid) != 0)
|
||||
+ exit (abs(OATH_SETGID_ERROR));
|
||||
+ if (setuid (ctx.st.st_uid) != 0)
|
||||
+ exit (abs(OATH_SETUID_ERROR));
|
||||
+ rc = oath_process_usersfile (&ctx, username, otp, window, passwd, last_otp);
|
||||
+ exit (abs(rc));
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ int status;
|
||||
+ rc = waitpid (cpid, &status, 0);
|
||||
+ if (rc < 0)
|
||||
+ goto wait_out;
|
||||
+
|
||||
+ if (!WIFEXITED(status))
|
||||
+ {
|
||||
+ /* child exited abnormally */
|
||||
+ rc = OATH_WAIT_ERROR;
|
||||
+ goto wait_out;
|
||||
+ }
|
||||
+
|
||||
+ const int exit_code = WEXITSTATUS(status);
|
||||
+ rc = exit_code == 0 ? OATH_OK : -exit_code;
|
||||
+wait_out:
|
||||
+ /*
|
||||
+ * only destroy the ctx after the child exited, otherwise the lockfile
|
||||
+ * would be unlinked before the job is finished.
|
||||
+ */
|
||||
+ destroy_usersfile_ctx(&ctx);
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
--
|
||||
2.45.2
|
||||
|
135
42-null_usersfile_okay.patch
Normal file
135
42-null_usersfile_okay.patch
Normal file
@ -0,0 +1,135 @@
|
||||
From f69897e6e8b3881b9e470a384cefc41a851b2475 Mon Sep 17 00:00:00 2001
|
||||
From: Luna <luna.dragon@suse.com>
|
||||
Date: Mon, 9 Sep 2024 19:14:08 +0530
|
||||
Subject: [PATCH 2/2] pam_oath: add null_usersfile_okay parameter to pam_oath
|
||||
|
||||
Co-authored-by: Jan Zerebecki <jzerebecki@suse.com>
|
||||
Co-authored-by: Miika Alikirri <miika.alikirri@suse.com>
|
||||
---
|
||||
pam_oath/README | 10 ++++++++++
|
||||
pam_oath/pam_oath.c | 32 ++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
diff --git a/pam_oath/README b/pam_oath/README
|
||||
index 9a8e7366..3c7da052 100644
|
||||
--- a/pam_oath/README
|
||||
+++ b/pam_oath/README
|
||||
@@ -77,6 +77,7 @@ jas@mocca:~$ su
|
||||
[pam_oath.c:parse_cfg(127)] alwaysok=1
|
||||
[pam_oath.c:parse_cfg(128)] try_first_pass=0
|
||||
[pam_oath.c:parse_cfg(129)] use_first_pass=0
|
||||
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
|
||||
[pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
|
||||
[pam_oath.c:parse_cfg(131)] digits=0
|
||||
[pam_oath.c:parse_cfg(132)] window=20
|
||||
@@ -144,6 +145,7 @@ jas@mocca:~$ su
|
||||
[pam_oath.c:parse_cfg(127)] alwaysok=1
|
||||
[pam_oath.c:parse_cfg(128)] try_first_pass=0
|
||||
[pam_oath.c:parse_cfg(129)] use_first_pass=0
|
||||
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
|
||||
[pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
|
||||
[pam_oath.c:parse_cfg(131)] digits=6
|
||||
[pam_oath.c:parse_cfg(132)] window=20
|
||||
@@ -176,6 +178,7 @@ jas@mocca:~$ su
|
||||
[pam_oath.c:parse_cfg(127)] alwaysok=1
|
||||
[pam_oath.c:parse_cfg(128)] try_first_pass=0
|
||||
[pam_oath.c:parse_cfg(129)] use_first_pass=0
|
||||
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
|
||||
[pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
|
||||
[pam_oath.c:parse_cfg(131)] digits=6
|
||||
[pam_oath.c:parse_cfg(132)] window=20
|
||||
@@ -213,6 +216,13 @@ List of all parameters
|
||||
never prompt the user - if no password is
|
||||
available or the password is not appropriate, the
|
||||
user will be denied access.
|
||||
+ "no_usersfile_okay": The argument no_usersfile_okay forces the module
|
||||
+ to act as if the user is not present in the config,
|
||||
+ if the config file does not exist. This has
|
||||
+ security implications only use if you know what you
|
||||
+ are doing. E.g. if the file is in a mount like home
|
||||
+ and that fails to be mounted, then this will succeed
|
||||
+ even if the OTP if configured for that user.
|
||||
|
||||
"usersfile": Specify filename where credentials are stored, for
|
||||
example "/etc/users.oath". The placeholder values
|
||||
diff --git a/pam_oath/pam_oath.c b/pam_oath/pam_oath.c
|
||||
index 25eb83e6..72712b53 100644
|
||||
--- a/pam_oath/pam_oath.c
|
||||
+++ b/pam_oath/pam_oath.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
+#include <libgen.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
@@ -72,6 +73,7 @@ struct cfg
|
||||
int alwaysok;
|
||||
int try_first_pass;
|
||||
int use_first_pass;
|
||||
+ int no_usersfile_okay;
|
||||
char *usersfile;
|
||||
unsigned digits;
|
||||
unsigned window;
|
||||
@@ -86,6 +88,7 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
|
||||
cfg->alwaysok = 0;
|
||||
cfg->try_first_pass = 0;
|
||||
cfg->use_first_pass = 0;
|
||||
+ cfg->no_usersfile_okay = 0;
|
||||
cfg->usersfile = NULL;
|
||||
cfg->digits = -1;
|
||||
cfg->window = 5;
|
||||
@@ -100,6 +103,8 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
|
||||
cfg->try_first_pass = 1;
|
||||
if (strcmp (argv[i], "use_first_pass") == 0)
|
||||
cfg->use_first_pass = 1;
|
||||
+ if (strcmp (argv[i], "no_usersfile_okay") == 0)
|
||||
+ cfg->no_usersfile_okay = 1;
|
||||
if (strncmp (argv[i], "usersfile=", 10) == 0)
|
||||
cfg->usersfile = (char *) argv[i] + 10;
|
||||
if (strncmp (argv[i], "digits=", 7) == 0)
|
||||
@@ -126,6 +131,7 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
|
||||
D (("alwaysok=%d", cfg->alwaysok));
|
||||
D (("try_first_pass=%d", cfg->try_first_pass));
|
||||
D (("use_first_pass=%d", cfg->use_first_pass));
|
||||
+ D (("no_usersfile_okay=%d", cfg->no_usersfile_okay));
|
||||
D (("usersfile=%s", cfg->usersfile ? cfg->usersfile : "(null)"));
|
||||
D (("digits=%d", cfg->digits));
|
||||
D (("window=%d", cfg->window));
|
||||
@@ -292,6 +298,32 @@ pam_sm_authenticate (pam_handle_t *pamh,
|
||||
}
|
||||
DBG (("usersfile is %s", usersfile));
|
||||
|
||||
+ if (cfg.no_usersfile_okay)
|
||||
+ {
|
||||
+ char *ucopy, *base;
|
||||
+ ucopy = strdup (usersfile);
|
||||
+ base = dirname (ucopy);
|
||||
+
|
||||
+ /* make sure that the base dir exists so we are sure that, for example,
|
||||
+ the user home directory is mounted. */
|
||||
+ rc = access (base, F_OK);
|
||||
+ free (ucopy);
|
||||
+ if (rc != 0)
|
||||
+ {
|
||||
+ DBG (("Basepath of file cannot be accessed '%s'", usersfile));
|
||||
+ retval = PAM_AUTH_ERR;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if (access (usersfile, F_OK) != 0)
|
||||
+ {
|
||||
+ DBG (("no_usersfile_okay set and no userfile was found, authenticating..."));
|
||||
+ retval = PAM_SUCCESS;
|
||||
+ goto done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
// quick check to skip unconfigured users before prompting for password
|
||||
{
|
||||
time_t last_otp;
|
||||
--
|
||||
GitLab
|
||||
|
BIN
oath-toolkit-2.6.11.tar.gz
(Stored with Git LFS)
Normal file
BIN
oath-toolkit-2.6.11.tar.gz
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
oath-toolkit-2.6.11.tar.gz.sig
Normal file
BIN
oath-toolkit-2.6.11.tar.gz.sig
Normal file
Binary file not shown.
249
oath-toolkit.changes
Normal file
249
oath-toolkit.changes
Normal file
@ -0,0 +1,249 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Oct 16 14:24:27 UTC 2024 - Jan Zerebecki <jan.suse@zerebecki.de>
|
||||
|
||||
- Update 0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch
|
||||
with bsc#1231699 improvements for security fix CVE-2024-47191
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Sep 13 15:10:22 UTC 2024 - Jan Zerebecki <jan.suse@zerebecki.de>
|
||||
|
||||
- Fix security issue CVE-2024-47191 by adding
|
||||
0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch .
|
||||
- Add patch to implement new null_usersfile_okay argument
|
||||
42-null_usersfile_okay.patch .
|
||||
- Makes this version 2.6.11.12 to be able to depend on it.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 3 11:18:24 UTC 2024 - pgajdos@suse.com
|
||||
|
||||
- version update to 2.6.11
|
||||
* liboath: Handle invalid base32 encoded secrets. Fixes: #41.
|
||||
* Various build fixes including updated gnulib files.
|
||||
* Improve compatibility with recent libxmlsec.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sun Jul 9 12:03:29 UTC 2023 - Martin Hauke <mardnh@gmx.de>
|
||||
|
||||
- Update to version 2.6.8
|
||||
* libpskc: Fixes for recent libxmlsec releases.
|
||||
* pam_oath: Provide fallback pam_modutil_getpwnam implementation.
|
||||
* pam_oath: Don't fail authentication when pam_modutil_getpwnam
|
||||
doesn't ** know the user when usersfile don't include ${USER}
|
||||
or ${HOME}.
|
||||
* pam_oath: Self-test improvements.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Aug 2 20:39:41 UTC 2022 - Torsten Gruner <simmphonie@opensuse.org>
|
||||
|
||||
- Use %_pam_moduledir instead of hardcoding %{_lib}/security
|
||||
- Define macro _pam_moduledir if not set to fix builds for Leap and SLE
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 21 09:52:55 UTC 2022 - Marcus Meissner <meissner@suse.com>
|
||||
|
||||
- url -> https
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sun May 2 14:36:13 UTC 2021 - Martin Hauke <mardnh@gmx.de>
|
||||
|
||||
- Update to version 2.6.7
|
||||
* pam_oath: Support variables in usersfile string parameter.
|
||||
These changes introduce the ${USER} and ${HOME} placeholder
|
||||
values for the usersfile string in the pam_oath configuration
|
||||
file. The placeholder values allow the user credentials file
|
||||
to be stored in a file path that is relative to the user, and
|
||||
mimics similar behavior found in google-authenticator-libpam.
|
||||
The motivation for these changes is to allow for
|
||||
non-privileged processes to use pam_oath (e.g., for 2FA with
|
||||
xscreensaver). Non-privileged and non-suid programs are
|
||||
unable to use pam_oath. These changes are a proposed
|
||||
alternative to a suid helper binary as well.
|
||||
* doc: Fix project URL in man pages.
|
||||
* build: Drop use of libxml's AM_PATH_XML2 in favor of pkg-config.
|
||||
* build: Modernize autotools usage.
|
||||
Most importantly, no longer use -Werror with AM_INIT_AUTOMAKE
|
||||
to make rebuilding from source more safe with future automake
|
||||
versions.
|
||||
* Updated gnulib files.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jan 20 21:40:44 UTC 2021 - Martin Hauke <mardnh@gmx.de>
|
||||
|
||||
- Update to version 2.6.6
|
||||
* oathtool: Support for reading KEY and OTP from standard input
|
||||
or filename. KEY and OTP may now be given as '-' to mean
|
||||
stdin, or @FILE to read from a particular file. This is
|
||||
recommended on multi-user systems, since secrets as command
|
||||
line parameters leak.
|
||||
* pam_oath: Fix unlikely logic fail on out of memory conditions.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Dec 29 11:58:14 UTC 2020 - Martin Hauke <mardnh@gmx.de>
|
||||
|
||||
- Update to version 2.6.5
|
||||
* oathtool: Support for reading KEY and OTP from standard input
|
||||
or filename.
|
||||
KEY and OTP may now be given as '-' to mean stdin, or @FILE to
|
||||
read from a particular file. This is recommended on multi-user
|
||||
systems, since secrets as command line parameters leak.
|
||||
* pam_oath: Fix unlikely logic fail on out of memory conditions.
|
||||
* Doc fixes.
|
||||
- Update to version 2.6.4
|
||||
* libpskc: New --with-xmlsec-crypto-engine to hard-code crypto
|
||||
engine. Use it like --with-xmlsec-crypto-engine=gnutls or
|
||||
--with-xmlsec-crypto-engine=openssl if the default dynamic
|
||||
loading fails because of runtime linker search path issues.
|
||||
* oathtool --totp --verbose now prints TOTP hash mode.
|
||||
* oathtool: Hash names (e.g., SHA256) for --totp are now upper
|
||||
case. Lower/mixed case hash names are supported for
|
||||
compatibility.
|
||||
* pam_oath: Fail gracefully for missing users.
|
||||
This allows you to incrementally add support for OATH
|
||||
authentication instead of forcing it on all users.
|
||||
* Fix libpskc memory corruption bug.
|
||||
* Fix man pages.
|
||||
* Build fixes.
|
||||
- Update to version 2.6.3
|
||||
* pam_oath: Fix self-tests.
|
||||
- Drop not longer needed patches:
|
||||
* 0001-Fix-no-return-in-nonvoid-function-errors-reported-by.patch
|
||||
* 0003-pam_oath-assign-safe-default-to-alwaysok-config-memb.patch
|
||||
* 0002-update_gnulibs_files.patch
|
||||
* gnulib-libio.patch
|
||||
- Use source verification
|
||||
- Use proper source URLs
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Aug 6 07:59:16 UTC 2018 - schwab@suse.de
|
||||
|
||||
- gnulib-libio.patch: Update gnulib for libio.h removal
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Jul 5 17:00:51 UTC 2018 - matthias.gerstner@suse.com
|
||||
|
||||
- Add patch 0003-pam_oath-assign-safe-default-to-alwaysok-config-memb.patch:
|
||||
- fix potential security issue in low memory situation (bsc#1089114)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sun May 20 21:40:32 UTC 2018 - julio@juliogonzalez.es
|
||||
|
||||
- Fix build for openSUSE Leap 42.2 and 42.3
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 18 07:32:43 UTC 2018 - jengelh@inai.de
|
||||
|
||||
- Trim/update descriptions. Fix RPM groups. Remove useless
|
||||
--with-pic.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Apr 13 13:26:47 UTC 2018 - mpluskal@suse.com
|
||||
|
||||
- Run spe-cleaner
|
||||
- Drop useless conditions
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 11 12:18:59 UTC 2018 - ncutler@suse.com
|
||||
|
||||
- bring License line into closer accordance with actual licenses
|
||||
mentioned in the tarball
|
||||
- split off xml/pskc/ directory/files from liboath0 into a separate
|
||||
"oath-toolkit-xml" subpackage to prevent conflicts if two versions of the
|
||||
liboath library were ever installed at the same time
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 11 11:26:36 UTC 2018 - ncutler@suse.com
|
||||
|
||||
- use %license instead of %doc to package license-related files
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Jan 16 11:18:53 UTC 2018 - dmarcoux@posteo.de
|
||||
|
||||
- Add patch (last commit which changed source, not released in 2.6.2):
|
||||
- 0002-update_gnulibs_files.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Aug 29 20:03:11 UTC 2016 - mardnh@gmx.de
|
||||
|
||||
- Update to Version 2.6.2
|
||||
- no changes in upstream code
|
||||
- Fix RPM groups for -devel packages
|
||||
- build with libpskc on supported suse-versions
|
||||
- Add patch:
|
||||
- 0001-Fix-no-return-in-nonvoid-function-errors-reported-by.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Sep 9 14:31:24 UTC 2015 - t.gruner@katodev.de
|
||||
|
||||
- Update to Version 2.6.1 (released 2015-07-31)
|
||||
- liboath: Fix 'make check' on 32-bit systems.
|
||||
|
||||
- Version 2.6.0 (released 2015-05-19)
|
||||
- liboath: Support TOTP with HMAC-SHA256 and HMAC-SHA512.
|
||||
This adds new APIs oath_totp_generate2, oath_totp_validate4 and
|
||||
oath_totp_validate4_callback.
|
||||
- oathtool: The --totp parameter now take an optional argument to specify MAC.
|
||||
For example use --totp=sha256 to use HMAC-SHA256. When --totp is used
|
||||
the default HMAC-SHA1 is used, as before.
|
||||
- pam_oath: Mention in README that you shouldn't use insecure keys.
|
||||
- pam_oath: Check return value from strdup.
|
||||
- The files 'gdoc' and 'expect.oath' are now included in the tarball.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Jan 24 10:29:53 UTC 2015 - mardnh@gmx.de
|
||||
|
||||
- Update to version 2.4.1:
|
||||
+ liboath: Fix usersfile bug that caused it to update the wrong line.
|
||||
When an usersfile contain multiple lines for the same user but with an
|
||||
unparseable token type (e.g., HOTP vs TOTP), the code would update the
|
||||
wrong line of the file. Since the then updated line could be a
|
||||
commented out line, this can lead to the same OTP being accepted
|
||||
multiple times which is a security vulnerability. Reported by Bas van
|
||||
Schaik <bas@sj-vs.net> and patch provided by Ilkka Virta
|
||||
<itvirta@iki.fi>. CVE-2013-7322
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Jul 11 18:14:17 UTC 2014 - darin@darins.net
|
||||
|
||||
- Ran through spec-cleaner
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Oct 23 09:41:19 UTC 2013 - vuntz@opensuse.org
|
||||
|
||||
- Update to version 2.4.0:
|
||||
+ liboath: Add new API methods for validating TOTP OTPs
|
||||
- Changes from version 2.2.0:
|
||||
+ libpskc: Add functions for setting PSKC data.
|
||||
+ liboath: Permit different passwords for different tokens for
|
||||
the same user.
|
||||
+ liboath: Make header file usable from C++ (extern "C" guard).
|
||||
+ build: Improve building from git with most recent automake and
|
||||
gengetopt.
|
||||
+ build: Valgrind is not enabled by default.
|
||||
- Fix license: libraries are LGPL-2.1+ and everything else is
|
||||
GPL-3.0+. Also properly package the COPYING files.
|
||||
- Prepare build libpskc, hidden under a %{build_pskc} define:
|
||||
+ Add libxml2-devel and pkgconfig(xmlsec1) BuildRequires.
|
||||
+ Create libpskc0 and libpskc-devel subpackages.
|
||||
+ Define %{build_pskc} to 0 since we don't have libxmlsec1 yet.
|
||||
- Rework summaries and descriptions.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Jun 15 18:46:27 UTC 2013 - bwiedemann@suse.com
|
||||
|
||||
- Update to version 2.0.2
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Feb 11 00:04:02 UTC 2011 - cristian.rodriguez@opensuse.org
|
||||
|
||||
- Update to version 1.4.6
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Feb 5 18:41:54 UTC 2011 - cristian.rodriguez@opensuse.org
|
||||
|
||||
- Use libgcrypt for crypto
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Feb 5 14:46:45 UTC 2011 - cristian.rodriguez@opensuse.org
|
||||
|
||||
- Initial version
|
||||
|
23
oath-toolkit.keyring
Normal file
23
oath-toolkit.keyring
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEXJLOtBYJKwYBBAHaRw8BAQdACIcrZIvhrxDBkK9fV+QlTmXxo2naObDuGtw5
|
||||
8YaxlOu0JVNpbW9uIEpvc2Vmc3NvbiA8c2ltb25Aam9zZWZzc29uLm9yZz6IlgQT
|
||||
FggAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgBYhBLHSvRN1vst4TPT4xNc8
|
||||
9jjFPAa+BQJezg00BQkDekmAAAoJENc89jjFPAa+7QMBAKyq5ZypvFOXgcwlNtQd
|
||||
f6F+SP9LnCNSreQRYo4RxSwAAQD7A+O56xFPB1DIM74lpvaExNJFHbJXCIfFGifJ
|
||||
ycR0A7gzBFySz3UWCSsGAQQB2kcPAQEHQLzCFcHHrKzVSPDDarZPYqn89H5TPaxw
|
||||
cORgRg+4DagEiH4EGBYIACYCGyAWIQSx0r0Tdb7LeEz0+MTXPPY4xTwGvgUCXs4N
|
||||
RwUJA3pI0gAKCRDXPPY4xTwGvgxBAQCyHr8nGeaoOAmhPPOGDObOoa6/Dps+WBpm
|
||||
vFw8J/Z5AAEAtE/pypHisMHmF4cy5S/kHVzLZvfxaTAlGqtoZGHShAa4MwRcks+B
|
||||
FgkrBgEEAdpHDwEBB0DsUwiDmnlwMSNoSF+ByvW0E6TVXou9PKDa9SpZvKghioj1
|
||||
BBgWCAAmAhsCFiEEsdK9E3W+y3hM9PjE1zz2OMU8Br4FAl7ODUwFCQN6SMsAgXYg
|
||||
BBkWCAAdFiEEo8ychwudMQq61M8vUXIrCP5HRaIFAlySz4EACgkQUXIrCP5HRaKn
|
||||
TAEAoB+OWrHmYCK8Cjr1DgPUH7JnhPBmR2DbhR5jPRREEugA+gOMeWmL6GOpaPfK
|
||||
YLcNhzw4ZnAlxSLY1wq1eANBpiQOCRDXPPY4xTwGvuQiAPwKnKAbzegaSATxN1cd
|
||||
Fia4m80uJNFHMQL679WSBG3FIAEA8uLgxGud6SqFgIaFR4wrzrIgzVWqHxDuu56f
|
||||
JSf/iAe4OARcks9qEgorBgEEAZdVAQUBAQdAMZUbpg1up2WOwPlQn3pPVaRMejyZ
|
||||
nScmD7d5TRzHehwDAQgHiH4EGBYIACYCGwwWIQSx0r0Tdb7LeEz0+MTXPPY4xTwG
|
||||
vgUCXs4NQAUJA3pI1gAKCRDXPPY4xTwGvu8QAP9Ln136hLt/yLfx4KYjBxPAdfd9
|
||||
oRYd3xqWFBxNZmn+BgD/XZrhNaY3MEBV4yIx4ts6JT7dJfXGcbNjxK1T2BlXdQE=
|
||||
=moUA
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
204
oath-toolkit.spec
Normal file
204
oath-toolkit.spec
Normal file
@ -0,0 +1,204 @@
|
||||
#
|
||||
# spec file for package oath-toolkit
|
||||
#
|
||||
# Copyright (c) 2024 SUSE LLC
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
# Please submit bugfixes or comments via https://bugs.opensuse.org/
|
||||
#
|
||||
|
||||
|
||||
%{!?_pam_moduledir: %define _pam_moduledir /%{_lib}/security}
|
||||
Name: oath-toolkit
|
||||
Version: 2.6.11.12
|
||||
Release: 0
|
||||
Summary: Toolkit for one-time password authentication systems
|
||||
License: GPL-3.0-or-later AND LGPL-2.1-or-later
|
||||
Group: Productivity/Networking/Security
|
||||
URL: https://www.nongnu.org/oath-toolkit/
|
||||
Source: https://download-mirror.savannah.gnu.org/releases/%{name}/%{name}-2.6.11.tar.gz
|
||||
Source1: https://download-mirror.savannah.gnu.org/releases/%{name}/%{name}-2.6.11.tar.gz.sig
|
||||
Source99: %{name}.keyring
|
||||
Patch001: 0001-usersfile-fix-potential-security-issues-in-PAM-modul.patch
|
||||
# https://gitlab.com/oath-toolkit/oath-toolkit/-/merge_requests/42
|
||||
Patch002: 42-null_usersfile_okay.patch
|
||||
BuildRequires: bison
|
||||
BuildRequires: gengetopt
|
||||
BuildRequires: libgcrypt-devel
|
||||
BuildRequires: libtool
|
||||
BuildRequires: pam-devel
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: pkgconfig(gtk-doc)
|
||||
BuildRequires: pkgconfig(libxml-2.0)
|
||||
BuildRequires: pkgconfig(xmlsec1)
|
||||
|
||||
%description
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems. It contains shared libraries, command line
|
||||
tools and a PAM module. Supported technologies include the
|
||||
event-based HOTP algorithm (RFC4226) and the time-based TOTP algorithm
|
||||
(RFC6238). OATH stands for Open AuTHentication, which is the
|
||||
organization that specify the algorithms. For managing secret key
|
||||
files, the Portable Symmetric Key Container (PSKC) format described in
|
||||
RFC6030 is supported.
|
||||
|
||||
%package -n pam_oath
|
||||
Summary: PAM module for pluggable login authentication for OATH
|
||||
License: GPL-3.0-or-later
|
||||
Group: Productivity/Networking/Security
|
||||
|
||||
%description -n pam_oath
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems.
|
||||
|
||||
This subpackage contains a module to integrate OATH into PAM.
|
||||
|
||||
%package -n liboath0
|
||||
Summary: Library for Open AuTHentication (OATH) HOTP support
|
||||
License: LGPL-2.1-or-later
|
||||
Group: System/Libraries
|
||||
Requires: %{name}-xml >= %{version}
|
||||
|
||||
%description -n liboath0
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems. Supported technologies include the
|
||||
event-based HOTP algorithm (RFC4226) and the time-based TOTP algorithm
|
||||
(RFC6238).
|
||||
|
||||
%package xml
|
||||
Summary: XML data files needed by liboath
|
||||
License: GPL-3.0-or-later AND LGPL-2.1-or-later
|
||||
Group: Productivity/Networking/Security
|
||||
BuildArch: noarch
|
||||
|
||||
%description xml
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems. It contains shared libraries, command line
|
||||
tools and a PAM module. Supported technologies include the
|
||||
event-based HOTP algorithm (RFC4226) and the time-based TOTP algorithm
|
||||
(RFC6238). OATH stands for Open AuTHentication, which is the
|
||||
organization that specify the algorithms. For managing secret key
|
||||
files, the Portable Symmetric Key Container (PSKC) format described in
|
||||
RFC6030 is supported.
|
||||
|
||||
%package -n liboath-devel
|
||||
Summary: Development files for the Open AuTHentication (OATH) HOTP support library
|
||||
License: LGPL-2.1-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: glibc-devel
|
||||
Requires: liboath0 = %{version}
|
||||
|
||||
%description -n liboath-devel
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems.
|
||||
|
||||
This subpackage contains the header files for the HOTP/TOTP library.
|
||||
|
||||
%package -n libpskc0
|
||||
Summary: Library for Portable Symmetric Key Container
|
||||
License: LGPL-2.1-or-later
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libpskc0
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems.
|
||||
|
||||
For managing secret key files, the Portable Symmetric Key Container
|
||||
(PSKC) format described in RFC6030 is supported.
|
||||
|
||||
%package -n libpskc-devel
|
||||
Summary: Development files for the Portable Symmetric Key Container library
|
||||
License: LGPL-2.1-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: glibc-devel
|
||||
Requires: libpskc0 = %{version}
|
||||
|
||||
%description -n libpskc-devel
|
||||
The OATH Toolkit makes it possible to build one-time password
|
||||
authentication systems.
|
||||
|
||||
For managing secret key files, the Portable Symmetric Key Container
|
||||
(PSKC) format described in RFC6030 is supported.
|
||||
|
||||
This subpackage contains the headers for this library.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-2.6.11
|
||||
%patch -P 001 -p1
|
||||
%patch -P 002 -p1
|
||||
|
||||
%build
|
||||
autoreconf -fiv
|
||||
%configure \
|
||||
--with-pam-dir=%{_pam_moduledir} \
|
||||
--with-libgcrypt \
|
||||
--disable-silent-rules \
|
||||
--disable-static
|
||||
# Only SLE and openSUSE >= 15.0 are using rpm >= 4.12
|
||||
# See https://en.opensuse.org/openSUSE:Build_system_recipes#automake
|
||||
%if 0%{?sle_version} >= 150000
|
||||
%make_build
|
||||
%else
|
||||
make %{?_smp_mflags}
|
||||
%endif
|
||||
|
||||
%install
|
||||
%make_install
|
||||
mv COPYING COPYING.summary
|
||||
find %{buildroot} -type f -name "*.la" -delete -print
|
||||
|
||||
%post -n liboath0 -p /sbin/ldconfig
|
||||
%postun -n liboath0 -p /sbin/ldconfig
|
||||
%post -n libpskc0 -p /sbin/ldconfig
|
||||
%postun -n libpskc0 -p /sbin/ldconfig
|
||||
|
||||
%files
|
||||
%license COPYING.summary
|
||||
%doc ChangeLog NEWS README
|
||||
%license oathtool/COPYING
|
||||
%{_bindir}/oathtool
|
||||
%{_mandir}/man1/oathtool.*
|
||||
%{_bindir}/pskctool
|
||||
%{_mandir}/man1/pskctool.*
|
||||
|
||||
%files -n pam_oath
|
||||
%doc pam_oath/README
|
||||
%license pam_oath/COPYING
|
||||
%{_pam_moduledir}/pam_oath.so
|
||||
|
||||
%files -n liboath0
|
||||
%license liboath/COPYING
|
||||
%{_libdir}/liboath.so.*
|
||||
|
||||
%files xml
|
||||
%{_datadir}/xml/pskc/
|
||||
|
||||
%files -n liboath-devel
|
||||
%{_libdir}/liboath.so
|
||||
%{_includedir}/liboath/
|
||||
%{_libdir}/pkgconfig/liboath.pc
|
||||
%doc %{_datadir}/gtk-doc/html/liboath
|
||||
%{_mandir}/man3/oath_*
|
||||
|
||||
%files -n libpskc0
|
||||
# there's no COPYING for libpskc, but it's LGPL, like liboath
|
||||
%doc libpskc/README
|
||||
%license liboath/COPYING
|
||||
%{_libdir}/libpskc.so.*
|
||||
|
||||
%files -n libpskc-devel
|
||||
%{_libdir}/libpskc.so
|
||||
%{_includedir}/pskc/
|
||||
%{_libdir}/pkgconfig/libpskc.pc
|
||||
%doc %{_datadir}/gtk-doc/html/libpskc
|
||||
%{_mandir}/man3/pskc_*
|
||||
|
||||
%changelog
|
Loading…
Reference in New Issue
Block a user