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_LIST_NAME, 25 RC_LIST_SKIP_RUNNING_CHECK, 26 __RC_LIST_MAX 27 }; 28 29 static const struct blobmsg_policy rc_list_policy[] = { 30 [RC_LIST_NAME] = { "name", BLOBMSG_TYPE_STRING }, 31 [RC_LIST_SKIP_RUNNING_CHECK] = { "skip_running_check", BLOBMSG_TYPE_BOOL }, 32 }; 33 34 enum { 35 RC_INIT_NAME, 36 RC_INIT_ACTION, 37 __RC_INIT_MAX 38 }; 39 40 static const struct blobmsg_policy rc_init_policy[] = { 41 [RC_INIT_NAME] = { "name", BLOBMSG_TYPE_STRING }, 42 [RC_INIT_ACTION] = { "action", BLOBMSG_TYPE_STRING }, 43 }; 44 45 struct rc_list_context { 46 struct uloop_process process; 47 struct uloop_timeout timeout; 48 struct ubus_context *ctx; 49 struct ubus_request_data req; 50 struct blob_buf buf; 51 DIR *dir; 52 bool skip_running_check; 53 char *req_name; 54 55 /* Info about currently processed init.d entry */ 56 struct { 57 char path[PATH_MAX]; 58 const char *d_name; 59 int start; 60 int stop; 61 bool enabled; 62 bool running; 63 bool use_procd; 64 } entry; 65 }; 66 67 static void rc_list_readdir(struct rc_list_context *c); 68 69 /** 70 * rc_check_script - check if script is safe to execute as root 71 * 72 * Check if it's owned by root and if only root can modify it. 73 */ 74 static int rc_check_script(const char *path) 75 { 76 struct stat s; 77 78 if (stat(path, &s)) 79 return UBUS_STATUS_NOT_FOUND; 80 81 if (s.st_uid != 0 || s.st_gid != 0 || !(s.st_mode & S_IXUSR) || (s.st_mode & S_IWOTH)) 82 return UBUS_STATUS_PERMISSION_DENIED; 83 84 return UBUS_STATUS_OK; 85 } 86 87 static void rc_list_add_table(struct rc_list_context *c) 88 { 89 void *e; 90 91 e = blobmsg_open_table(&c->buf, c->entry.d_name); 92 93 if (c->entry.start >= 0) 94 blobmsg_add_u16(&c->buf, "start", c->entry.start); 95 if (c->entry.stop >= 0) 96 blobmsg_add_u16(&c->buf, "stop", c->entry.stop); 97 blobmsg_add_u8(&c->buf, "enabled", c->entry.enabled); 98 if (!c->skip_running_check && c->entry.use_procd) 99 blobmsg_add_u8(&c->buf, "running", c->entry.running); 100 101 blobmsg_close_table(&c->buf, e); 102 } 103 104 static void rpc_list_exec_timeout_cb(struct uloop_timeout *t) 105 { 106 struct rc_list_context *c = container_of(t, struct rc_list_context, timeout); 107 108 ULOG_WARN("Timeout waiting for %s\n", c->entry.path); 109 110 uloop_process_delete(&c->process); 111 kill(c->process.pid, SIGKILL); 112 /* uloop no longer tracks the process after uloop_process_delete(), so 113 * reap the killed child here to avoid leaving a zombie behind. */ 114 waitpid(c->process.pid, NULL, 0); 115 116 rc_list_readdir(c); 117 } 118 119 /** 120 * rc_exec - execute a file and call callback on complete 121 */ 122 static int rc_list_exec(struct rc_list_context *c, const char *action, uloop_process_handler cb) 123 { 124 pid_t pid; 125 int err; 126 int fd; 127 128 pid = fork(); 129 switch (pid) { 130 case -1: 131 return -errno; 132 case 0: 133 if (c->skip_running_check) 134 exit(-EFAULT); 135 136 if (!c->entry.use_procd) 137 exit(-EOPNOTSUPP); 138 139 /* Set stdin, stdout & stderr to /dev/null */ 140 fd = open("/dev/null", O_RDWR); 141 if (fd >= 0) { 142 dup2(fd, 0); 143 dup2(fd, 1); 144 dup2(fd, 2); 145 if (fd > 2) 146 close(fd); 147 } 148 149 uloop_end(); 150 151 execl(c->entry.path, c->entry.path, action, NULL); 152 exit(errno); 153 default: 154 c->process.pid = pid; 155 c->process.cb = cb; 156 157 err = uloop_process_add(&c->process); 158 if (err) 159 return err; 160 161 c->timeout.cb = rpc_list_exec_timeout_cb; 162 err = uloop_timeout_set(&c->timeout, RC_LIST_EXEC_TIMEOUT_MS); 163 if (err) { 164 uloop_process_delete(&c->process); 165 return err; 166 } 167 168 return 0; 169 } 170 } 171 172 static void rc_list_exec_running_cb(struct uloop_process *p, int stat) 173 { 174 struct rc_list_context *c = container_of(p, struct rc_list_context, process); 175 176 uloop_timeout_cancel(&c->timeout); 177 178 c->entry.running = !stat; 179 rc_list_add_table(c); 180 181 rc_list_readdir(c); 182 } 183 184 static void rc_list_readdir(struct rc_list_context *c) 185 { 186 struct dirent *e; 187 FILE *fp; 188 189 e = readdir(c->dir); 190 /* 191 * If scanning for a specific script and entry.d_name is set 192 * we can assume we found a matching one in the previous 193 * iteration since entry.d_name is set only if a match is found. 194 */ 195 if (!e || (c->req_name && c->entry.d_name)) { 196 closedir(c->dir); 197 ubus_send_reply(c->ctx, &c->req, c->buf.head); 198 ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK); 199 blob_buf_free(&c->buf); 200 free(c->req_name); 201 free(c); 202 return; 203 } 204 205 if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) 206 goto next; 207 208 if (c->req_name && strcmp(e->d_name, c->req_name)) 209 goto next; 210 211 memset(&c->entry, 0, sizeof(c->entry)); 212 c->entry.start = -1; 213 c->entry.stop = -1; 214 215 snprintf(c->entry.path, sizeof(c->entry.path), "/etc/init.d/%s", e->d_name); 216 if (rc_check_script(c->entry.path)) 217 goto next; 218 219 c->entry.d_name = e->d_name; 220 221 fp = fopen(c->entry.path, "r"); 222 if (fp) { 223 struct stat s; 224 char path[PATH_MAX]; 225 char line[255]; 226 bool beginning; 227 int count = 0; 228 229 beginning = true; 230 while ((c->entry.start < 0 || c->entry.stop < 0 || 231 (!c->skip_running_check && !c->entry.use_procd)) && 232 count <= 10 && fgets(line, sizeof(line), fp)) { 233 if (beginning) { 234 if (!strncmp(line, "START=", 6)) { 235 c->entry.start = strtoul(line + 6, NULL, 0); 236 } else if (!strncmp(line, "STOP=", 5)) { 237 c->entry.stop = strtoul(line + 5, NULL, 0); 238 } else if (!c->skip_running_check && !strncmp(line, "USE_PROCD=", 10)) { 239 c->entry.use_procd = !!strtoul(line + 10, NULL, 0); 240 } 241 count++; 242 } 243 244 beginning = !!strchr(line, '\n'); 245 } 246 fclose(fp); 247 248 if (c->entry.start >= 0) { 249 snprintf(path, sizeof(path), "/etc/rc.d/S%02d%s", c->entry.start, c->entry.d_name); 250 if (!stat(path, &s) && (s.st_mode & S_IXUSR)) 251 c->entry.enabled = true; 252 } 253 } 254 255 if (rc_list_exec(c, "running", rc_list_exec_running_cb)) 256 goto next; 257 258 return; 259 next: 260 rc_list_readdir(c); 261 } 262 263 /** 264 * rc_list - allocate listing context and start reading directory 265 */ 266 static int rc_list(struct ubus_context *ctx, struct ubus_object *obj, 267 struct ubus_request_data *req, const char *method, 268 struct blob_attr *msg) 269 { 270 struct blob_attr *tb[__RC_LIST_MAX]; 271 struct rc_list_context *c; 272 273 blobmsg_parse(rc_list_policy, __RC_LIST_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); 274 275 c = calloc(1, sizeof(*c)); 276 if (!c) 277 return UBUS_STATUS_UNKNOWN_ERROR; 278 279 c->ctx = ctx; 280 c->dir = opendir("/etc/init.d"); 281 if (!c->dir) { 282 free(c); 283 return UBUS_STATUS_UNKNOWN_ERROR; 284 } 285 286 blob_buf_init(&c->buf, 0); 287 288 if (tb[RC_LIST_SKIP_RUNNING_CHECK]) 289 c->skip_running_check = blobmsg_get_bool(tb[RC_LIST_SKIP_RUNNING_CHECK]); 290 /* Copy the requested name: msg (and the ctx receive buffer it points 291 * into) is only valid during this call, but req_name is dereferenced 292 * later from the deferred, asynchronous directory walk. */ 293 if (tb[RC_LIST_NAME]) 294 c->req_name = strdup(blobmsg_get_string(tb[RC_LIST_NAME])); 295 296 ubus_defer_request(ctx, req, &c->req); 297 298 rc_list_readdir(c); 299 300 return 0; /* Deferred */ 301 } 302 303 struct rc_init_context { 304 struct uloop_process process; 305 struct ubus_context *ctx; 306 struct ubus_request_data req; 307 }; 308 309 static void rc_init_cb(struct uloop_process *p, int stat) 310 { 311 struct rc_init_context *c = container_of(p, struct rc_init_context, process); 312 313 ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK); 314 315 free(c); 316 } 317 318 static int rc_init(struct ubus_context *ctx, struct ubus_object *obj, 319 struct ubus_request_data *req, const char *method, 320 struct blob_attr *msg) 321 { 322 struct blob_attr *tb[__RC_INIT_MAX]; 323 struct rc_init_context *c; 324 char path[PATH_MAX]; 325 const char *action; 326 const char *name; 327 const char *chr; 328 pid_t pid; 329 int err; 330 int fd; 331 332 blobmsg_parse(rc_init_policy, __RC_INIT_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); 333 334 if (!tb[RC_INIT_NAME] || !tb[RC_INIT_ACTION]) 335 return UBUS_STATUS_INVALID_ARGUMENT; 336 337 name = blobmsg_get_string(tb[RC_INIT_NAME]); 338 339 /* Validate script name */ 340 for (chr = name; (chr = strchr(chr, '.')); chr++) { 341 if (*(chr + 1) == '.') 342 return UBUS_STATUS_INVALID_ARGUMENT; 343 } 344 if (strchr(name, '/')) 345 return UBUS_STATUS_INVALID_ARGUMENT; 346 347 snprintf(path, sizeof(path), "/etc/init.d/%s", name); 348 349 /* Validate script privileges */ 350 err = rc_check_script(path); 351 if (err) 352 return err; 353 354 action = blobmsg_get_string(tb[RC_INIT_ACTION]); 355 if (strcmp(action, "disable") && 356 strcmp(action, "enable") && 357 strcmp(action, "stop") && 358 strcmp(action, "start") && 359 strcmp(action, "restart") && 360 strcmp(action, "reload")) 361 return UBUS_STATUS_INVALID_ARGUMENT; 362 363 c = calloc(1, sizeof(*c)); 364 if (!c) 365 return UBUS_STATUS_UNKNOWN_ERROR; 366 367 pid = fork(); 368 switch (pid) { 369 case -1: 370 free(c); 371 return UBUS_STATUS_UNKNOWN_ERROR; 372 case 0: 373 /* Set stdin, stdout & stderr to /dev/null */ 374 fd = open("/dev/null", O_RDWR); 375 if (fd >= 0) { 376 dup2(fd, 0); 377 dup2(fd, 1); 378 dup2(fd, 2); 379 if (fd > 2) 380 close(fd); 381 } 382 383 uloop_end(); 384 385 execl(path, path, action, NULL); 386 exit(errno); 387 default: 388 c->ctx = ctx; 389 c->process.pid = pid; 390 c->process.cb = rc_init_cb; 391 uloop_process_add(&c->process); 392 393 ubus_defer_request(ctx, req, &c->req); 394 395 return 0; /* Deferred */ 396 } 397 } 398 399 int rpc_rc_api_init(struct ubus_context *ctx) 400 { 401 static const struct ubus_method rc_methods[] = { 402 UBUS_METHOD("list", rc_list, rc_list_policy), 403 UBUS_METHOD("init", rc_init, rc_init_policy), 404 }; 405 406 static struct ubus_object_type rc_type = 407 UBUS_OBJECT_TYPE("rc", rc_methods); 408 409 static struct ubus_object obj = { 410 .name = "rc", 411 .type = &rc_type, 412 .methods = rc_methods, 413 .n_methods = ARRAY_SIZE(rc_methods), 414 }; 415 416 return ubus_add_object(ctx, &obj); 417 } 418
This page was automatically generated by LXR 0.3.1. • OpenWrt