]>
Commit | Line | Data |
---|---|---|
9b3c7c3c | 1 | /* pt_chmod - helper program for `grantpt'. |
2b778ceb | 2 | Copyright (C) 1998-2021 Free Software Foundation, Inc. |
6591c335 | 3 | This file is part of the GNU C Library. |
6591c335 UD |
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 <argp.h> |
6591c335 | 20 | #include <errno.h> |
9b3c7c3c | 21 | #include <error.h> |
6591c335 | 22 | #include <grp.h> |
9b3c7c3c UD |
23 | #include <libintl.h> |
24 | #include <locale.h> | |
2028f49d | 25 | #include <signal.h> |
9b3c7c3c UD |
26 | #include <stdio.h> |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <sys/stat.h> | |
30 | #include <unistd.h> | |
f793b624 UD |
31 | #ifdef HAVE_LIBCAP |
32 | # include <sys/capability.h> | |
33 | # include <sys/prctl.h> | |
34 | #endif | |
9b3c7c3c UD |
35 | |
36 | #include "pty-private.h" | |
6591c335 | 37 | |
9b3c7c3c UD |
38 | /* Get libc version number. */ |
39 | #include "../version.h" | |
6591c335 | 40 | |
9b3c7c3c UD |
41 | #define PACKAGE _libc_intl_domainname |
42 | ||
43 | /* Name and version of program. */ | |
44 | static void print_version (FILE *stream, struct argp_state *state); | |
45 | void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; | |
46 | ||
47 | /* Function to print some extra text in the help message. */ | |
48 | static char *more_help (int key, const char *text, void *input); | |
49 | ||
50 | /* Data structure to communicate with argp functions. */ | |
51 | static struct argp argp = | |
6591c335 | 52 | { |
9b3c7c3c UD |
53 | NULL, NULL, NULL, NULL, NULL, more_help |
54 | }; | |
55 | ||
56 | ||
57 | /* Print the version information. */ | |
58 | static void | |
59 | print_version (FILE *stream, struct argp_state *state) | |
60 | { | |
8b748aed | 61 | fprintf (stream, "pt_chown %s%s\n", PKGVERSION, VERSION); |
9b3c7c3c UD |
62 | fprintf (stream, gettext ("\ |
63 | Copyright (C) %s Free Software Foundation, Inc.\n\ | |
64 | This is free software; see the source for copying conditions. There is NO\n\ | |
65 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ | |
9fcdec73 | 66 | "), "2021"); |
6591c335 UD |
67 | } |
68 | ||
9b3c7c3c UD |
69 | static char * |
70 | more_help (int key, const char *text, void *input) | |
6591c335 | 71 | { |
9b3c7c3c | 72 | char *cp; |
8b748aed | 73 | char *tp; |
00bc5db0 | 74 | |
9b3c7c3c UD |
75 | switch (key) |
76 | { | |
77 | case ARGP_KEY_HELP_PRE_DOC: | |
78 | asprintf (&cp, gettext ("\ | |
00bc5db0 UD |
79 | Set the owner, group and access permission of the slave pseudo\ |
80 | terminal corresponding to the master pseudo terminal passed on\ | |
81 | file descriptor `%d'. This is the helper program for the\ | |
82 | `grantpt' function. It is not intended to be run directly from\ | |
83 | the command line.\n"), | |
9b3c7c3c UD |
84 | PTY_FILENO); |
85 | return cp; | |
86 | case ARGP_KEY_HELP_EXTRA: | |
87 | /* We print some extra information. */ | |
8b748aed JM |
88 | if (asprintf (&tp, gettext ("\ |
89 | For bug reporting instructions, please see:\n\ | |
90 | %s.\n"), REPORT_BUGS_TO) < 0) | |
91 | return NULL; | |
92 | if (asprintf (&cp, gettext ("\ | |
9b3c7c3c UD |
93 | The owner is set to the current user, the group is set to `%s',\ |
94 | and the access permission is set to `%o'.\n\n\ | |
95 | %s"), | |
8b748aed JM |
96 | TTY_GROUP, S_IRUSR|S_IWUSR|S_IWGRP, tp) < 0) |
97 | { | |
98 | free (tp); | |
99 | return NULL; | |
100 | } | |
9b3c7c3c UD |
101 | return cp; |
102 | default: | |
103 | break; | |
104 | } | |
105 | return (char *) text; | |
6591c335 UD |
106 | } |
107 | ||
d54fb3b6 | 108 | static int |
71e5d196 | 109 | do_pt_chown (void) |
6591c335 | 110 | { |
6591c335 | 111 | char *pty; |
f793b624 | 112 | struct stat64 st; |
9b3c7c3c | 113 | struct group *p; |
6591c335 | 114 | gid_t gid; |
6591c335 | 115 | |
9b3c7c3c UD |
116 | /* Check that PTY_FILENO is a valid master pseudo terminal. */ |
117 | pty = ptsname (PTY_FILENO); | |
6591c335 UD |
118 | if (pty == NULL) |
119 | return errno == EBADF ? FAIL_EBADF : FAIL_EINVAL; | |
6591c335 | 120 | |
9b3c7c3c UD |
121 | /* Check that the returned slave pseudo terminal is a |
122 | character device. */ | |
f793b624 | 123 | if (stat64 (pty, &st) < 0 || !S_ISCHR (st.st_mode)) |
6591c335 UD |
124 | return FAIL_EINVAL; |
125 | ||
9b3c7c3c UD |
126 | /* Get the group ID of the special `tty' group. */ |
127 | p = getgrnam (TTY_GROUP); | |
128 | gid = p ? p->gr_gid : getgid (); | |
129 | ||
130 | /* Set the owner to the real user ID, and the group to that special | |
131 | group ID. */ | |
f3799213 | 132 | if (chown (pty, getuid (), gid) < 0) |
9b3c7c3c | 133 | return FAIL_EACCES; |
6591c335 | 134 | |
9b3c7c3c UD |
135 | /* Set the permission mode to readable and writable by the owner, |
136 | and writable by the group. */ | |
837dea7c UD |
137 | if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP) |
138 | && chmod (pty, S_IRUSR|S_IWUSR|S_IWGRP) < 0) | |
6591c335 UD |
139 | return FAIL_EACCES; |
140 | ||
71e5d196 UD |
141 | return 0; |
142 | } | |
143 | ||
144 | ||
145 | int | |
146 | main (int argc, char *argv[]) | |
147 | { | |
a0e0c6c5 | 148 | uid_t euid = geteuid (); |
f793b624 | 149 | uid_t uid = getuid (); |
71e5d196 | 150 | int remaining; |
2028f49d GT |
151 | sigset_t signalset; |
152 | ||
153 | /* Clear any signal mask from the parent process. */ | |
154 | sigemptyset (&signalset); | |
155 | sigprocmask (SIG_SETMASK, &signalset, NULL); | |
71e5d196 | 156 | |
a0e0c6c5 | 157 | if (argc == 1 && euid == 0) |
f793b624 UD |
158 | { |
159 | #ifdef HAVE_LIBCAP | |
160 | /* Drop privileges. */ | |
161 | if (uid != euid) | |
162 | { | |
163 | static const cap_value_t cap_list[] = | |
164 | { CAP_CHOWN, CAP_FOWNER }; | |
165 | # define ncap_list (sizeof (cap_list) / sizeof (cap_list[0])) | |
166 | cap_t caps = cap_init (); | |
167 | if (caps == NULL) | |
139ee080 | 168 | return FAIL_ENOMEM; |
f793b624 UD |
169 | |
170 | /* There is no reason why these should not work. */ | |
171 | cap_set_flag (caps, CAP_PERMITTED, ncap_list, cap_list, CAP_SET); | |
172 | cap_set_flag (caps, CAP_EFFECTIVE, ncap_list, cap_list, CAP_SET); | |
173 | ||
174 | int res = cap_set_proc (caps); | |
175 | ||
176 | cap_free (caps); | |
177 | ||
a1ffb40e | 178 | if (__glibc_unlikely (res != 0)) |
139ee080 | 179 | return FAIL_EXEC; |
f793b624 UD |
180 | } |
181 | #endif | |
182 | ||
183 | /* Normal invocation of this program is with no arguments and | |
184 | with privileges. */ | |
185 | return do_pt_chown (); | |
186 | } | |
71e5d196 UD |
187 | |
188 | /* We aren't going to be using privileges, so drop them right now. */ | |
f793b624 | 189 | setuid (uid); |
a0e0c6c5 | 190 | |
71e5d196 UD |
191 | /* Set locale via LC_ALL. */ |
192 | setlocale (LC_ALL, ""); | |
193 | ||
194 | /* Set the text message domain. */ | |
195 | textdomain (PACKAGE); | |
196 | ||
197 | /* parse and process arguments. */ | |
198 | argp_parse (&argp, argc, argv, 0, &remaining, NULL); | |
199 | ||
200 | if (remaining < argc) | |
201 | { | |
202 | /* We should not be called with any non-option parameters. */ | |
203 | error (0, 0, gettext ("too many arguments")); | |
204 | argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, | |
205 | program_invocation_short_name); | |
206 | return EXIT_FAILURE; | |
207 | } | |
208 | ||
209 | /* Check if we are properly installed. */ | |
a0e0c6c5 | 210 | if (euid != 0) |
71e5d196 UD |
211 | error (FAIL_EXEC, 0, gettext ("needs to be installed setuid `root'")); |
212 | ||
213 | return EXIT_SUCCESS; | |
6591c335 | 214 | } |