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