diff options
author | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 16:18:43 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 17:01:52 -0800 |
commit | 26ee21df2a5fe63f08cfae8c7d35c24bd3dd4f04 (patch) | |
tree | e6e25c1da5974a60660c8b2108d609fae00af126 /Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c | |
parent | a3ee6f5fc767b1b01568bce6dd31fc9ca932a8d2 (diff) | |
parent | 9727ff2a3fa0e94a42b34a579027bacf4146d571 (diff) | |
download | pam-26ee21df2a5fe63f08cfae8c7d35c24bd3dd4f04.tar.gz pam-26ee21df2a5fe63f08cfae8c7d35c24bd3dd4f04.tar.bz2 pam-26ee21df2a5fe63f08cfae8c7d35c24bd3dd4f04.zip |
merge upstream version 0.99.10.0
Diffstat (limited to 'Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c')
-rw-r--r-- | Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c b/Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c new file mode 100644 index 00000000..d57dbbe3 --- /dev/null +++ b/Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c @@ -0,0 +1,346 @@ +/* Copyright © 2007, 2008 Red Hat, Inc. All rights reserved. + Red Hat author: Miloslav Trmač <mitr@redhat.com> + + Redistribution and use in source and binary forms of Linux-PAM, with + or without modification, are permitted provided that the following + conditions are met: + + 1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + + 2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + + ALTERNATIVELY, this product may be distributed under the terms of the + GNU General Public License, in which case the provisions of the GNU + GPL are required INSTEAD OF the above restrictions. (This clause is + necessary due to a potential conflict between the GNU GPL and the + restrictions contained in a BSD-style copyright.) + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. */ + +#include <errno.h> +#include <fnmatch.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <libaudit.h> +#include <linux/netlink.h> + +#define PAM_SM_SESSION + +#include <security/pam_ext.h> +#include <security/pam_modules.h> +#include <security/pam_modutil.h> + +#define DATANAME "pam_tty_audit_last_state" + +/* Open an audit netlink socket */ +static int +nl_open (void) +{ + return socket (AF_NETLINK, SOCK_RAW, NETLINK_AUDIT); +} + +static int +nl_send (int fd, unsigned type, unsigned flags, const void *data, size_t size) +{ + struct sockaddr_nl addr; + struct msghdr msg; + struct nlmsghdr nlm; + struct iovec iov[2]; + ssize_t res; + + nlm.nlmsg_len = NLMSG_LENGTH (size); + nlm.nlmsg_type = type; + nlm.nlmsg_flags = NLM_F_REQUEST | flags; + nlm.nlmsg_seq = 0; + nlm.nlmsg_pid = 0; + iov[0].iov_base = &nlm; + iov[0].iov_len = sizeof (nlm); + iov[1].iov_base = (void *)data; + iov[1].iov_len = size; + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + addr.nl_groups = 0; + msg.msg_name = &addr; + msg.msg_namelen = sizeof (addr); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + res = sendmsg (fd, &msg, 0); + if (res == -1) + return -1; + if ((size_t)res != nlm.nlmsg_len) + { + errno = EIO; + return -1; + } + return 0; +} + +static int +nl_recv (int fd, unsigned type, void *buf, size_t size) +{ + struct sockaddr_nl addr; + struct msghdr msg; + struct nlmsghdr nlm; + struct iovec iov[2]; + ssize_t res; + + again: + iov[0].iov_base = &nlm; + iov[0].iov_len = sizeof (nlm); + msg.msg_name = &addr; + msg.msg_namelen = sizeof (addr); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + if (type != NLMSG_ERROR) + { + res = recvmsg (fd, &msg, MSG_PEEK); + if (res == -1) + return -1; + if (res != NLMSG_LENGTH (0)) + { + errno = EIO; + return -1; + } + if (nlm.nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr err; + + iov[1].iov_base = &err; + iov[1].iov_len = sizeof (err); + msg.msg_iovlen = 2; + res = recvmsg (fd, &msg, 0); + if (res == -1) + return -1; + if ((size_t)res != NLMSG_LENGTH (sizeof (err)) + || nlm.nlmsg_type != NLMSG_ERROR) + { + errno = EIO; + return -1; + } + if (err.error == 0) + goto again; + errno = -err.error; + return -1; + } + } + if (size != 0) + { + iov[1].iov_base = buf; + iov[1].iov_len = size; + msg.msg_iovlen = 2; + } + res = recvmsg (fd, &msg, 0); + if (res == -1) + return -1; + if ((size_t)res != NLMSG_LENGTH (size) + || nlm.nlmsg_type != type) + { + errno = EIO; + return -1; + } + return 0; +} + +static int +nl_recv_ack (int fd) +{ + struct nlmsgerr err; + + if (nl_recv (fd, NLMSG_ERROR, &err, sizeof (err)) != 0) + return -1; + if (err.error != 0) + { + errno = -err.error; + return -1; + } + return 0; +} + +static void +cleanup_old_status (pam_handle_t *pamh, void *data, int error_status) +{ + (void)pamh; + (void)error_status; + free (data); +} + +int +pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + enum command { CMD_NONE, CMD_ENABLE, CMD_DISABLE }; + + enum command command; + struct audit_tty_status *old_status, new_status; + const char *user; + int i, fd, open_only; + + (void)flags; + + if (pam_get_user (pamh, &user, NULL) != PAM_SUCCESS) + { + pam_syslog (pamh, LOG_ERR, "error determining target user's name"); + return PAM_SESSION_ERR; + } + + command = CMD_NONE; + open_only = 0; + for (i = 0; i < argc; i++) + { + if (strncmp (argv[i], "enable=", 7) == 0 + || strncmp (argv[i], "disable=", 8) == 0) + { + enum command this_command; + char *copy, *tok_data, *tok; + + this_command = *argv[i] == 'e' ? CMD_ENABLE : CMD_DISABLE; + copy = strdup (strchr (argv[i], '=') + 1); + if (copy == NULL) + return PAM_SESSION_ERR; + for (tok = strtok_r (copy, ",", &tok_data); tok != NULL; + tok = strtok_r (NULL, ",", &tok_data)) + { + if (fnmatch (tok, user, 0) == 0) + { + command = this_command; + break; + } + } + free (copy); + } + else if (strcmp (argv[i], "open_only") == 0) + open_only = 1; + else + { + pam_syslog (pamh, LOG_ERR, "unknown option `%s'", argv[i]); + return PAM_SESSION_ERR; + } + } + if (command == CMD_NONE) + return PAM_SUCCESS; + + old_status = malloc (sizeof (*old_status)); + if (old_status == NULL) + return PAM_SESSION_ERR; + + fd = nl_open (); + if (fd == -1 + || nl_send (fd, AUDIT_TTY_GET, 0, NULL, 0) != 0 + || nl_recv (fd, AUDIT_TTY_GET, old_status, sizeof (*old_status)) != 0) + { + pam_syslog (pamh, LOG_ERR, "error reading current audit status: %m"); + if (fd != -1) + close (fd); + free (old_status); + return PAM_SESSION_ERR; + } + + new_status.enabled = (command == CMD_ENABLE ? 1 : 0); + if (old_status->enabled == new_status.enabled) + { + free (old_status); + goto ok_fd; + } + + if (open_only == 0 + && pam_set_data (pamh, DATANAME, old_status, cleanup_old_status) + != PAM_SUCCESS) + { + pam_syslog (pamh, LOG_ERR, "error saving old audit status"); + close (fd); + free (old_status); + return PAM_SESSION_ERR; + } + + if (nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, &new_status, + sizeof (new_status)) != 0 + || nl_recv_ack (fd) != 0) + { + pam_syslog (pamh, LOG_ERR, "error setting current audit status: %m"); + close (fd); + if (open_only != 0) + free (old_status); + return PAM_SESSION_ERR; + } + /* Fall through */ + ok_fd: + close (fd); + pam_syslog (pamh, LOG_DEBUG, "changed status from %d to %d", + old_status->enabled, new_status.enabled); + if (open_only != 0) + free (old_status); + return PAM_SUCCESS; +} + +int +pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + const void *status_; + + (void)flags; + (void)argc; + (void)argv; + if (pam_get_data (pamh, DATANAME, &status_) == PAM_SUCCESS) + { + const struct audit_tty_status *status; + int fd; + + status = status_; + + fd = nl_open (); + if (fd == -1 + || nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, status, + sizeof (*status)) != 0 + || nl_recv_ack (fd) != 0) + { + pam_syslog (pamh, LOG_ERR, "error restoring audit status: %m"); + if (fd != -1) + close (fd); + return PAM_SESSION_ERR; + } + close (fd); + pam_syslog (pamh, LOG_ERR, "restored status to %d", status->enabled); + } + return PAM_SUCCESS; +} + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_tty_audit_modstruct = { + "pam_tty_audit", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL +}; +#endif |