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