rc: fix and improve script scanning START and STOP
[project/rpcd.git] / rc.c
1 // SPDX-License-Identifier: ISC OR MIT
2 /*
3 * rpcd - UBUS RPC server
4 *
5 * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
6 */
7
8 #include <dirent.h>
9 #include <fcntl.h>
10 #include <linux/limits.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13
14 #include <libubox/blobmsg.h>
15 #include <libubox/ulog.h>
16 #include <libubox/uloop.h>
17 #include <libubus.h>
18
19 #include <rpcd/rc.h>
20
21 #define RC_LIST_EXEC_TIMEOUT_MS 3000
22
23 enum {
24 RC_INIT_NAME,
25 RC_INIT_ACTION,
26 __RC_INIT_MAX
27 };
28
29 static const struct blobmsg_policy rc_init_policy[] = {
30 [RC_INIT_NAME] = { "name", BLOBMSG_TYPE_STRING },
31 [RC_INIT_ACTION] = { "action", BLOBMSG_TYPE_STRING },
32 };
33
34 struct rc_list_context {
35 struct uloop_process process;
36 struct uloop_timeout timeout;
37 struct ubus_context *ctx;
38 struct ubus_request_data req;
39 struct blob_buf *buf;
40 DIR *dir;
41
42 /* Info about currently processed init.d entry */
43 struct {
44 char path[PATH_MAX];
45 const char *d_name;
46 int start;
47 int stop;
48 bool enabled;
49 bool running;
50 } entry;
51 };
52
53 static void rc_list_readdir(struct rc_list_context *c);
54
55 /**
56 * rc_check_script - check if script is safe to execute as root
57 *
58 * Check if it's owned by root and if only root can modify it.
59 */
60 static int rc_check_script(const char *path)
61 {
62 struct stat s;
63
64 if (stat(path, &s))
65 return UBUS_STATUS_NOT_FOUND;
66
67 if (s.st_uid != 0 || s.st_gid != 0 || !(s.st_mode & S_IXUSR) || (s.st_mode & S_IWOTH))
68 return UBUS_STATUS_PERMISSION_DENIED;
69
70 return UBUS_STATUS_OK;
71 }
72
73 static void rc_list_add_table(struct rc_list_context *c)
74 {
75 void *e;
76
77 e = blobmsg_open_table(c->buf, c->entry.d_name);
78
79 if (c->entry.start >= 0)
80 blobmsg_add_u16(c->buf, "start", c->entry.start);
81 if (c->entry.stop >= 0)
82 blobmsg_add_u16(c->buf, "stop", c->entry.stop);
83 blobmsg_add_u8(c->buf, "enabled", c->entry.enabled);
84 blobmsg_add_u8(c->buf, "running", c->entry.running);
85
86 blobmsg_close_table(c->buf, e);
87 }
88
89 static void rpc_list_exec_timeout_cb(struct uloop_timeout *t)
90 {
91 struct rc_list_context *c = container_of(t, struct rc_list_context, timeout);
92
93 ULOG_WARN("Timeout waiting for %s\n", c->entry.path);
94
95 uloop_process_delete(&c->process);
96 kill(c->process.pid, SIGKILL);
97
98 rc_list_readdir(c);
99 }
100
101 /**
102 * rc_exec - execute a file and call callback on complete
103 */
104 static int rc_list_exec(struct rc_list_context *c, const char *action, uloop_process_handler cb)
105 {
106 pid_t pid;
107 int err;
108 int fd;
109
110 pid = fork();
111 switch (pid) {
112 case -1:
113 return -errno;
114 case 0:
115 /* Set stdin, stdout & stderr to /dev/null */
116 fd = open("/dev/null", O_RDWR);
117 if (fd >= 0) {
118 dup2(fd, 0);
119 dup2(fd, 1);
120 dup2(fd, 2);
121 if (fd > 2)
122 close(fd);
123 }
124
125 uloop_end();
126
127 execl(c->entry.path, c->entry.path, action, NULL);
128 exit(errno);
129 default:
130 c->process.pid = pid;
131 c->process.cb = cb;
132
133 err = uloop_process_add(&c->process);
134 if (err)
135 return err;
136
137 c->timeout.cb = rpc_list_exec_timeout_cb;
138 err = uloop_timeout_set(&c->timeout, RC_LIST_EXEC_TIMEOUT_MS);
139 if (err) {
140 uloop_process_delete(&c->process);
141 return err;
142 }
143
144 return 0;
145 }
146 }
147
148 static void rc_list_exec_running_cb(struct uloop_process *p, int stat)
149 {
150 struct rc_list_context *c = container_of(p, struct rc_list_context, process);
151
152 uloop_timeout_cancel(&c->timeout);
153
154 c->entry.running = !stat;
155 rc_list_add_table(c);
156
157 rc_list_readdir(c);
158 }
159
160 static void rc_list_readdir(struct rc_list_context *c)
161 {
162 struct dirent *e;
163 FILE *fp;
164
165 e = readdir(c->dir);
166 if (!e) {
167 closedir(c->dir);
168 ubus_send_reply(c->ctx, &c->req, c->buf->head);
169 ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK);
170 return;
171 }
172
173 if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
174 goto next;
175
176 memset(&c->entry, 0, sizeof(c->entry));
177 c->entry.start = -1;
178 c->entry.stop = -1;
179
180 snprintf(c->entry.path, sizeof(c->entry.path), "/etc/init.d/%s", e->d_name);
181 if (rc_check_script(c->entry.path))
182 goto next;
183
184 c->entry.d_name = e->d_name;
185
186 fp = fopen(c->entry.path, "r");
187 if (fp) {
188 struct stat s;
189 char path[PATH_MAX];
190 char line[255];
191 bool beginning;
192 int count = 0;
193
194 beginning = true;
195 while ((c->entry.start < 0 || c->entry.stop < 0) &&
196 count <= 10 && fgets(line, sizeof(line), fp)) {
197 if (beginning) {
198 if (!strncmp(line, "START=", 6)) {
199 c->entry.start = strtoul(line + 6, NULL, 0);
200 } else if (!strncmp(line, "STOP=", 5)) {
201 c->entry.stop = strtoul(line + 5, NULL, 0);
202 }
203 count++;
204 }
205
206 beginning = !!strchr(line, '\n');
207 }
208 fclose(fp);
209
210 if (c->entry.start >= 0) {
211 snprintf(path, sizeof(path), "/etc/rc.d/S%02d%s", c->entry.start, c->entry.d_name);
212 if (!stat(path, &s) && (s.st_mode & S_IXUSR))
213 c->entry.enabled = true;
214 }
215 }
216
217 if (rc_list_exec(c, "running", rc_list_exec_running_cb))
218 goto next;
219
220 return;
221 next:
222 rc_list_readdir(c);
223 }
224
225 /**
226 * rc_list - allocate listing context and start reading directory
227 */
228 static int rc_list(struct ubus_context *ctx, struct ubus_object *obj,
229 struct ubus_request_data *req, const char *method,
230 struct blob_attr *msg)
231 {
232 static struct blob_buf buf;
233 struct rc_list_context *c;
234
235 blob_buf_init(&buf, 0);
236
237 c = calloc(1, sizeof(*c));
238 if (!c)
239 return UBUS_STATUS_UNKNOWN_ERROR;
240
241 c->ctx = ctx;
242 c->buf = &buf;
243 c->dir = opendir("/etc/init.d");
244 if (!c->dir) {
245 free(c);
246 return UBUS_STATUS_UNKNOWN_ERROR;
247 }
248
249 ubus_defer_request(ctx, req, &c->req);
250
251 rc_list_readdir(c);
252
253 return 0; /* Deferred */
254 }
255
256 struct rc_init_context {
257 struct uloop_process process;
258 struct ubus_context *ctx;
259 struct ubus_request_data req;
260 };
261
262 static void rc_init_cb(struct uloop_process *p, int stat)
263 {
264 struct rc_init_context *c = container_of(p, struct rc_init_context, process);
265
266 ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK);
267
268 free(c);
269 }
270
271 static int rc_init(struct ubus_context *ctx, struct ubus_object *obj,
272 struct ubus_request_data *req, const char *method,
273 struct blob_attr *msg)
274 {
275 struct blob_attr *tb[__RC_INIT_MAX];
276 struct rc_init_context *c;
277 char path[PATH_MAX];
278 const char *action;
279 const char *name;
280 const char *chr;
281 pid_t pid;
282 int err;
283 int fd;
284
285 blobmsg_parse(rc_init_policy, __RC_INIT_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
286
287 if (!tb[RC_INIT_NAME] || !tb[RC_INIT_ACTION])
288 return UBUS_STATUS_INVALID_ARGUMENT;
289
290 name = blobmsg_get_string(tb[RC_INIT_NAME]);
291
292 /* Validate script name */
293 for (chr = name; (chr = strchr(chr, '.')); chr++) {
294 if (*(chr + 1) == '.')
295 return UBUS_STATUS_INVALID_ARGUMENT;
296 }
297 if (strchr(name, '/'))
298 return UBUS_STATUS_INVALID_ARGUMENT;
299
300 snprintf(path, sizeof(path), "/etc/init.d/%s", name);
301
302 /* Validate script privileges */
303 err = rc_check_script(path);
304 if (err)
305 return err;
306
307 action = blobmsg_get_string(tb[RC_INIT_ACTION]);
308 if (strcmp(action, "disable") &&
309 strcmp(action, "enable") &&
310 strcmp(action, "stop") &&
311 strcmp(action, "start") &&
312 strcmp(action, "restart") &&
313 strcmp(action, "reload"))
314 return UBUS_STATUS_INVALID_ARGUMENT;
315
316 c = calloc(1, sizeof(*c));
317 if (!c)
318 return UBUS_STATUS_UNKNOWN_ERROR;
319
320 pid = fork();
321 switch (pid) {
322 case -1:
323 free(c);
324 return UBUS_STATUS_UNKNOWN_ERROR;
325 case 0:
326 /* Set stdin, stdout & stderr to /dev/null */
327 fd = open("/dev/null", O_RDWR);
328 if (fd >= 0) {
329 dup2(fd, 0);
330 dup2(fd, 1);
331 dup2(fd, 2);
332 if (fd > 2)
333 close(fd);
334 }
335
336 uloop_end();
337
338 execl(path, path, action, NULL);
339 exit(errno);
340 default:
341 c->ctx = ctx;
342 c->process.pid = pid;
343 c->process.cb = rc_init_cb;
344 uloop_process_add(&c->process);
345
346 ubus_defer_request(ctx, req, &c->req);
347
348 return 0; /* Deferred */
349 }
350 }
351
352 int rpc_rc_api_init(struct ubus_context *ctx)
353 {
354 static const struct ubus_method rc_methods[] = {
355 UBUS_METHOD_NOARG("list", rc_list),
356 UBUS_METHOD("init", rc_init, rc_init_policy),
357 };
358
359 static struct ubus_object_type rc_type =
360 UBUS_OBJECT_TYPE("rc", rc_methods);
361
362 static struct ubus_object obj = {
363 .name = "rc",
364 .type = &rc_type,
365 .methods = rc_methods,
366 .n_methods = ARRAY_SIZE(rc_methods),
367 };
368
369 return ubus_add_object(ctx, &obj);
370 }