From a33543dd9281563dbf12b04862c79e090d59086b Mon Sep 17 00:00:00 2001 From: jmallett Date: Thu, 2 Jan 2003 20:44:41 +0000 Subject: [PATCH] Implement POSIX grantpt(3) functionality, and add a pt_chown utility (akin to Solaris, it is in /usr/libexec) to perform the handing over of tty nodes to the user being granted the pty. Submitted by: Ryan Younce Reviewed by: security-officer@, standards@, mike@ --- include/stdlib.h | 8 +- lib/libc/stdlib/Makefile.inc | 15 +- lib/libc/stdlib/grantpt.3 | 224 ++++++++++++++++++++++++++++++ lib/libc/stdlib/grantpt.c | 259 +++++++++++++++++++++++++++++++++++ libexec/Makefile | 1 + libexec/pt_chown/Makefile | 9 ++ libexec/pt_chown/pt_chown.c | 103 ++++++++++++++ 7 files changed, 608 insertions(+), 11 deletions(-) create mode 100644 lib/libc/stdlib/grantpt.3 create mode 100644 lib/libc/stdlib/grantpt.c create mode 100644 libexec/pt_chown/Makefile create mode 100644 libexec/pt_chown/pt_chown.c diff --git a/include/stdlib.h b/include/stdlib.h index b8dddedb6f30..f7fd3a761dc5 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -184,7 +184,7 @@ double erand48(unsigned short[3]); int getsubopt(char **, char *const *, char **); #define _GETSUBOPT_DECLARED #endif -/* int grantpt(int); */ +int grantpt(int); char *initstate(unsigned long /* XSI requires u_int */, char *, long); long jrand48(unsigned short[3]); /* char *l64a(long); */ @@ -200,8 +200,8 @@ char *mktemp(char *); #endif long mrand48(void); long nrand48(unsigned short[3]); -/* int posix_openpt(int); */ -/* char *ptsname(int); */ +int posix_openpt(int); +char *ptsname(int); int putenv(const char *); long random(void); char *realpath(const char *, char resolved_path[]); @@ -214,7 +214,7 @@ int setkey(const char *); char *setstate(/* const */ char *); void srand48(long); void srandom(unsigned long); -/* int unlockpt(int); */ +int unlockpt(int); #endif /* __XSI_VISIBLE */ #if __BSD_VISIBLE diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index e38890861869..bc1030d5db9f 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -6,11 +6,11 @@ MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ bsearch.c calloc.c div.c exit.c getenv.c getopt.c getopt_long.c \ - getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c insque.c \ - labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c merge.c putenv.c \ - qsort.c qsort_r.c radixsort.c rand.c random.c reallocf.c realpath.c \ - remque.c setenv.c strfmon.c strhash.c strtod.c strtoimax.c strtol.c \ - strtoll.c strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c \ + getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \ + insque.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c merge.c \ + putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c reallocf.c \ + realpath.c remque.c setenv.c strfmon.c strhash.c strtod.c strtoimax.c \ + strtol.c strtoll.c strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c \ system.c tdelete.c tfind.c tsearch.c twalk.c # machine-dependent stdlib sources @@ -19,14 +19,15 @@ MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ .endif MAN+= abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \ - div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 hcreate.3 \ - imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \ + div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 grantpt.3 \ + hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \ lsearch.3 malloc.3 memory.3 qsort.3 radixsort.3 rand.3 random.3 \ realpath.3 strfmon.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3 MLINKS+=atol.3 atoll.3 MLINKS+=exit.3 _Exit.3 MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3 +MLINKS+=grantpt.3 posix_openpt.3 grantpt.3 ptsname.3 grantpt.3 unlockpt.3 MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3 MLINKS+=insque.3 remque.3 MLINKS+=lsearch.3 lfind.3 diff --git a/lib/libc/stdlib/grantpt.3 b/lib/libc/stdlib/grantpt.3 new file mode 100644 index 000000000000..2983c2dd68fd --- /dev/null +++ b/lib/libc/stdlib/grantpt.3 @@ -0,0 +1,224 @@ +.\" +.\" Copyright (c) 2002 The FreeBSD Project, Inc. +.\" All rights reserved. +.\" +.\" This software includes code contributed to the FreeBSD Project +.\" by Ryan Younce of North Carolina State University. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the FreeBSD Project nor the names of its +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +.\" PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT +.\" OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +.\" TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +.\" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 23, 2002 +.Os +.Dt GRANTPT 3 +.Sh NAME +.Nm grantpt , +.Nm ptsname , +.Nm unlockpt , +.Nm posix_openpt +.Nd pseudo-terminal access functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn grantpt "int fildes" +.Ft char * +.Fn ptsname "int fildes" +.Ft int +.Fn unlockpt "int fildes" +.In fcntl.h +.Ft int +.Fn posix_openpt "int mode" +.Sh DESCRIPTION +The +.Fn grantpt , +.Fn ptsname , +.Fn unlockpt , +and +.Fn posix_openpt +functions allow access to pseudo-terminal devices. +The first three functions accept a file descriptor +that references the master half of a pseudo-terminal pair. +This file descriptor is created with +.Fn posix_openpt . +.Pp +The +.Fn grantpt +function is used to establish ownership and permissions +of the slave device counterpart to the master device +specified with +.Va fildes . +The slave device's ownership is set to the real user ID +of the calling process, and the permissions are set to +user readable-writable and group writable. +The group owner of the slave device is also set to the +group "tty" if it exists on the system; otherwise, it +is left untouched. +.Pp +The +.Fn ptsname +function returns the full pathname of the slave device +counterpart to the master device specified with +.Va fildes . +This value can be used +to subsequently open the appropriate slave after +.Fn posix_openpt +and +.Fn grantpt +have been called. +.Pp +The +.Fn unlockpt +function clears the lock held on the pseudo-terminal pair +for the master device specified with +.Va fildes . +.Pp +The +.Fn posix_openpt +function opens the first available master pseudo-terminal +device and returns a descriptor to it. +.Va mode +specifies the flags used for opening the device: +.Bl -tag -width O_NOCTTY +.It Dv O_RDWR +Open for reading and writing. +.It Dv O_NOCTTY +If set, do not allow the terminal to become +the controlling terminal for the calling process. +.El +.Sh RETURN VALUES +The +.Fn grantpt +and +.Fn unlockpt +functions return 0 on success; otherwise -1 is returned and +.Va errno +is set to indicate the error. +.Pp +The +.Fn ptsname +function returns a pointer to the name +of the slave device on success; +otherwise a NULL pointer is returned and +.Va errno +is set to indicate the error. +.Pp +The +.Fn posix_openpt +function returns a file descriptor to the first +available master pseudo-terminal device on success; +otherwise -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn grantpt , +.Fn ptsname , +and +.Fn unlockpt +functions may fail and set +.Va errno +to: +.Bl -tag -width Er +.It EINVAL +.Va fildes +is not a master pseudo-terminal device. +.El +.Pp +In addition, the +.Fn grantpt +function may set +.Va errno +to: +.Bl -tag -width Er +.It EACCES +The slave pseudo-terminal device could not be accessed. +.El +.Pp +The +.Fn posix_openpt +function may fail and set +.Va errno +to: +.Bl -tag -width Er +.It EINVAL +.Va mode +consists an an invalid mode bit. +.It EAGAIN +The system has no available pseudo-terminal devices. +.El +.Pp +The +.Fn grantpt , +.Fn ptsname , +and +.Fn unlockpt +functions may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr fstat 2 . +.Pp +The +.Fn posix_openpt +function may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr open 2 . +.Sh SEE ALSO +.Xr open 2 , +.Xr pty 4 , +.Xr tty 4 +.Sh STANDARDS +The +.Fn grantpt , +.Fn ptsname , +.Fn unlockpt , +and +.Fn posix_openpt +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn grantpt , +.Fn ptsname , +.Fn unlockpt , +and +.Fn posix_openpt +functions appeared in +.Fx 5.0 . +.Sh NOTES +The purpose of the +.Fn unlockpt +function has no meaning in +.Fx . +.Pp +The flag +.Dv O_NOCTTY +is included for compatibility; in +.Fx , +opening a terminal does not cause it to become +a process's controlling terminal. diff --git a/lib/libc/stdlib/grantpt.c b/lib/libc/stdlib/grantpt.c new file mode 100644 index 000000000000..3e69f172d51e --- /dev/null +++ b/lib/libc/stdlib/grantpt.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2002 The FreeBSD Project, Inc. + * All rights reserved. + * + * This software includes code contributed to the FreeBSD Project + * by Ryan Younce of North Carolina State University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the FreeBSD Project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef lint +__FBSDID("$FreeBSD$"); +#endif /* not lint */ + +#include "namespace.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#define PTM_MAJOR 6 /* pseudo tty master major */ +#define PTS_MAJOR 5 /* pseudo tty slave major */ +#define PTM_PREFIX "pty" /* pseudo tty master naming convention */ +#define PTS_PREFIX "tty" /* pseudo tty slave naming convention */ + +/* + * The following are range values for pseudo TTY devices. Pseudo TTYs have a + * name of /dev/[pt]ty[p-sP-S][0-9a-v], yielding 256 combinations per major. + */ +#define PT_MAX 256 +#define PT_DEV1 "pqrsPQRS" +#define PT_DEV2 "0123456789abcdefghijklmnopqrstuv" + +/* + * grantpt(3) support utility. + */ +#define _PATH_PTCHOWN "/usr/libexec/pt_chown" + +/* + * ISPTM(x) returns 0 for struct stat x if x is not a pty master. + * The bounds checking may be unnecessary but it does eliminate doubt. + */ +#define ISPTM(x) (S_ISCHR((x).st_mode) && \ + major((x).st_rdev) == PTM_MAJOR && \ + minor((x).st_rdev) >= 0 && \ + minor((x).st_rdev) < PT_MAX) + +/* + * grantpt(): grant ownership of a slave pseudo-terminal device to the + * current user. + */ + +int +grantpt(int fildes) +{ + int retval, serrno, status; + pid_t pid, spid; + gid_t gid; + char *slave; + sigset_t oblock, nblock; + struct stat sbuf; + struct group *grp; + + retval = -1; + serrno = errno; + + if ((slave = ptsname(fildes)) != NULL) { + /* + * Block SIGCHLD. + */ + (void)sigemptyset(&nblock); + (void)sigaddset(&nblock, SIGCHLD); + (void)_sigprocmask(SIG_BLOCK, &nblock, &oblock); + + switch (pid = fork()) { + case -1: + break; + case 0: /* child */ + /* + * pt_chown expects the master pseudo TTY to be its + * standard input. + */ + (void)_dup2(fildes, STDIN_FILENO); + (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); + execl(_PATH_PTCHOWN, _PATH_PTCHOWN, (char *)NULL); + _exit(EX_UNAVAILABLE); + /* NOTREACHED */ + default: /* parent */ + /* + * Just wait for the process. Error checking is + * done below. + */ + while ((spid = _waitpid(pid, &status, 0)) == -1 && + (errno == EINTR)) + ; + if (spid != -1 && WIFEXITED(status) && + WEXITSTATUS(status) == EX_OK) + retval = 0; + else + errno = EACCES; + break; + } + + /* + * Restore process's signal mask. + */ + (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); + + if (retval) { + /* + * pt_chown failed. Try to manually change the + * permissions for the slave. + */ + gid = (grp = getgrnam("tty")) ? grp->gr_gid : -1; + if (chown(slave, getuid(), gid) == -1 || + chmod(slave, S_IRUSR | S_IWUSR | S_IWGRP) == -1) + errno = EACCES; + else + retval = 0; + } + } + + if (!retval) + errno = serrno; + + return (retval); +} + +/* + * posix_openpt(): open the first available master pseudo-terminal device + * and return descriptor. + */ +int +posix_openpt(int oflag) +{ + char *mc1, *mc2, master[] = _PATH_DEV PTM_PREFIX "XY"; + const char *pc1, *pc2; + int fildes, bflag, serrno; + + fildes = -1; + bflag = 0; + serrno = errno; + + /* + * Check flag validity. POSIX doesn't require it, + * but we still do so. + */ + if (oflag & ~(O_RDWR | O_NOCTTY)) + errno = EINVAL; + else { + mc1 = master + strlen(_PATH_DEV PTM_PREFIX); + mc2 = mc1 + 1; + + /* Cycle through all possible master PTY devices. */ + for (pc1 = PT_DEV1; !bflag && (*mc1 = *pc1); ++pc1) + for (pc2 = PT_DEV2; *mc2 = *pc2; ++pc2) { + /* + * Break out if we successfully open a PTY, + * or if open() fails due to limits. + */ + if ((fildes = _open(master, oflag)) != -1 || + (errno == EMFILE || errno == ENFILE)) { + ++bflag; + break; + } + } + + if (fildes != -1) + errno = serrno; + else if (!bflag) + errno = EAGAIN; + } + + return (fildes); +} + +/* + * ptsname(): return the pathname of the slave pseudo-terminal device + * associated with the specified master. + */ +char * +ptsname(int fildes) +{ + static char slave[] = _PATH_DEV PTS_PREFIX "XY"; + char *retval; + struct stat sbuf; + + retval = NULL; + + if (_fstat(fildes, &sbuf) == 0) { + if (!ISPTM(sbuf)) + errno = EINVAL; + else { + (void)sprintf(slave, _PATH_DEV PTS_PREFIX "%c%c", + PT_DEV1[minor(sbuf.st_rdev) / 32], + PT_DEV2[minor(sbuf.st_rdev) % 32]); + retval = slave; + } + } + + return (retval); +} + +/* + * unlockpt(): unlock a pseudo-terminal device pair. + */ +int +unlockpt(int fildes) +{ + int retval; + struct stat sbuf; + + /* + * Unlocking a master/slave pseudo-terminal pair has no meaning in a + * non-streams PTY environment. However, we do ensure fildes is a + * valid master pseudo-terminal device. + */ + if ((retval = _fstat(fildes, &sbuf)) == 0 && !ISPTM(sbuf)) { + errno = EINVAL; + retval = -1; + } + + return (retval); +} diff --git a/libexec/Makefile b/libexec/Makefile index 6b438a145abc..b10c3f5c897e 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -12,6 +12,7 @@ SUBDIR= atrun \ makekey \ mknetid \ pppoed \ + pt_chown \ rbootd \ revnetgroup \ rexecd \ diff --git a/libexec/pt_chown/Makefile b/libexec/pt_chown/Makefile new file mode 100644 index 000000000000..974a730f0374 --- /dev/null +++ b/libexec/pt_chown/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= pt_chown +SRCS= pt_chown.c +BINOWN= root +BINMODE=4555 +NOMAN= yes + +.include diff --git a/libexec/pt_chown/pt_chown.c b/libexec/pt_chown/pt_chown.c new file mode 100644 index 000000000000..d89ffeaba87e --- /dev/null +++ b/libexec/pt_chown/pt_chown.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002 The FreeBSD Project, Inc. + * All rights reserved. + * + * This software includes code contributed to the FreeBSD Project + * by Ryan Younce of North Carolina State University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the FreeBSD Project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef lint +__FBSDID("$FreeBSD$"); +#endif /* not lint */ + +#include + +#include +#include +#include +#include + +/* + * pt_chown + * Utility support routine for grantpt(3). + * + * According to IEEE Std 1003.1-2001, grantpt(3) changes ownership and + * permission bits of a slave pseudo-terminal device associated with a + * master. + * + * Since doing this if we are not the owner of the slave (which would + * rarely happen) cannot be done by conventional methods, grantpt(3) + * has to rely on this support program, which is setuid root, to change + * the slave's owner, group, and permission mode attributes. It's + * a rather undesirable approach, but Digital Unix and Solaris also seem + * to rely on this approach to pull this off. + * + * This program hangs around long enough to do just these things upon + * its standard input (which is set up by grantpt(3) to be the master's + * descriptor, the one passed to it). The rationale behind this + * approach not allowing somebody to modify ownership of another active + * pseudo terminal is: + * + * 1) This program only operates on its standard input. If STDIN_FILENO + * is not open or is not a pseudo-terminal master, no action is + * taken and the program exits (ptsname() is called for a non-NULL + * return). + * 2) Only one active file description for a pseudo-terminal master + * can exist at a time (attempting to open an active PTY returns with + * EIO - I/O Error). Thus, if the pseudo-terminal is already in + * use by somebody else, it could not have been opened to begin + * with, and thus this program would be useless in such situations. + */ +int +main(int argc, char *argv[]) +{ + int retcode; + char *slave; + gid_t gid; + struct group *grp; + + retcode = EX_OK; + + if ((slave = ptsname(STDIN_FILENO)) == NULL) + retcode = EX_USAGE; + else { + gid = (grp = getgrnam("tty")) ? grp->gr_gid : -1; + if (chown(slave, getuid(), gid) == 0 && + chmod(slave, S_IRUSR | S_IWUSR | S_IWGRP) == 0) + retcode = 0; + else + retcode = EX_NOPERM; + } + + /* + * grantpt(3) checks the retcode for being either zero or + * nonzero. Any nonzero return results in errno being set + * to EACCES. + */ + exit(retcode); +}