1 /* Copyright (C) 1998-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
25 #include <sys/resource.h>
27 #include <sys/types.h>
31 #include "pty-private.h"
34 /* Return the result of ptsname_r in the buffer pointed to by PTS,
35 which should be of length BUF_LEN. If it is too long to fit in
36 this buffer, a sufficiently long buffer is allocated using malloc,
37 and returned in PTS. 0 is returned upon success, -1 otherwise. */
39 pts_name (int fd
, char **pts
, size_t buf_len
, struct stat64
*stp
)
50 rv
= __ptsname_internal (fd
, buf
, buf_len
, stp
);
54 /* ptsname_r returns with ENOTTY to indicate
55 a descriptor not referring to a pty master.
56 For this condition, grantpt must return EINVAL. */
58 errno
= rv
; /* Not necessarily set by __ptsname_r. */
62 if (memchr (buf
, '\0', buf_len
))
63 /* We succeeded and the returned name fit in the buffer. */
66 /* Try again with a longer buffer. */
67 buf_len
+= buf_len
; /* Double it */
70 /* No initial buffer; start out by mallocing one. */
71 buf_len
= 128; /* First time guess. */
74 /* We've already malloced another buffer at least once. */
75 new_buf
= (char *) realloc (buf
, buf_len
);
77 new_buf
= (char *) malloc (buf_len
);
88 *pts
= buf
; /* Return buffer to the user. */
90 free (buf
); /* Free what we malloced when returning an error. */
95 /* Change the ownership and access permission of the slave pseudo
96 terminal associated with the master pseudo terminal specified
110 if (__glibc_unlikely (pts_name (fd
, &buf
, sizeof (_buf
), &st
)))
112 int save_errno
= errno
;
114 /* Check, if the file descriptor is valid. pts_name returns the
115 wrong errno number, so we cannot use that. */
116 if (__libc_fcntl (fd
, F_GETFD
) == -1 && errno
== EBADF
)
119 /* If the filedescriptor is no TTY, grantpt has to set errno
121 if (save_errno
== ENOTTY
)
122 __set_errno (EINVAL
);
124 __set_errno (save_errno
);
129 /* Make sure that we own the device. */
130 uid_t uid
= __getuid ();
131 if (st
.st_uid
!= uid
)
133 if (__chown (buf
, uid
, st
.st_gid
) < 0)
137 static int tty_gid
= -1;
138 if (__glibc_unlikely (tty_gid
== -1))
142 size_t grbuflen
= __sysconf (_SC_GETGR_R_SIZE_MAX
);
145 /* Get the group ID of the special `tty' group. */
146 if (grbuflen
== (size_t) -1L)
147 /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX.
148 Try a moderate value. */
150 grtmpbuf
= (char *) __alloca (grbuflen
);
151 __getgrnam_r (TTY_GROUP
, &grbuf
, grtmpbuf
, grbuflen
, &p
);
155 gid_t gid
= tty_gid
== -1 ? __getgid () : tty_gid
;
158 /* Make sure the group of the device is that special group. */
159 if (st
.st_gid
!= gid
)
161 if (__chown (buf
, uid
, gid
) < 0)
165 /* Make sure the permission mode is set to readable and writable by
166 the owner, and writable by the group. */
167 mode_t mode
= S_IRUSR
|S_IWUSR
|S_IWGRP
;
169 /* When built without pt_chown, we have delegated the creation of the
170 pty node with the right group and permission mode to the kernel, and
171 non-root users are unlikely to be able to change it. Therefore let's
172 consider that POSIX enforcement is the responsibility of the whole
173 system and not only the GNU libc. Thus accept different group or
176 /* Make sure the permission is set to readable and writable by the
177 owner. For security reasons, make it writable by the group only
178 when originally writable and when the group of the device is that
180 mode_t mode
= S_IRUSR
|S_IWUSR
181 |((st
.st_gid
== gid
) ? (st
.st_mode
& S_IWGRP
) : 0);
184 if ((st
.st_mode
& ACCESSPERMS
) != mode
)
186 if (__chmod (buf
, mode
) < 0)
193 /* We have to use the helper program if it is available. */
197 pid_t pid
= __fork ();
202 /* Disable core dumps. */
203 struct rlimit rl
= { 0, 0 };
204 __setrlimit (RLIMIT_CORE
, &rl
);
206 /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */
207 if (fd
!= PTY_FILENO
)
208 if (__dup2 (fd
, PTY_FILENO
) < 0)
211 # ifdef CLOSE_ALL_FDS
215 execle (_PATH_PT_CHOWN
, __basename (_PATH_PT_CHOWN
), NULL
, NULL
);
222 if (__waitpid (pid
, &w
, 0) == -1)
225 __set_errno (ENOEXEC
);
227 switch (WEXITSTATUS (w
))
236 __set_errno (EINVAL
);
239 __set_errno (EACCES
);
242 __set_errno (ENOEXEC
);
245 __set_errno (ENOMEM
);
249 assert(! "grantpt: internal error: invalid exit code from pt_chown");
260 libc_hidden_def (grantpt
)