]> git.pld-linux.org Git - projects/rc-scripts.git/blame - src/usernetctl.c
- merge from TOTALNEW branch (see NEWS for more info)
[projects/rc-scripts.git] / src / usernetctl.c
CommitLineData
7742e157
AF
1#include <alloca.h>
2#include <ctype.h>
3#include <errno.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/stat.h>
9#include <unistd.h>
10
de1fc6ce 11/* This will be running setuid root, so be careful! */
7742e157
AF
12static char * safeEnviron[] = {
13 "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
14 "HOME=/root",
15 NULL
16};
17
18#define FOUND_FALSE -1
19#define NOT_FOUND 0
20#define FOUND_TRUE 1
21
de1fc6ce
JR
22static void
23usage(void) {
24 fprintf(stderr, "usage: usernetctl <interface-config> <up|down|report>\n");
25 exit(1);
26}
7742e157 27
de1fc6ce
JR
28static size_t
29testSafe(char *ifaceConfig) {
7742e157
AF
30 struct stat sb;
31
de1fc6ce 32 /* These shouldn't be symbolic links -- anal, but that's fine w/ mkj. */
7742e157
AF
33 if (lstat(ifaceConfig, &sb)) {
34 fprintf(stderr, "failed to stat %s: %s\n", ifaceConfig,
35 strerror(errno));
36 exit(1);
37 }
38
de1fc6ce 39 /* Safety/sanity checks. */
7742e157
AF
40 if (!S_ISREG(sb.st_mode)) {
41 fprintf(stderr, "%s is not a normal file\n", ifaceConfig);
42 exit(1);
43 }
44
45 if (sb.st_uid) {
46 fprintf(stderr, "%s should be owned by root\n", ifaceConfig);
47 exit(1);
48 }
49
50 if (sb.st_mode & S_IWOTH) {
51 fprintf(stderr, "%s should not be world writeable\n", ifaceConfig);
52 exit(1);
53 }
54
55 return sb.st_size;
56}
57
58
de1fc6ce
JR
59static int
60userCtl(char *file) {
61 char *contents = NULL;
62 char *chptr = NULL;
63 char *next = NULL;
64 int fd = -1, retval = NOT_FOUND;
65 size_t size = 0;
7742e157
AF
66
67 size = testSafe(file);
68
de1fc6ce 69 contents = malloc(size + 2);
7742e157 70
de1fc6ce 71 if ((fd = open(file, O_RDONLY)) == -1) {
7742e157
AF
72 fprintf(stderr, "failed to open %s: %s\n", file, strerror(errno));
73 exit(1);
74 }
75
76 if (read(fd, contents, size) != size) {
77 perror("error reading device configuration");
78 exit(1);
79 }
80 close(fd);
81
82 contents[size] = '\n';
83 contents[size + 1] = '\0';
84
de1fc6ce
JR
85 /* Each pass parses a single line (until an answer is found), The contents
86 pointer itself points to the beginning of the current line. */
7742e157
AF
87 while (*contents) {
88 chptr = contents;
89 while (*chptr != '\n') chptr++;
de1fc6ce 90 next = chptr + 1;
12de71be 91 while (chptr >= contents && isspace(*chptr)) chptr--;
7742e157
AF
92 *(++chptr) = '\0';
93
94 if (!strncmp(contents, "USERCTL=", 8)) {
12de71be 95 contents += 8;
96 if (contents[0] == '"' &&
97 contents[strlen(contents) - 1] == '"') {
98 contents++;
99 contents[strlen(contents) - 1] = '\0';
100 }
101
102 if (!strcmp(contents, "yes") || !strcmp(contents, "true"))
de1fc6ce 103 retval = FOUND_TRUE;
12de71be 104 else
de1fc6ce
JR
105 retval = FOUND_FALSE;
106
107 break;
7742e157
AF
108 }
109
de1fc6ce 110 contents = next;
7742e157
AF
111 }
112
de1fc6ce 113 free(contents);
7742e157 114
de1fc6ce
JR
115 return retval;
116}
7742e157 117
de1fc6ce
JR
118int
119main(int argc, char ** argv) {
7742e157
AF
120 char * ifaceConfig;
121 char * chptr;
122 char * cmd;
123 int report = 0;
124 char tmp;
125
126 if (argc != 3) usage();
127
128 if (!strcmp(argv[2], "up")) {
de1fc6ce 129 cmd = "./ifup";
7742e157 130 } else if (!strcmp(argv[2], "down")) {
de1fc6ce 131 cmd = "./ifdown";
7742e157
AF
132 } else if (!strcmp(argv[2], "report")) {
133 report = 1;
134 } else {
135 usage();
136 }
137
de1fc6ce
JR
138 if (chdir("/etc/sysconfig/network-scripts")) {
139 fprintf(stderr, "error switching to /etc/sysconfig/network-scripts: "
7742e157
AF
140 "%s\n", strerror(errno));
141 exit(1);
142 }
143
144 /* force the interface configuration to be in the current directory */
145 chptr = ifaceConfig = argv[1];
146 while (*chptr) {
147 if (*chptr == '/')
148 ifaceConfig = chptr + 1;
149 chptr++;
150 }
151
152 /* automatically prepend "ifcfg-" if it is not specified */
153 if (strncmp(ifaceConfig, "ifcfg-", 6)) {
154 char *temp;
155
156 temp = (char *) alloca(strlen(ifaceConfig) + 7);
157 strcpy(temp, "ifcfg-");
158 /* strcat is safe because we got the length from strlen */
159 strcat(temp, ifaceConfig);
160 ifaceConfig = temp;
161 }
162
de1fc6ce 163 if(getuid() != 0)
7742e157
AF
164 switch (userCtl(ifaceConfig)) {
165 char *dash;
166
167 case NOT_FOUND:
168 /* a `-' will be found at least in "ifcfg-" */
169 dash = strrchr(ifaceConfig, '-');
170 if (*(dash-1) != 'g') {
171 /* This was a clone configuration; ask the parent config */
172 tmp = *dash;
173 *dash = '\0';
174 if (userCtl(ifaceConfig) == FOUND_TRUE) {
175 /* exit the switch; users are allowed to control */
176 *dash = tmp;
177 break;
178 }
179 *dash = tmp;
180 }
181 /* else fall through */
182 case FOUND_FALSE:
183 if (! report)
184 fprintf(stderr,
185 "Users are not allowed to control this interface.\n");
186 exit(1);
187 break;
188 }
189
190 /* looks good to me -- let's go for it if we are changing the interface,
191 * report good status to the user otherwise */
192
193 if (report)
194 exit(0);
195
196 /* pppd wants the real uid to be the same as the effective (god only
197 knows why when it works fine setuid out of the box) */
198 setuid(geteuid());
199
200 execle(cmd, cmd, ifaceConfig, NULL, safeEnviron);
201 fprintf(stderr, "exec of %s failed: %s\n", cmd, strerror(errno));
202
203 exit(1);
204}
This page took 0.06934 seconds and 4 git commands to generate.