1 /* Copyright (C) 1998-2024 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/>. */
23 #include <scratch_buffer.h>
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 struct scratch_buffer sbuf
;
152 scratch_buffer_init (&sbuf
);
153 if (!scratch_buffer_set_array_size (&sbuf
, 1, grbuflen
))
158 grtmpbuf
= sbuf
.data
;
159 __getgrnam_r (TTY_GROUP
, &grbuf
, grtmpbuf
, grbuflen
, &p
);
163 scratch_buffer_free(&sbuf
);
165 gid_t gid
= tty_gid
== -1 ? __getgid () : tty_gid
;
168 /* Make sure the group of the device is that special group. */
169 if (st
.st_gid
!= gid
)
171 if (__chown (buf
, uid
, gid
) < 0)
175 /* Make sure the permission mode is set to readable and writable by
176 the owner, and writable by the group. */
177 mode_t mode
= S_IRUSR
|S_IWUSR
|S_IWGRP
;
179 /* When built without pt_chown, we have delegated the creation of the
180 pty node with the right group and permission mode to the kernel, and
181 non-root users are unlikely to be able to change it. Therefore let's
182 consider that POSIX enforcement is the responsibility of the whole
183 system and not only the GNU libc. Thus accept different group or
186 /* Make sure the permission is set to readable and writable by the
187 owner. For security reasons, make it writable by the group only
188 when originally writable and when the group of the device is that
190 mode_t mode
= S_IRUSR
|S_IWUSR
191 |((st
.st_gid
== gid
) ? (st
.st_mode
& S_IWGRP
) : 0);
194 if ((st
.st_mode
& ACCESSPERMS
) != mode
)
196 if (__chmod (buf
, mode
) < 0)
203 /* We have to use the helper program if it is available. */
207 pid_t pid
= __fork ();
212 /* Disable core dumps. */
213 struct rlimit rl
= { 0, 0 };
214 __setrlimit (RLIMIT_CORE
, &rl
);
216 /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */
217 if (fd
!= PTY_FILENO
)
218 if (__dup2 (fd
, PTY_FILENO
) < 0)
221 # ifdef CLOSE_ALL_FDS
225 execle (_PATH_PT_CHOWN
, __basename (_PATH_PT_CHOWN
), NULL
, NULL
);
232 if (__waitpid (pid
, &w
, 0) == -1)
235 __set_errno (ENOEXEC
);
237 switch (WEXITSTATUS (w
))
246 __set_errno (EINVAL
);
249 __set_errno (EACCES
);
252 __set_errno (ENOEXEC
);
255 __set_errno (ENOMEM
);
259 assert(! "grantpt: internal error: invalid exit code from pt_chown");
270 libc_hidden_def (grantpt
)