diff --git a/include/pty-session.h b/include/pty-session.h index 0c9ccc6f0..09eff43fd 100644 --- a/include/pty-session.h +++ b/include/pty-session.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -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); diff --git a/lib/pty-session.c b/lib/pty-session.c index f4bb0045a..8352f8c67 100644 --- a/lib/pty-session.c +++ b/lib/pty-session.c @@ -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) { diff --git a/login-utils/su-common.c b/login-utils/su-common.c index ca49429df..afd0ea8ad 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -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() */