rc.c 9.0 KB

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