From cddf1b0fbc9c394633fbbe287ccdd33d66798d5e Mon Sep 17 00:00:00 2001 From: nicm <> Date: Thu, 20 Apr 2017 17:48:30 +0000 Subject: [PATCH] Add getptmfd(), fdopenpty(), fdforkpty() functions. These allow programs to separate the open(/dev/ptm) from the ioctl(PTMGET) for privilege separation or pledge(). Based on a diff from reyk@. ok deraadt millert --- src/lib/libutil/openpty.3 | 53 +++++++++++++++++++++++++++++----- src/lib/libutil/pty.c | 54 ++++++++++++++++++++++++++++------- src/lib/libutil/shlib_version | 2 +- src/lib/libutil/util.h | 6 +++- 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/lib/libutil/openpty.3 b/src/lib/libutil/openpty.3 index a49e533a..3d89cbc5 100644 --- a/src/lib/libutil/openpty.3 +++ b/src/lib/libutil/openpty.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: openpty.3,v 1.17 2015/08/28 19:54:06 kettenis Exp $ +.\" $OpenBSD: openpty.3,v 1.18 2017/04/20 17:48:30 nicm Exp $ .\" Copyright (c) 1995 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,7 +30,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: August 28 2015 $ +.Dd $Mdocdate: April 20 2017 $ .Dt OPENPTY 3 .Os .Sh NAME @@ -42,11 +42,17 @@ .In termios.h .In util.h .Ft int +.Fn getptmfd "void" +.Ft int .Fn openpty "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp" .Ft int +.Fn fdopenpty "int ptmfd" "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp" +.Ft int .Fn login_tty "int fd" .Ft pid_t .Fn forkpty "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp" +.Ft pid_t +.Fn fdforkpty "int ptmfd" "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp" .Sh DESCRIPTION The .Fn openpty , @@ -90,6 +96,22 @@ uses of that device are revoked (see for details). .Pp The +.Fn fdopenpty +and +.Fn fdforkpty +functions work like +.Fn openpty +and +.Fn forkpty +but expect a +.Pa /dev/ptm +file descriptor +.Fa ptmfd +obtained from the +.Fn getptmfd +function. +.Pp +The .Fn login_tty function prepares for a login on the tty .Fa fd @@ -151,25 +173,42 @@ slave pseudo terminals pseudo terminal management device .El .Sh ERRORS +.Fn getptmfd +may fail and set +.Va errno +for any of the errors specified for the routine +.Xr open 2 . +.Pp .Fn openpty +and +.Fn fdopenpty will fail if: .Bl -tag -width Er .It Bq Er ENOENT There are no available ttys. .El .Pp -.Fn login_tty +.Fn fdopenpty +and +.Fn fdforkpty will fail if -.Fn ioctl -fails to set -.Fa fd -to the controlling terminal of the current process. +.Fn getptmfd +fails. .Fn forkpty +and +.Fn fdforkpty will fail if either .Fn openpty or .Fn fork fails. +.Pp +.Fn login_tty +will fail if +.Fn ioctl +fails to set +.Fa fd +to the controlling terminal of the current process. .Sh SEE ALSO .Xr fork 2 , .Xr revoke 2 , diff --git a/src/lib/libutil/pty.c b/src/lib/libutil/pty.c index 2a19de81..c796acb5 100644 --- a/src/lib/libutil/pty.c +++ b/src/lib/libutil/pty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pty.c,v 1.20 2016/08/30 14:44:45 guenther Exp $ */ +/* $OpenBSD: pty.c,v 1.21 2017/04/20 17:48:30 nicm Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -43,25 +43,42 @@ #include "util.h" +int +getptmfd(void) +{ + return (open(PATH_PTMDEV, O_RDWR|O_CLOEXEC)); +} + int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { - int master, slave, fd; + int ptmfd; + + if ((ptmfd = getptmfd()) == -1) + return (-1); + if (fdopenpty(ptmfd, amaster, aslave, name, termp, winp) == -1) { + close(ptmfd); + return (-1); + } + close(ptmfd); + return (0); +} + +int +fdopenpty(int ptmfd, int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + int master, slave; struct ptmget ptm; /* * Use /dev/ptm and the PTMGET ioctl to get a properly set up and * owned pty/tty pair. */ - fd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC); - if (fd == -1) + if (ioctl(ptmfd, PTMGET, &ptm) == -1) return (-1); - if ((ioctl(fd, PTMGET, &ptm) == -1)) { - close(fd); - return (-1); - } - close(fd); + master = ptm.cfd; slave = ptm.sfd; if (name) { @@ -81,11 +98,28 @@ openpty(int *amaster, int *aslave, char *name, struct termios *termp, pid_t forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp) +{ + int ptmfd; + pid_t pid; + + if ((ptmfd = getptmfd()) == -1) + return (-1); + if ((pid = fdforkpty(ptmfd, amaster, name, termp, winp)) == -1) { + close(ptmfd); + return (-1); + } + close(ptmfd); + return (pid); +} + +pid_t +fdforkpty(int ptmfd, int *amaster, char *name, struct termios *termp, + struct winsize *winp) { int master, slave; pid_t pid; - if (openpty(&master, &slave, name, termp, winp) == -1) + if (fdopenpty(ptmfd, &master, &slave, name, termp, winp) == -1) return (-1); switch (pid = fork()) { case -1: diff --git a/src/lib/libutil/shlib_version b/src/lib/libutil/shlib_version index eb2c603a..7b5f7ac5 100644 --- a/src/lib/libutil/shlib_version +++ b/src/lib/libutil/shlib_version @@ -1,2 +1,2 @@ major=12 -minor=1 +minor=2 diff --git a/src/lib/libutil/util.h b/src/lib/libutil/util.h index 469e003d..15bf32db 100644 --- a/src/lib/libutil/util.h +++ b/src/lib/libutil/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.34 2013/06/03 21:07:02 tedu Exp $ */ +/* $OpenBSD: util.h,v 1.35 2017/04/20 17:48:30 nicm Exp $ */ /* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */ /*- @@ -98,9 +98,13 @@ void pw_prompt(void); void pw_copy(int, int, const struct passwd *, const struct passwd *); int pw_scan(char *, struct passwd *, int *); void pw_error(const char *, int, int); +int getptmfd(void); int openpty(int *, int *, char *, struct termios *, struct winsize *); +int fdopenpty(int, int *, int *, char *, struct termios *, + struct winsize *); int opendisk(const char *, int, char *, size_t, int); pid_t forkpty(int *, char *, struct termios *, struct winsize *); +pid_t fdforkpty(int, int *, char *, struct termios *, struct winsize *); int getmaxpartitions(void); int getrawpartition(void); void login_fbtab(const char *, uid_t, gid_t);