]> git.pld-linux.org Git - projects/rc-scripts.git/blame - src/usernetctl.c
netfs: respect VSERVER_ISOLATION_NET here as well
[projects/rc-scripts.git] / src / usernetctl.c
CommitLineData
00196ec7
AM
1/*
2 * Copyright (c) 1997-2003 Red Hat, Inc. All rights reserved.
3 *
4 * This software may be freely redistributed under the terms of the GNU
5 * public license.
6 *
7 * You should have received a copy of the GNU General Public License
8 * along with this program; if not, write to the Free Software
9 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
10 *
11 */
12
7742e157
AF
13#include <alloca.h>
14#include <ctype.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/stat.h>
21#include <unistd.h>
00196ec7 22#include <limits.h>
7742e157 23
de1fc6ce 24/* This will be running setuid root, so be careful! */
52471a31 25static const char * safeEnviron[] = {
7742e157
AF
26 "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
27 "HOME=/root",
28 NULL
29};
30
31#define FOUND_FALSE -1
32#define NOT_FOUND 0
33#define FOUND_TRUE 1
34
e9aec22c
AM
35#ifndef SBINDIR
36#define SBINDIR "/sbin"
37#endif
38
de1fc6ce
JR
39static void
40usage(void) {
41 fprintf(stderr, "usage: usernetctl <interface-config> <up|down|report>\n");
42 exit(1);
43}
7742e157 44
de1fc6ce 45static size_t
52471a31 46testSafe(char *ifaceConfig, int fd) {
7742e157
AF
47 struct stat sb;
48
de1fc6ce 49 /* These shouldn't be symbolic links -- anal, but that's fine w/ mkj. */
52471a31 50 if (fstat(fd, &sb)) {
7742e157
AF
51 fprintf(stderr, "failed to stat %s: %s\n", ifaceConfig,
52 strerror(errno));
53 exit(1);
54 }
55
de1fc6ce 56 /* Safety/sanity checks. */
7742e157
AF
57 if (!S_ISREG(sb.st_mode)) {
58 fprintf(stderr, "%s is not a normal file\n", ifaceConfig);
59 exit(1);
60 }
61
62 if (sb.st_uid) {
63 fprintf(stderr, "%s should be owned by root\n", ifaceConfig);
64 exit(1);
65 }
66
67 if (sb.st_mode & S_IWOTH) {
68 fprintf(stderr, "%s should not be world writeable\n", ifaceConfig);
69 exit(1);
70 }
71
72 return sb.st_size;
73}
74
75
de1fc6ce
JR
76static int
77userCtl(char *file) {
00196ec7 78 char *buf;
de1fc6ce
JR
79 char *contents = NULL;
80 char *chptr = NULL;
81 char *next = NULL;
82 int fd = -1, retval = NOT_FOUND;
83 size_t size = 0;
7742e157 84
52471a31
AM
85 /* Open the file and then test it to see if we like it. This way
86 we avoid switcheroo attacks. */
de1fc6ce 87 if ((fd = open(file, O_RDONLY)) == -1) {
7742e157
AF
88 fprintf(stderr, "failed to open %s: %s\n", file, strerror(errno));
89 exit(1);
90 }
91
52471a31
AM
92 size = testSafe(file, fd);
93 if (size > INT_MAX) {
94 fprintf(stderr, "file %s is too big\n", file);
95 exit(1);
96 }
97
98 buf = contents = malloc(size + 2);
99 if (contents == NULL) {
100 fprintf(stderr, "failed to allocate memory\n");
101 exit(1);
102 }
103
7742e157
AF
104 if (read(fd, contents, size) != size) {
105 perror("error reading device configuration");
106 exit(1);
107 }
108 close(fd);
109
110 contents[size] = '\n';
111 contents[size + 1] = '\0';
112
de1fc6ce
JR
113 /* Each pass parses a single line (until an answer is found), The contents
114 pointer itself points to the beginning of the current line. */
7742e157
AF
115 while (*contents) {
116 chptr = contents;
117 while (*chptr != '\n') chptr++;
de1fc6ce 118 next = chptr + 1;
12de71be 119 while (chptr >= contents && isspace(*chptr)) chptr--;
7742e157
AF
120 *(++chptr) = '\0';
121
52471a31 122 if (!strncasecmp(contents, "USERCTL=", 8)) {
12de71be 123 contents += 8;
00196ec7
AM
124 if ((contents[0] == '"' &&
125 contents[strlen(contents) - 1] == '"') ||
126 (contents[0] == '\'' &&
127 contents[strlen(contents) - 1] == '\''))
128 {
12de71be 129 contents++;
130 contents[strlen(contents) - 1] = '\0';
131 }
132
52471a31 133 if (!strcasecmp(contents, "yes") || !strcasecmp(contents, "true"))
de1fc6ce 134 retval = FOUND_TRUE;
12de71be 135 else
de1fc6ce
JR
136 retval = FOUND_FALSE;
137
138 break;
7742e157
AF
139 }
140
de1fc6ce 141 contents = next;
7742e157
AF
142 }
143
00196ec7 144 free(buf);
7742e157 145
de1fc6ce
JR
146 return retval;
147}
7742e157 148
de1fc6ce
JR
149int
150main(int argc, char ** argv) {
7742e157
AF
151 char * ifaceConfig;
152 char * chptr;
00196ec7 153 char * cmd = NULL;
7742e157
AF
154 int report = 0;
155 char tmp;
156
157 if (argc != 3) usage();
158
159 if (!strcmp(argv[2], "up")) {
e9aec22c 160 cmd = SBINDIR "/ifup";
7742e157 161 } else if (!strcmp(argv[2], "down")) {
e9aec22c 162 cmd = SBINDIR "/ifdown";
7742e157
AF
163 } else if (!strcmp(argv[2], "report")) {
164 report = 1;
165 } else {
166 usage();
167 }
168
d25dc461
AM
169 if (chdir("/etc/sysconfig/interfaces")) {
170 fprintf(stderr, "error switching to /etc/sysconfig/interfaces: "
7742e157
AF
171 "%s\n", strerror(errno));
172 exit(1);
173 }
174
175 /* force the interface configuration to be in the current directory */
176 chptr = ifaceConfig = argv[1];
177 while (*chptr) {
178 if (*chptr == '/')
179 ifaceConfig = chptr + 1;
180 chptr++;
181 }
182
183 /* automatically prepend "ifcfg-" if it is not specified */
184 if (strncmp(ifaceConfig, "ifcfg-", 6)) {
185 char *temp;
00196ec7
AM
186 size_t len = strlen(ifaceConfig);
187
188 /* Make sure a wise guys hasn't tried an integer wrap-around or
189 stack overflow attack. There's no way it could refer to anything
190 bigger than the largest filename, so cut 'em off there. */
191 if (len > PATH_MAX)
192 exit(1);
7742e157 193
00196ec7 194 temp = (char *) alloca(len + 7);
7742e157
AF
195 strcpy(temp, "ifcfg-");
196 /* strcat is safe because we got the length from strlen */
197 strcat(temp, ifaceConfig);
198 ifaceConfig = temp;
199 }
200
de1fc6ce 201 if(getuid() != 0)
7742e157
AF
202 switch (userCtl(ifaceConfig)) {
203 char *dash;
204
205 case NOT_FOUND:
206 /* a `-' will be found at least in "ifcfg-" */
207 dash = strrchr(ifaceConfig, '-');
208 if (*(dash-1) != 'g') {
209 /* This was a clone configuration; ask the parent config */
210 tmp = *dash;
211 *dash = '\0';
212 if (userCtl(ifaceConfig) == FOUND_TRUE) {
213 /* exit the switch; users are allowed to control */
214 *dash = tmp;
215 break;
216 }
217 *dash = tmp;
218 }
219 /* else fall through */
220 case FOUND_FALSE:
221 if (! report)
222 fprintf(stderr,
223 "Users are not allowed to control this interface.\n");
224 exit(1);
225 break;
226 }
227
228 /* looks good to me -- let's go for it if we are changing the interface,
229 * report good status to the user otherwise */
230
231 if (report)
232 exit(0);
233
234 /* pppd wants the real uid to be the same as the effective (god only
235 knows why when it works fine setuid out of the box) */
236 setuid(geteuid());
237
238 execle(cmd, cmd, ifaceConfig, NULL, safeEnviron);
239 fprintf(stderr, "exec of %s failed: %s\n", cmd, strerror(errno));
240
241 exit(1);
242}
This page took 0.117208 seconds and 4 git commands to generate.