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[32]; 191 bool beginning; 192 193 beginning = true; 194 while (c->entry.start < 0 && c->entry.stop < 0 && fgets(line, sizeof(line), fp)) { 195 if (beginning) { 196 if (!strncmp(line, "START=", 6)) { 197 c->entry.start = strtoul(line + 6, NULL, 0); 198 } else if (!strncmp(line, "STOP=", 5)) { 199 c->entry.stop = strtoul(line + 5, NULL, 0); 200 } 201 } 202 203 beginning = !!strchr(line, '\n'); 204 } 205 fclose(fp); 206 207 if (c->entry.start >= 0) { 208 snprintf(path, sizeof(path), "/etc/rc.d/S%02d%s", c->entry.start, c->entry.d_name); 209 if (!stat(path, &s) && (s.st_mode & S_IXUSR)) 210 c->entry.enabled = true; 211 } 212 } 213 214 if (rc_list_exec(c, "running", rc_list_exec_running_cb)) 215 goto next; 216 217 return; 218 next: 219 rc_list_readdir(c); 220 } 221 222 /** 223 * rc_list - allocate listing context and start reading directory 224 */ 225 static int rc_list(struct ubus_context *ctx, struct ubus_object *obj, 226 struct ubus_request_data *req, const char *method, 227 struct blob_attr *msg) 228 { 229 static struct blob_buf buf; 230 struct rc_list_context *c; 231 232 blob_buf_init(&buf, 0); 233 234 c = calloc(1, sizeof(*c)); 235 if (!c) 236 return UBUS_STATUS_UNKNOWN_ERROR; 237 238 c->ctx = ctx; 239 c->buf = &buf; 240 c->dir = opendir("/etc/init.d"); 241 if (!c->dir) { 242 free(c); 243 return UBUS_STATUS_UNKNOWN_ERROR; 244 } 245 246 ubus_defer_request(ctx, req, &c->req); 247 248 rc_list_readdir(c); 249 250 return 0; /* Deferred */ 251 } 252 253 struct rc_init_context { 254 struct uloop_process process; 255 struct ubus_context *ctx; 256 struct ubus_request_data req; 257 }; 258 259 static void rc_init_cb(struct uloop_process *p, int stat) 260 { 261 struct rc_init_context *c = container_of(p, struct rc_init_context, process); 262 263 ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK); 264 265 free(c); 266 } 267 268 static int rc_init(struct ubus_context *ctx, struct ubus_object *obj, 269 struct ubus_request_data *req, const char *method, 270 struct blob_attr *msg) 271 { 272 struct blob_attr *tb[__RC_INIT_MAX]; 273 struct rc_init_context *c; 274 char path[PATH_MAX]; 275 const char *action; 276 const char *name; 277 const char *chr; 278 pid_t pid; 279 int err; 280 int fd; 281 282 blobmsg_parse(rc_init_policy, __RC_INIT_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); 283 284 if (!tb[RC_INIT_NAME] || !tb[RC_INIT_ACTION]) 285 return UBUS_STATUS_INVALID_ARGUMENT; 286 287 name = blobmsg_get_string(tb[RC_INIT_NAME]); 288 289 /* Validate script name */ 290 for (chr = name; (chr = strchr(chr, '.')); chr++) { 291 if (*(chr + 1) == '.') 292 return UBUS_STATUS_INVALID_ARGUMENT; 293 } 294 if (strchr(name, '/')) 295 return UBUS_STATUS_INVALID_ARGUMENT; 296 297 snprintf(path, sizeof(path), "/etc/init.d/%s", name); 298 299 /* Validate script privileges */ 300 err = rc_check_script(path); 301 if (err) 302 return err; 303 304 action = blobmsg_get_string(tb[RC_INIT_ACTION]); 305 if (strcmp(action, "disable") && 306 strcmp(action, "enable") && 307 strcmp(action, "stop") && 308 strcmp(action, "start") && 309 strcmp(action, "restart") && 310 strcmp(action, "reload")) 311 return UBUS_STATUS_INVALID_ARGUMENT; 312 313 c = calloc(1, sizeof(*c)); 314 if (!c) 315 return UBUS_STATUS_UNKNOWN_ERROR; 316 317 pid = fork(); 318 switch (pid) { 319 case -1: 320 free(c); 321 return UBUS_STATUS_UNKNOWN_ERROR; 322 case 0: 323 /* Set stdin, stdout & stderr to /dev/null */ 324 fd = open("/dev/null", O_RDWR); 325 if (fd >= 0) { 326 dup2(fd, 0); 327 dup2(fd, 1); 328 dup2(fd, 2); 329 if (fd > 2) 330 close(fd); 331 } 332 333 uloop_end(); 334 335 execl(path, path, action, NULL); 336 exit(errno); 337 default: 338 c->ctx = ctx; 339 c->process.pid = pid; 340 c->process.cb = rc_init_cb; 341 uloop_process_add(&c->process); 342 343 ubus_defer_request(ctx, req, &c->req); 344 345 return 0; /* Deferred */ 346 } 347 } 348 349 int rpc_rc_api_init(struct ubus_context *ctx) 350 { 351 static const struct ubus_method rc_methods[] = { 352 UBUS_METHOD_NOARG("list", rc_list), 353 UBUS_METHOD("init", rc_init, rc_init_policy), 354 }; 355 356 static struct ubus_object_type rc_type = 357 UBUS_OBJECT_TYPE("rc", rc_methods); 358 359 static struct ubus_object obj = { 360 .name = "rc", 361 .type = &rc_type, 362 .methods = rc_methods, 363 .n_methods = ARRAY_SIZE(rc_methods), 364 }; 365 366 return ubus_add_object(ctx, &obj); 367 } 368
This page was automatically generated by LXR 0.3.1. • OpenWrt