Merge branch 'tomato-ND-USBmod' into tomato-RT
[tomato.git] / release / src / router / radvd / privsep-linux.c
blobd6717bfe084f8be853fa26edf9601391ff4d2d4b
1 /*
2 * $Id: privsep-linux.c,v 1.6 2011/02/28 10:53:07 reubenhwk Exp $
4 * Authors:
5 * Jim Paris <jim@jtan.com>
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Lars Fenneberg <lf@elemental.net>
9 * This software is Copyright 1996,1997,2008 by the above mentioned author(s),
10 * All Rights Reserved.
12 * The license which is distributed with this software in the file COPYRIGHT
13 * applies to this software. If your distribution is missing this file, you
14 * may request it from <pekkas@netcore.fi>.
18 #include "config.h"
19 #include "includes.h"
20 #include "radvd.h"
21 #include "pathnames.h"
23 int privsep_set(const char *iface, const char *var, uint32_t val);
24 void privsep_read_loop(void);
26 /* For reading or writing, depending on process */
27 static int pfd = -1;
29 /* Command types */
30 enum privsep_type {
31 SET_INTERFACE_LINKMTU,
32 SET_INTERFACE_CURHLIM,
33 SET_INTERFACE_REACHTIME,
34 SET_INTERFACE_RETRANSTIMER,
37 /* Command sent over pipe is a fixed size binary structure. */
38 struct privsep_command {
39 int type;
40 char iface[IFNAMSIZ];
41 uint32_t val;
44 /* Privileged read loop */
45 void
46 privsep_read_loop(void)
48 struct privsep_command cmd;
49 int ret;
51 while (1) {
52 ret = readn(pfd, &cmd, sizeof(cmd));
53 if (ret <= 0) {
54 /* Error or EOF, give up */
55 if (ret < 0) {
56 flog(LOG_ERR, "Exiting, privsep_read_loop had readn error: %s\n",
57 strerror(errno));
58 } else {
59 flog(LOG_ERR, "Exiting, privsep_read_loop had readn return 0 bytes\n");
61 close(pfd);
62 _exit(0);
64 if (ret != sizeof(cmd)) {
65 /* Short read, ignore */
66 continue;
69 cmd.iface[IFNAMSIZ-1] = '\0';
71 switch(cmd.type) {
73 case SET_INTERFACE_LINKMTU:
74 if (cmd.val < MIN_AdvLinkMTU || cmd.val > MAX_AdvLinkMTU) {
75 flog(LOG_ERR, "(privsep) %s: LinkMTU (%u) is not within the defined bounds, ignoring", cmd.iface, cmd.val);
76 break;
78 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_LINKMTU, "LinkMTU", cmd.val);
79 break;
81 case SET_INTERFACE_CURHLIM:
82 if (cmd.val < MIN_AdvCurHopLimit || cmd.val > MAX_AdvCurHopLimit) {
83 flog(LOG_ERR, "(privsep) %s: CurHopLimit (%u) is not within the defined bounds, ignoring", cmd.iface, cmd.val);
84 break;
86 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_CURHLIM, "CurHopLimit", cmd.val);
87 break;
89 case SET_INTERFACE_REACHTIME:
90 if (cmd.val < MIN_AdvReachableTime || cmd.val > MAX_AdvReachableTime) {
91 flog(LOG_ERR, "(privsep) %s: BaseReachableTimer (%u) is not within the defined bounds, ignoring", cmd.iface, cmd.val);
92 break;
94 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_BASEREACHTIME_MS, "BaseReachableTimer (ms)", cmd.val);
95 if (ret == 0)
96 break;
97 set_interface_var(cmd.iface, PROC_SYS_IP6_BASEREACHTIME, "BaseReachableTimer", cmd.val / 1000);
98 break;
100 case SET_INTERFACE_RETRANSTIMER:
101 if (cmd.val < MIN_AdvRetransTimer || cmd.val > MAX_AdvRetransTimer) {
102 flog(LOG_ERR, "(privsep) %s: RetransTimer (%u) is not within the defined bounds, ignoring", cmd.iface, cmd.val);
103 break;
105 ret = set_interface_var(cmd.iface, PROC_SYS_IP6_RETRANSTIMER_MS, "RetransTimer (ms)", cmd.val);
106 if (ret == 0)
107 break;
108 set_interface_var(cmd.iface, PROC_SYS_IP6_RETRANSTIMER, "RetransTimer", cmd.val / 1000 * USER_HZ); /* XXX user_hz */
109 break;
111 default:
112 /* Bad command */
113 break;
118 /* Return 1 if privsep is currently enabled */
120 privsep_enabled(void)
122 if (pfd < 0)
123 return 0;
124 return 1;
127 /* Fork to create privileged process connected by a pipe */
129 privsep_init(void)
131 int pipefds[2];
132 pid_t pid;
134 if (privsep_enabled())
135 return 0;
137 if (pipe(pipefds) != 0) {
138 flog(LOG_ERR, "Couldn't create privsep pipe.");
139 return (-1);
142 pid = fork();
143 if (pid == -1) {
144 flog(LOG_ERR, "Couldn't fork for privsep.");
145 return (-1);
148 if (pid == 0) {
149 int nullfd;
151 /* This will be the privileged child */
152 close(pipefds[1]);
153 pfd = pipefds[0];
155 /* Detach from stdio */
156 nullfd = open("/dev/null", O_RDONLY);
157 if (nullfd < 0) {
158 perror("/dev/null");
159 close(pfd);
160 _exit(1);
162 dup2(nullfd, 0);
163 dup2(nullfd, 1);
164 /* XXX: we'll keep stderr open in debug mode for better logging */
165 if (get_debuglevel() == 0)
166 dup2(nullfd, 2);
168 privsep_read_loop();
169 close(pfd);
170 flog(LOG_ERR, "Exiting, privsep_read_loop is complete.\n");
171 _exit(0);
174 /* Continue execution (will drop privileges soon) */
175 close(pipefds[0]);
176 pfd = pipefds[1];
178 return 0;
181 /* Interface calls for the unprivileged process */
183 privsep_interface_linkmtu(const char *iface, uint32_t mtu)
185 struct privsep_command cmd;
186 cmd.type = SET_INTERFACE_LINKMTU;
187 strncpy(cmd.iface, iface, sizeof(cmd.iface));
188 cmd.val = mtu;
190 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
191 return (-1);
192 return 0;
196 privsep_interface_curhlim(const char *iface, uint32_t hlim)
198 struct privsep_command cmd;
199 cmd.type = SET_INTERFACE_CURHLIM;
200 strncpy(cmd.iface, iface, sizeof(cmd.iface));
201 cmd.val = hlim;
202 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
203 return (-1);
204 return 0;
208 privsep_interface_reachtime(const char *iface, uint32_t rtime)
210 struct privsep_command cmd;
211 cmd.type = SET_INTERFACE_REACHTIME;
212 strncpy(cmd.iface, iface, sizeof(cmd.iface));
213 cmd.val = rtime;
214 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
215 return (-1);
216 return 0;
220 privsep_interface_retranstimer(const char *iface, uint32_t rettimer)
222 struct privsep_command cmd;
223 cmd.type = SET_INTERFACE_RETRANSTIMER;
224 strncpy(cmd.iface, iface, sizeof(cmd.iface));
225 cmd.val = rettimer;
226 if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
227 return (-1);
228 return 0;