]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
su: (pty) change owner and mode for pty
authorKarel Zak <kzak@redhat.com>
Tue, 23 Feb 2021 10:52:45 +0000 (11:52 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 23 Feb 2021 10:52:45 +0000 (11:52 +0100)
The current situation:

 # su --pty - kzak
 $ ll $(tty)
 crw--w---- 1 root tty 136, 9 Feb 23 11:53 /dev/pts/9
 $ mesg
 mesg: cannot open /dev/pts/9: Permission denied

the pseudo-terminal is still owned by the original user.

New version:

 # su --pty - kzak
 # ll $(tty)
 crw--w---- 1 kzak tty 136, 9 Feb 23 11:56 /dev/pts/9
 # mesg
 is y

The patch follows login(1) to change the pty owner and group. It
follows "TTYPERM" and "TTYGROUP" from login.defs (or econf lib).

Signed-off-by: Karel Zak <kzak@redhat.com>
include/pty-session.h
lib/pty-session.c
login-utils/su-common.c

index 0c9ccc6f012bbad2e48fef28e7f3f4498d1792d0..09eff43fdb352bd0b79af6287ec040d0b0fa2375 100644 (file)
@@ -10,6 +10,7 @@
 #include <termios.h>
 #include <signal.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 
 #include <sys/signalfd.h>
 
@@ -98,6 +99,7 @@ struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty);
 int ul_pty_is_running(struct ul_pty *pty);
 int ul_pty_setup(struct ul_pty *pty);
 void ul_pty_cleanup(struct ul_pty *pty);
+int ul_pty_chownmod_slave(struct ul_pty *pty, uid_t uid, gid_t gid, mode_t mode);
 void ul_pty_init_slave(struct ul_pty *pty);
 int ul_pty_proxy_master(struct ul_pty *pty);
 
index f4bb0045a225521879999130216437b075670890..8352f8c677837c21ae4aed7e240c8e726cca404c 100644 (file)
@@ -239,6 +239,15 @@ void ul_pty_cleanup(struct ul_pty *pty)
        tcsetattr(STDIN_FILENO, TCSADRAIN, &rtt);
 }
 
+int ul_pty_chownmod_slave(struct ul_pty *pty, uid_t uid, gid_t gid, mode_t mode)
+{
+       if (fchown(pty->slave, uid, gid))
+               return -errno;
+       if (fchmod(pty->slave, mode))
+               return -errno;
+       return 0;
+}
+
 /* call me in child process */
 void ul_pty_init_slave(struct ul_pty *pty)
 {
index ca49429df2983d175154605aeefd2b4e428b2dc7..afd0ea8ad5f05fc9a190e56fc78cc4e8c4343dcd 100644 (file)
@@ -82,7 +82,6 @@ UL_DEBUG_DEFINE_MASKNAMES(su) = UL_DEBUG_EMPTY_MASKNAMES;
 #define DBG(m, x)       __UL_DBG(su, SU_DEBUG_, m, x)
 #define ON_DBG(m, x)    __UL_DBG_CALL(su, SU_DEBUG_, m, x)
 
-
 /* name of the pam configuration files. separate configs for su and su -  */
 #define PAM_SRVNAME_SU "su"
 #define PAM_SRVNAME_SU_L "su-l"
@@ -255,6 +254,26 @@ static void wait_for_child_cb(
 {
        wait_for_child((struct su_context *) data);
 }
+
+static void chownmod_pty(struct su_context *su)
+{
+       gid_t gid = su->pwd->pw_gid;
+       mode_t mode = (mode_t) getlogindefs_num("TTYPERM", TTY_MODE);
+       const char *grname = getlogindefs_str("TTYGROUP", TTYGRPNAME);
+
+       if (grname && *grname) {
+               struct group *gr = getgrnam(grname);
+               if (gr) /* group by name */
+                       gid = gr->gr_gid;
+               else    /* group by ID */
+                       gid = (gid_t) getlogindefs_num("TTYGROUP", gid);
+       }
+
+       if (ul_pty_chownmod_slave(su->pty,
+                                 su->pwd->pw_uid,
+                                 gid, mode))
+               warn(_("change owner or mode for pseudo-terminal failed"));
+}
 #endif
 
 /* Log the fact that someone has run su to the user given by PW;
@@ -496,7 +515,6 @@ static void parent_setup_signals(struct su_context *su)
        }
 }
 
-
 static void create_watching_parent(struct su_context *su)
 {
        int status;
@@ -1191,6 +1209,10 @@ int su_main(int argc, char **argv, int mode)
        create_watching_parent(su);
        /* Now we're in the child.  */
 
+#ifdef USE_PTY
+       if (su->force_pty)
+               chownmod_pty(su);
+#endif
        change_identity(su->pwd);
        if (!su->same_session) {
                /* note that on --pty we call setsid() in ul_pty_init_slave() */