Add getptmfd(), fdopenpty(), fdforkpty() functions. These allow programs
authornicm <nicm@openbsd.org>
Thu, 20 Apr 2017 17:48:30 +0000 (17:48 +0000)
committernicm <nicm@openbsd.org>
Thu, 20 Apr 2017 17:48:30 +0000 (17:48 +0000)
to separate the open(/dev/ptm) from the ioctl(PTMGET) for privilege
separation or pledge().

Based on a diff from reyk@.

ok deraadt millert

lib/libutil/openpty.3
lib/libutil/pty.c
lib/libutil/shlib_version
lib/libutil/util.h

index a49e533..3d89cbc 100644 (file)
@@ -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
 .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 ,
index 2a19de8..c796acb 100644 (file)
@@ -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
 
 #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:
index eb2c603..7b5f7ac 100644 (file)
@@ -1,2 +1,2 @@
 major=12
-minor=1
+minor=2
index 469e003..15bf32d 100644 (file)
@@ -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);