]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/grantpt.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / sysdeps / unix / grantpt.c
CommitLineData
04277e02 1/* Copyright (C) 1998-2019 Free Software Foundation, Inc.
6591c335
UD
2 This file is part of the GNU C Library.
3 Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
6591c335
UD
9
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
41bdb6e2 13 Lesser General Public License for more details.
6591c335 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
6591c335 18
9b3c7c3c 19#include <assert.h>
6591c335 20#include <errno.h>
3c877031 21#include <fcntl.h>
9b3c7c3c
UD
22#include <grp.h>
23#include <limits.h>
6591c335 24#include <stdlib.h>
9b3c7c3c 25#include <string.h>
6591c335
UD
26#include <sys/resource.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <sys/wait.h>
9b3c7c3c 30#include <unistd.h>
6591c335 31
9b3c7c3c
UD
32#include "pty-private.h"
33
34
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. */
39static int
aa989023 40pts_name (int fd, char **pts, size_t buf_len, struct stat64 *stp)
9b3c7c3c
UD
41{
42 int rv;
43 char *buf = *pts;
44
45 for (;;)
46 {
47 char *new_buf;
48
49 if (buf_len)
50 {
aa989023 51 rv = __ptsname_internal (fd, buf, buf_len, stp);
ffa8d2a0
RM
52 if (rv != 0)
53 {
54 if (rv == ENOTTY)
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. */
9db6ee8d
RM
58 rv = EINVAL;
59 errno = rv; /* Not necessarily set by __ptsname_r. */
ffa8d2a0
RM
60 break;
61 }
9b3c7c3c 62
ffa8d2a0
RM
63 if (memchr (buf, '\0', buf_len))
64 /* We succeeded and the returned name fit in the buffer. */
9b3c7c3c
UD
65 break;
66
67 /* Try again with a longer buffer. */
68 buf_len += buf_len; /* Double it */
69 }
70 else
71 /* No initial buffer; start out by mallocing one. */
72 buf_len = 128; /* First time guess. */
6591c335 73
9b3c7c3c
UD
74 if (buf != *pts)
75 /* We've already malloced another buffer at least once. */
9cddf9de 76 new_buf = (char *) realloc (buf, buf_len);
9b3c7c3c 77 else
9cddf9de 78 new_buf = (char *) malloc (buf_len);
9b3c7c3c
UD
79 if (! new_buf)
80 {
81 rv = -1;
82 __set_errno (ENOMEM);
83 break;
84 }
85 buf = new_buf;
86 }
6591c335 87
9b3c7c3c
UD
88 if (rv == 0)
89 *pts = buf; /* Return buffer to the user. */
90 else if (buf != *pts)
91 free (buf); /* Free what we malloced when returning an error. */
6591c335 92
9b3c7c3c
UD
93 return rv;
94}
6591c335 95
9b3c7c3c
UD
96/* Change the ownership and access permission of the slave pseudo
97 terminal associated with the master pseudo terminal specified
98 by FD. */
6591c335 99int
9b3c7c3c 100grantpt (int fd)
6591c335 101{
00bc5db0 102 int retval = -1;
9b3c7c3c
UD
103#ifdef PATH_MAX
104 char _buf[PATH_MAX];
105#else
106 char _buf[512];
107#endif
108 char *buf = _buf;
aa989023 109 struct stat64 st;
9b3c7c3c 110
a1ffb40e 111 if (__glibc_unlikely (pts_name (fd, &buf, sizeof (_buf), &st)))
b34de9ea
UD
112 {
113 int save_errno = errno;
114
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)
118 return -1;
119
120 /* If the filedescriptor is no TTY, grantpt has to set errno
21f2c223 121 to EINVAL. */
b34de9ea 122 if (save_errno == ENOTTY)
21f2c223 123 __set_errno (EINVAL);
b34de9ea
UD
124 else
125 __set_errno (save_errno);
126
127 return -1;
128 }
00bc5db0 129
9b3c7c3c 130 /* Make sure that we own the device. */
21f2c223 131 uid_t uid = __getuid ();
9b3c7c3c
UD
132 if (st.st_uid != uid)
133 {
37ba7d66 134 if (__chown (buf, uid, st.st_gid) < 0)
9b3c7c3c
UD
135 goto helper;
136 }
137
21f2c223 138 static int tty_gid = -1;
a1ffb40e 139 if (__glibc_unlikely (tty_gid == -1))
21f2c223
UD
140 {
141 char *grtmpbuf;
142 struct group grbuf;
143 size_t grbuflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
144 struct group *p;
145
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. */
150 grbuflen = 1024;
151 grtmpbuf = (char *) __alloca (grbuflen);
152 __getgrnam_r (TTY_GROUP, &grbuf, grtmpbuf, grbuflen, &p);
153 if (p != NULL)
154 tty_gid = p->gr_gid;
155 }
156 gid_t gid = tty_gid == -1 ? __getgid () : tty_gid;
9b3c7c3c 157
77356912 158#if HAVE_PT_CHOWN
9b3c7c3c
UD
159 /* Make sure the group of the device is that special group. */
160 if (st.st_gid != gid)
161 {
37ba7d66 162 if (__chown (buf, uid, gid) < 0)
9b3c7c3c
UD
163 goto helper;
164 }
165
166 /* Make sure the permission mode is set to readable and writable by
167 the owner, and writable by the group. */
77356912
AJ
168 mode_t mode = S_IRUSR|S_IWUSR|S_IWGRP;
169#else
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
175 permission mode. */
176
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
180 special group. */
a04549c1
JM
181 mode_t mode = S_IRUSR|S_IWUSR
182 |((st.st_gid == gid) ? (st.st_mode & S_IWGRP) : 0);
77356912
AJ
183#endif
184
185 if ((st.st_mode & ACCESSPERMS) != mode)
9b3c7c3c 186 {
77356912 187 if (__chmod (buf, mode) < 0)
9b3c7c3c
UD
188 goto helper;
189 }
190
00bc5db0
UD
191 retval = 0;
192 goto cleanup;
6591c335 193
e4608715 194 /* We have to use the helper program if it is available. */
21f2c223 195 helper:;
6591c335 196
73ba67cb 197#if HAVE_PT_CHOWN
21f2c223 198 pid_t pid = __fork ();
6591c335 199 if (pid == -1)
00bc5db0 200 goto cleanup;
6591c335
UD
201 else if (pid == 0)
202 {
9b3c7c3c
UD
203 /* Disable core dumps. */
204 struct rlimit rl = { 0, 0 };
4aebaa6b 205 __setrlimit (RLIMIT_CORE, &rl);
6591c335 206
9cddf9de 207 /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */
9b3c7c3c
UD
208 if (fd != PTY_FILENO)
209 if (__dup2 (fd, PTY_FILENO) < 0)
6591c335
UD
210 _exit (FAIL_EBADF);
211
e4608715 212# ifdef CLOSE_ALL_FDS
139ee080 213 CLOSE_ALL_FDS ();
e4608715 214# endif
139ee080 215
3b51c390 216 execle (_PATH_PT_CHOWN, __basename (_PATH_PT_CHOWN), NULL, NULL);
6591c335
UD
217 _exit (FAIL_EXEC);
218 }
219 else
220 {
9b3c7c3c 221 int w;
00bc5db0 222
50304ef0 223 if (__waitpid (pid, &w, 0) == -1)
00bc5db0 224 goto cleanup;
6591c335 225 if (!WIFEXITED (w))
00bc5db0 226 __set_errno (ENOEXEC);
6591c335 227 else
f793b624 228 switch (WEXITSTATUS (w))
6591c335
UD
229 {
230 case 0:
00bc5db0 231 retval = 0;
6591c335
UD
232 break;
233 case FAIL_EBADF:
234 __set_errno (EBADF);
00bc5db0 235 break;
6591c335
UD
236 case FAIL_EINVAL:
237 __set_errno (EINVAL);
00bc5db0 238 break;
6591c335
UD
239 case FAIL_EACCES:
240 __set_errno (EACCES);
00bc5db0 241 break;
6591c335
UD
242 case FAIL_EXEC:
243 __set_errno (ENOEXEC);
00bc5db0 244 break;
f793b624
UD
245 case FAIL_ENOMEM:
246 __set_errno (ENOMEM);
247 break;
6591c335
UD
248
249 default:
01eb16fd 250 assert(! "grantpt: internal error: invalid exit code from pt_chown");
6591c335
UD
251 }
252 }
e4608715 253#endif
6591c335 254
00bc5db0
UD
255 cleanup:
256 if (buf != _buf)
257 free (buf);
258
259 return retval;
6591c335 260}