Discussion:
PAM support in tmux?
Ben Boeckel
2011-07-22 01:47:43 UTC
Permalink
Hi,

With systemd-logind, there will be the option to kill all user processes
on logout. I was wondering whether a patch to start a PAM session for
each tmux server would be accepted. It would be a compile-time option
and if wanted, options could also be added. Thanks.

--Ben

[1]http://0pointer.de/public/systemd-man/systemd-logind.conf.html
Nicholas Marriott
2011-07-22 02:06:01 UTC
Permalink
Maybe. Can you give a bit more explanation? What is systemd-logind and
why does this option have anything to do with PAM? Why does it need PAM
to kill processes on logout?

I'm not really clear on the use case either. It seems to me that if the
admin wants to kill all processes of a user on logout then tmux
shouldn't be an exception (or if it is, it should be in the program
doing the killing and configured by the admin, not in tmux). Or if the
user wants to kill processes, why can't they do what they do now and
tmux will keep running as normal since it is stays as a daemon...?

PAM is a bit awful so I'm reluctant to let tmux touch it without a
really good reason.
Post by Ben Boeckel
Hi,
With systemd-logind, there will be the option to kill all user processes
on logout. I was wondering whether a patch to start a PAM session for
each tmux server would be accepted. It would be a compile-time option
and if wanted, options could also be added. Thanks.
--Ben
[1]http://0pointer.de/public/systemd-man/systemd-logind.conf.html
------------------------------------------------------------------------------
10 Tips for Better Web Security
Web security, SSL, hacker attacks & Denial of Service (DoS), private keys,
security Microsoft Exchange, secure Instant Messaging, and much more.
http://www.accelacomm.com/jaw/sfnl/114/51426210/
_______________________________________________
tmux-users mailing list
https://lists.sourceforge.net/lists/listinfo/tmux-users
Ben Boeckel
2011-07-22 03:16:50 UTC
Permalink
Post by Nicholas Marriott
Maybe. Can you give a bit more explanation? What is systemd-logind and
why does this option have anything to do with PAM? Why does it need PAM
to kill processes on logout?
If applications do nothing, they will be killed on logout. If, instead,
the application declares that it holds a session via PAM, it will be
left alone (my tests with Rawhide so far indicate that something isn't
quite right and isn't happening as setting it doesn't really do much).
Post by Nicholas Marriott
I'm not really clear on the use case either. It seems to me that if the
admin wants to kill all processes of a user on logout then tmux
shouldn't be an exception
I'll ask the systemd devs about this case.
Post by Nicholas Marriott
(or if it is, it should be in the program doing the killing and
configured by the admin, not in tmux).
It tracks PAM sessions. I'd imagine this is cleaner than keeping a list
of exemptions somewhere.
Post by Nicholas Marriott
Or if the user wants to kill processes, why can't they do what they do
now and tmux will keep running as normal since it is stays as a
daemon...?
systemd-logind puts a user's session into a cgroup and kills the
heirarchy when the user logs out. Without tmux declaring another
session, tmux is in the session that gets killed.
Post by Nicholas Marriott
PAM is a bit awful so I'm reluctant to let tmux touch it without a
really good reason.
The patch is attached (doesn't adversely affect things on F15, trying
out the Rawhide box when I get a chance). I'll ask the systemd devs if
the patch does what is needed.

--Ben
Nicholas Marriott
2011-07-22 03:38:37 UTC
Permalink
Post by Ben Boeckel
Post by Nicholas Marriott
Maybe. Can you give a bit more explanation? What is systemd-logind and
why does this option have anything to do with PAM? Why does it need PAM
to kill processes on logout?
If applications do nothing, they will be killed on logout. If, instead,
the application declares that it holds a session via PAM, it will be
left alone (my tests with Rawhide so far indicate that something isn't
quite right and isn't happening as setting it doesn't really do much).
Ok I see, but this really ties into my question below. Why this change?

Unix has always worked in the same way. If you logout then programs are
killed, unless they daemonize (which is pretty standard by now) in which
case they sit around until you kill them.

And sysadmins of course can kill your stuff whenever they like.

So, why is systemd different here?

It seems obvious - if users leave stuff running in the background they
should stay running, unless the admin has prevented it or kills
it. Seems pretty standard? I don't follow why this is different for
systemd.

I'm not wildly happy about adding more OS-specific code to tmux for
something it already does perfectly well everywhere (including Linux
right now).

If it has to be done differently then - glibc has the daemon() function,
and tmux uses it on Linux. Shouldn't this code be part of glibc instead
of tmux?
Post by Ben Boeckel
Post by Nicholas Marriott
I'm not really clear on the use case either. It seems to me that if the
admin wants to kill all processes of a user on logout then tmux
shouldn't be an exception
I'll ask the systemd devs about this case.
Post by Nicholas Marriott
(or if it is, it should be in the program doing the killing and
configured by the admin, not in tmux).
It tracks PAM sessions. I'd imagine this is cleaner than keeping a list
of exemptions somewhere.
If it has to be managed by the application then I don't agree. It is
cleaner to have a list managed by the admin than requiring code changes
to every application which is just a disaster.
Post by Ben Boeckel
Post by Nicholas Marriott
Or if the user wants to kill processes, why can't they do what they do
now and tmux will keep running as normal since it is stays as a
daemon...?
systemd-logind puts a user's session into a cgroup and kills the
heirarchy when the user logs out. Without tmux declaring another
session, tmux is in the session that gets killed.
That doesn't seem like tmux's problem, it seems like either the user or
the admin or systemd should configure tmux in a group it isn't going to
kill when tmux becomes a daemon? Like setsid?
Post by Ben Boeckel
Post by Nicholas Marriott
PAM is a bit awful so I'm reluctant to let tmux touch it without a
really good reason.
The patch is attached (doesn't adversely affect things on F15, trying
out the Rawhide box when I get a chance). I'll ask the systemd devs if
the patch does what is needed.
The bulk of this at least needs to be in osdep-linux.c.
Post by Ben Boeckel
--Ben
diff --git a/trunk/configure.ac b/trunk/configure.ac
index ba00a79..fce018b 100644
--- a/trunk/configure.ac
+++ b/trunk/configure.ac
@@ -56,6 +56,13 @@ AC_ARG_ENABLE(
)
AM_CONDITIONAL(IS_STATIC, test "x" = xyes)
+# PAM support?
+AC_ARG_ENABLE(
+ pam,
+ AC_HELP_STRING(--enable-pam, create a PAM session on server startup),
+ found_pam=$enable_pam
+)
+
# Is this gcc?
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
AC_MSG_CHECKING(for gcc that whines about -I)
@@ -121,6 +128,18 @@ if test "x$found_curses" = xno; then
AC_MSG_ERROR("curses not found")
fi
+if test "x$enable_pam" = xyes; then
+ # Look for libpam.
+ AC_SEARCH_LIBS(pam_start, [pam], found_pam=yes, found_pam=no)
+ # Look for libpam_misc.
+ AC_SEARCH_LIBS(misc_conv, [pam_misc], found_pam_misc=yes, found_pam_misc=no)
+ if test "x$found_pam" = xno || test "x$found_pam_misc" = xno; then
+ AC_MSG_ERROR("PAM not found")
+ else
+ AC_DEFINE(ENABLE_PAM)
+ fi
+fi
+
# Look for networking libraries.
AC_SEARCH_LIBS(b64_ntop, resolv)
AC_SEARCH_LIBS(__b64_ntop, resolv)
diff --git a/trunk/server.c b/trunk/server.c
index c442c66..4fc3b9d 100644
--- a/trunk/server.c
+++ b/trunk/server.c
@@ -16,6 +16,11 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifdef ENABLE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#endif
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -26,6 +31,9 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
+#ifdef ENABLE_PAM
+#include <pwd.h>
+#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -52,6 +60,11 @@ struct event server_ev_second;
struct paste_stack global_buffers;
+#ifdef ENABLE_PAM
+pam_handle_t *pam_handle;
+int pam_last_status;
+#endif
+
int server_create_socket(void);
void server_loop(void);
int server_should_shutdown(void);
@@ -65,6 +78,10 @@ void server_child_stopped(pid_t, int);
void server_second_callback(int, short, void *);
void server_lock_server(void);
void server_lock_sessions(void);
+#ifdef ENABLE_PAM
+void server_pam_init(void);
+void server_pam_teardown(void);
+#endif
/* Create server socket. */
int
@@ -152,6 +169,9 @@ server_start(void)
mode_key_init_trees();
key_bindings_init();
utf8_build();
+#ifdef ENABLE_PAM
+ server_pam_init();
+#endif
start_time = time(NULL);
log_debug("socket path %s", socket_path);
@@ -199,6 +219,9 @@ server_start(void)
set_signals(server_signal_callback);
server_loop();
+#ifdef ENABLE_PAM
+ server_pam_teardown();
+#endif
exit(0);
}
@@ -522,3 +545,63 @@ server_lock_sessions(void)
}
}
}
+
+#ifdef ENABLE_PAM
+/* Start a PAM session */
+void
+server_pam_init(void)
+{
+ struct passwd *passwd_struct;
+ struct pam_conv conv;
+
+ pam_handle = NULL;
+
+ passwd_struct = getpwuid(geteuid());
+
+ if (!passwd_struct) {
+ log_warnx("getpwuid error: %s", strerror(errno));
+ return;
+ }
+
+ conv.conv = misc_conv;
+ conv.appdata_ptr = NULL;
+
+ pam_last_status = pam_start("tmux", passwd_struct->pw_name, &conv, &pam_handle);
+
+ if (pam_last_status != PAM_SUCCESS) {
+ pam_handle = NULL;
+ log_warnx("pam_start error: %s", pam_strerror(pam_handle, pam_last_status));
+ return;
+ }
+
+ pam_last_status = pam_open_session(pam_handle, 0);
+
+ if (pam_last_status != PAM_SUCCESS) {
+ pam_handle = NULL;
+ log_warnx("pam_open_session error: %s", pam_strerror(pam_handle, pam_last_status));
+ return;
+ }
+}
+
+/* Teardown a PAM session */
+void
+server_pam_teardown(void)
+{
+ if (!pam_handle) {
+ return;
+ }
+
+ pam_last_status = pam_close_session(pam_handle, 0);
+
+ if (pam_last_status != PAM_SUCCESS) {
+ pam_handle = NULL;
+ log_warnx("pam_close_session error: %s", pam_strerror(pam_handle, pam_last_status));
+ return;
+ }
+ pam_last_status = pam_end(pam_handle, pam_last_status);
+
+ if (pam_last_status != PAM_SUCCESS) {
+ log_warnx("pam_end error: %s", pam_strerror(pam_handle, pam_last_status));
+ }
+}
+#endif
Loading...