1 /* Copyright (C) 1998-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
26 #include <sys/resource.h>
28 #include <sys/types.h>
32 #include "pty-private.h"
35 /* Return the result of ptsname_r in the buffer pointed to by PTS,
36 which should be of length BUF_LEN. If it is too long to fit in
37 this buffer, a sufficiently long buffer is allocated using malloc,
38 and returned in PTS. 0 is returned upon success, -1 otherwise. */
40 pts_name (int fd
, char **pts
, size_t buf_len
, struct stat64
*stp
)
51 rv
= __ptsname_internal (fd
, buf
, buf_len
, stp
);
55 /* ptsname_r returns with ENOTTY to indicate
56 a descriptor not referring to a pty master.
57 For this condition, grantpt must return EINVAL. */
59 errno
= rv
; /* Not necessarily set by __ptsname_r. */
63 if (memchr (buf
, '\0', buf_len
))
64 /* We succeeded and the returned name fit in the buffer. */
67 /* Try again with a longer buffer. */
68 buf_len
+= buf_len
; /* Double it */
71 /* No initial buffer; start out by mallocing one. */
72 buf_len
= 128; /* First time guess. */
75 /* We've already malloced another buffer at least once. */
76 new_buf
= (char *) realloc (buf
, buf_len
);
78 new_buf
= (char *) malloc (buf_len
);
89 *pts
= buf
; /* Return buffer to the user. */
91 free (buf
); /* Free what we malloced when returning an error. */
96 /* Change the ownership and access permission of the slave pseudo
97 terminal associated with the master pseudo terminal specified
111 if (__glibc_unlikely (pts_name (fd
, &buf
, sizeof (_buf
), &st
)))
113 int save_errno
= errno
;
115 /* Check, if the file descriptor is valid. pts_name returns the
116 wrong errno number, so we cannot use that. */
117 if (__libc_fcntl (fd
, F_GETFD
) == -1 && errno
== EBADF
)
120 /* If the filedescriptor is no TTY, grantpt has to set errno
122 if (save_errno
== ENOTTY
)
123 __set_errno (EINVAL
);
125 __set_errno (save_errno
);
130 /* Make sure that we own the device. */
131 uid_t uid
= __getuid ();
132 if (st
.st_uid
!= uid
)
134 if (__chown (buf
, uid
, st
.st_gid
) < 0)
138 static int tty_gid
= -1;
139 if (__glibc_unlikely (tty_gid
== -1))
143 size_t grbuflen
= __sysconf (_SC_GETGR_R_SIZE_MAX
);
146 /* Get the group ID of the special `tty' group. */
147 if (grbuflen
== (size_t) -1L)
148 /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX.
149 Try a moderate value. */
151 grtmpbuf
= (char *) __alloca (grbuflen
);
152 __getgrnam_r (TTY_GROUP
, &grbuf
, grtmpbuf
, grbuflen
, &p
);
156 gid_t gid
= tty_gid
== -1 ? __getgid () : tty_gid
;
159 /* Make sure the group of the device is that special group. */
160 if (st
.st_gid
!= gid
)
162 if (__chown (buf
, uid
, gid
) < 0)
166 /* Make sure the permission mode is set to readable and writable by
167 the owner, and writable by the group. */
168 mode_t mode
= S_IRUSR
|S_IWUSR
|S_IWGRP
;
170 /* When built without pt_chown, we have delegated the creation of the
171 pty node with the right group and permission mode to the kernel, and
172 non-root users are unlikely to be able to change it. Therefore let's
173 consider that POSIX enforcement is the responsibility of the whole
174 system and not only the GNU libc. Thus accept different group or
177 /* Make sure the permission is set to readable and writable by the
178 owner. For security reasons, make it writable by the group only
179 when originally writable and when the group of the device is that
181 mode_t mode
= S_IRUSR
|S_IWUSR
|
182 ((st
.st_gid
== gid
) ? (st
.st_mode
& S_IWGRP
) : 0);
185 if ((st
.st_mode
& ACCESSPERMS
) != mode
)
187 if (__chmod (buf
, mode
) < 0)
194 /* We have to use the helper program if it is available. */
198 pid_t pid
= __fork ();
203 /* Disable core dumps. */
204 struct rlimit rl
= { 0, 0 };
205 __setrlimit (RLIMIT_CORE
, &rl
);
207 /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */
208 if (fd
!= PTY_FILENO
)
209 if (__dup2 (fd
, PTY_FILENO
) < 0)
212 # ifdef CLOSE_ALL_FDS
216 execle (_PATH_PT_CHOWN
, __basename (_PATH_PT_CHOWN
), NULL
, NULL
);
223 if (__waitpid (pid
, &w
, 0) == -1)
226 __set_errno (ENOEXEC
);
228 switch (WEXITSTATUS (w
))
237 __set_errno (EINVAL
);
240 __set_errno (EACCES
);
243 __set_errno (ENOEXEC
);
246 __set_errno (ENOMEM
);
250 assert(! "grantpt: internal error: invalid exit code from pt_chown");