1 /*
2 *
3 * Authors:
4 * Jim Paris <jim@jtan.com>
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Lars Fenneberg <lf@elemental.net>
7 *
8 * This software is Copyright 1996,1997,2008 by the above mentioned author(s),
9 * All Rights Reserved.
10 *
11 * The license which is distributed with this software in the file COPYRIGHT
12 * applies to this software. If your distribution is missing this file, you
13 * may request it from <reubenhwk@gmail.com>.
14 *
15 */
16
17 #include "config.h"
18 #include "includes.h"
19 #include "pathnames.h"
20 #include "radvd.h"
21
22 static int set_interface_var(const char *iface, const char *var, const char *name, uint32_t val);
23 static void privsep_read_loop(void);
24
25 /* For reading or writing, depending on process */
26 static int pfd = -1;
27
privsep_set_write_fd(int fd)28 void privsep_set_write_fd(int fd) { pfd = fd; }
29
30 /* Command types */
31 enum privsep_type {
32 SET_INTERFACE_LINKMTU,
33 SET_INTERFACE_CURHLIM,
34 SET_INTERFACE_REACHTIME,
35 SET_INTERFACE_RETRANSTIMER,
36 };
37
38 /* Command sent over pipe is a fixed size binary structure. */
39 struct privsep_command {
40 int type;
41 char iface[IFNAMSIZ];
42 uint32_t val;
43 };
44
45 /* Privileged read loop */
privsep_read_loop(void)46 static void privsep_read_loop(void)
47 {
48 while (1) {
49 struct privsep_command cmd;
50 int ret = readn(pfd, &cmd, sizeof(cmd));
51 if (ret <= 0) {
52 /* Error or EOF, give up */
53 if (ret < 0) {
54 flog(LOG_ERR, "Exiting, privsep_read_loop had readn error: %s", strerror(errno));
55 } else {
56 flog(LOG_ERR, "Exiting, privsep_read_loop had readn return 0 bytes");
57 }
58 }
59 if (ret != sizeof(cmd)) {
60 /* Short read, ignore */
61 return;
62 }
63
64 cmd.iface[IFNAMSIZ - 1] = '\0';
65
66 switch (cmd.type) {
67
68 case SET_INTERFACE_LINKMTU:
69 if (cmd.val < MIN_AdvLinkMTU || cmd.val > MAX_AdvLinkMTU) {
70 flog(LOG_ERR, "(privsep) %s: LinkMTU (%u) is not within the defined bounds, ignoring", cmd.iface,
71 cmd.val);
72 break;
73 }
74 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_LINKMTU, "LinkMTU", cmd.val);
75 break;
76
77 case SET_INTERFACE_CURHLIM:
78 if (cmd.val < MIN_AdvCurHopLimit || cmd.val > MAX_AdvCurHopLimit) {
79 flog(LOG_ERR, "(privsep) %s: CurHopLimit (%u) is not within the defined bounds, ignoring",
80 cmd.iface, cmd.val);
81 break;
82 }
83 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_CURHLIM, "CurHopLimit", cmd.val);
84 break;
85
86 case SET_INTERFACE_REACHTIME:
87 if (cmd.val < MIN_AdvReachableTime || cmd.val > MAX_AdvReachableTime) {
88 flog(LOG_ERR, "(privsep) %s: BaseReachableTimer (%u) is not within the defined bounds, ignoring",
89 cmd.iface, cmd.val);
90 break;
91 }
92 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_BASEREACHTIME_MS, "BaseReachableTimer (ms)", cmd.val);
93 if (ret == 0)
94 break;
95 set_interface_var(cmd.iface, PROC_SYS_IP6_BASEREACHTIME, "BaseReachableTimer", cmd.val / 1000);
96 break;
97
98 case SET_INTERFACE_RETRANSTIMER:
99 if (cmd.val < MIN_AdvRetransTimer || cmd.val > MAX_AdvRetransTimer) {
100 flog(LOG_ERR, "(privsep) %s: RetransTimer (%u) is not within the defined bounds, ignoring",
101 cmd.iface, cmd.val);
102 break;
103 }
104 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_RETRANSTIMER_MS, "RetransTimer (ms)", cmd.val);
105 if (ret == 0)
106 break;
107 set_interface_var(cmd.iface, PROC_SYS_IP6_RETRANSTIMER, "RetransTimer",
108 cmd.val / 1000 * USER_HZ); /* XXX user_hz */
109 break;
110
111 default:
112 /* Bad command */
113 break;
114 }
115 }
116 }
117
privsep_init(int fd)118 void privsep_init(int fd)
119 {
120 /* This will be the privileged child */
121 pfd = fd;
122 privsep_read_loop();
123 close(pfd);
124 flog(LOG_ERR, "Exiting, privsep_read_loop is complete.");
125 }
126
127 /* Interface calls for the unprivileged process */
privsep_interface_linkmtu(const char * iface,uint32_t mtu)128 int privsep_interface_linkmtu(const char *iface, uint32_t mtu)
129 {
130 struct privsep_command cmd;
131 cmd.type = SET_INTERFACE_LINKMTU;
132 strncpy(cmd.iface, iface, sizeof(cmd.iface));
133 cmd.val = mtu;
134
135 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
136 return -1;
137 return 0;
138 }
139
privsep_interface_curhlim(const char * iface,uint32_t hlim)140 int privsep_interface_curhlim(const char *iface, uint32_t hlim)
141 {
142 struct privsep_command cmd;
143 cmd.type = SET_INTERFACE_CURHLIM;
144 strncpy(cmd.iface, iface, sizeof(cmd.iface));
145 cmd.val = hlim;
146 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
147 return -1;
148 return 0;
149 }
150
privsep_interface_reachtime(const char * iface,uint32_t rtime)151 int privsep_interface_reachtime(const char *iface, uint32_t rtime)
152 {
153 struct privsep_command cmd;
154 cmd.type = SET_INTERFACE_REACHTIME;
155 strncpy(cmd.iface, iface, sizeof(cmd.iface));
156 cmd.val = rtime;
157 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
158 return -1;
159 return 0;
160 }
161
privsep_interface_retranstimer(const char * iface,uint32_t rettimer)162 int privsep_interface_retranstimer(const char *iface, uint32_t rettimer)
163 {
164 struct privsep_command cmd;
165 cmd.type = SET_INTERFACE_RETRANSTIMER;
166 strncpy(cmd.iface, iface, sizeof(cmd.iface));
167 cmd.val = rettimer;
168 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
169 return -1;
170 return 0;
171 }
172
173 /* note: also called from the root context */
set_interface_var(const char * iface,const char * var,const char * name,uint32_t val)174 static int set_interface_var(const char *iface, const char *var, const char *name, uint32_t val)
175 {
176 int retval = -1;
177 FILE *fp = 0;
178 char *spath = strdupf(var, iface);
179
180 /* No path traversal */
181 if (!iface[0] || !strcmp(iface, ".") || !strcmp(iface, "..") || strchr(iface, '/'))
182 goto cleanup;
183
184 if (access(spath, F_OK) != 0)
185 goto cleanup;
186
187 fp = fopen(spath, "w");
188 if (!fp) {
189 if (name)
190 flog(LOG_ERR, "failed to set %s (%u) for %s: %s", name, val, iface, strerror(errno));
191 goto cleanup;
192 }
193
194 if (0 > fprintf(fp, "%u", val)) {
195 goto cleanup;
196 }
197
198 retval = 0;
199
200 cleanup:
201 if (fp)
202 fclose(fp);
203
204 free(spath);
205
206 return retval;
207 }
208