1 /* 2 * rpcd - UBUS RPC server 3 * 4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <libubus.h> 20 21 #include <rpcd/exec.h> 22 #include <rpcd/plugin.h> 23 #include <rpcd/session.h> 24 #include <sys/reboot.h> 25 26 static const struct rpc_daemon_ops *ops; 27 28 enum { 29 RPC_P_USER, 30 RPC_P_PASSWORD, 31 __RPC_P_MAX 32 }; 33 34 static const struct blobmsg_policy rpc_password_policy[__RPC_P_MAX] = { 35 [RPC_P_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING }, 36 [RPC_P_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, 37 }; 38 39 enum { 40 RPC_UPGRADE_KEEP, 41 __RPC_UPGRADE_MAX 42 }; 43 44 static const struct blobmsg_policy rpc_upgrade_policy[__RPC_UPGRADE_MAX] = { 45 [RPC_UPGRADE_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, 46 }; 47 48 enum { 49 RPC_PACKAGELIST_ALL, 50 __RPC_PACKAGELIST_MAX 51 }; 52 53 static const struct blobmsg_policy rpc_packagelist_policy[__RPC_PACKAGELIST_MAX] = { 54 [RPC_PACKAGELIST_ALL] = { .name = "all", .type = BLOBMSG_TYPE_BOOL }, 55 }; 56 57 static int 58 rpc_errno_status(void) 59 { 60 switch (errno) 61 { 62 case EACCES: 63 return UBUS_STATUS_PERMISSION_DENIED; 64 65 case ENOTDIR: 66 return UBUS_STATUS_INVALID_ARGUMENT; 67 68 case ENOENT: 69 return UBUS_STATUS_NOT_FOUND; 70 71 case EINVAL: 72 return UBUS_STATUS_INVALID_ARGUMENT; 73 74 default: 75 return UBUS_STATUS_UNKNOWN_ERROR; 76 } 77 } 78 79 static int 80 rpc_cgi_password_set(struct ubus_context *ctx, struct ubus_object *obj, 81 struct ubus_request_data *req, const char *method, 82 struct blob_attr *msg) 83 { 84 pid_t pid; 85 int fd, fds[2]; 86 struct stat s; 87 struct blob_attr *tb[__RPC_P_MAX]; 88 ssize_t n; 89 int ret; 90 const char *const passwd = "/bin/passwd"; 91 const struct timespec ts = {0, 100 * 1000 * 1000}; 92 93 blobmsg_parse(rpc_password_policy, __RPC_P_MAX, tb, 94 blob_data(msg), blob_len(msg)); 95 96 if (!tb[RPC_P_USER] || !tb[RPC_P_PASSWORD]) 97 return UBUS_STATUS_INVALID_ARGUMENT; 98 99 if (stat(passwd, &s)) 100 return UBUS_STATUS_NOT_FOUND; 101 102 if (!(s.st_mode & S_IXUSR)) 103 return UBUS_STATUS_PERMISSION_DENIED; 104 105 if (pipe(fds)) 106 return rpc_errno_status(); 107 108 switch ((pid = fork())) 109 { 110 case -1: 111 close(fds[0]); 112 close(fds[1]); 113 return rpc_errno_status(); 114 115 case 0: 116 uloop_done(); 117 118 dup2(fds[0], 0); 119 close(fds[0]); 120 close(fds[1]); 121 122 if ((fd = open("/dev/null", O_RDWR)) > -1) 123 { 124 dup2(fd, 1); 125 dup2(fd, 2); 126 close(fd); 127 } 128 129 ret = chdir("/"); 130 if (ret < 0) 131 return rpc_errno_status(); 132 133 if (execl(passwd, passwd, 134 blobmsg_data(tb[RPC_P_USER]), NULL)) 135 return rpc_errno_status(); 136 137 default: 138 close(fds[0]); 139 140 n = write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]), 141 blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1); 142 if (n < 0) 143 return rpc_errno_status(); 144 145 n = write(fds[1], "\n", 1); 146 if (n < 0) 147 return rpc_errno_status(); 148 149 nanosleep(&ts, NULL); 150 151 n = write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]), 152 blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1); 153 if (n < 0) 154 return rpc_errno_status(); 155 n = write(fds[1], "\n", 1); 156 if (n < 0) 157 return rpc_errno_status(); 158 159 close(fds[1]); 160 161 waitpid(pid, NULL, 0); 162 163 return 0; 164 } 165 } 166 167 static int 168 rpc_sys_packagelist(struct ubus_context *ctx, struct ubus_object *obj, 169 struct ubus_request_data *req, const char *method, 170 struct blob_attr *msg) 171 { 172 struct blob_attr *tb[__RPC_PACKAGELIST_MAX]; 173 int all = false; 174 struct blob_buf buf = { 0 }; 175 char var[256], pkg[128] = { 0 }, ver[128] = { 0 }; 176 char *tmp, *p1, *p2, *p3; 177 void *tbl; 178 179 blobmsg_parse(rpc_packagelist_policy, __RPC_PACKAGELIST_MAX, tb, 180 blob_data(msg), blob_len(msg)); 181 182 if (tb[RPC_PACKAGELIST_ALL] && blobmsg_get_bool(tb[RPC_PACKAGELIST_ALL])) 183 all = true; 184 185 FILE *f = fopen("/usr/lib/opkg/status", "r"); 186 if (!f) 187 return UBUS_STATUS_NOT_FOUND; 188 189 blob_buf_init(&buf, 0); 190 tbl = blobmsg_open_table(&buf, "packages"); 191 pkg[0] = ver[0] = '\0'; 192 193 while(fgets(var, sizeof(var), f)) { 194 p1 = strchr(var, ' '); 195 p2 = p3 = NULL; 196 if (!p1) 197 goto procstr; 198 199 *p1++ = '\0'; 200 p2 = strchr(p1, ' '); 201 if (!p2) { 202 tmp = strchr(p1, '\n'); 203 if (tmp) 204 *tmp = '\0'; 205 goto procstr; 206 } 207 208 *p2++ = '\0'; 209 p3 = strchr(p2, ' '); 210 if (!p3) { 211 tmp = strchr(p2, '\n'); 212 if (tmp) 213 *tmp = '\0'; 214 goto procstr; 215 } 216 217 *p3++ = '\0'; 218 tmp = strchr(p3, '\n'); 219 if (tmp) 220 *tmp = '\0'; 221 222 procstr: 223 if (!p1) 224 continue; 225 226 if (!strcmp(var, "Package:")) { 227 strncpy(pkg, p1, sizeof(pkg) - 1); 228 continue; 229 } 230 231 /* If there is ABIVersion, remove that suffix */ 232 if (!strcmp(var, "ABIVersion:")) { 233 if (strlen(pkg) <= strlen(p1)) 234 continue; 235 tmp = &pkg[strlen(pkg) - strlen(p1)]; 236 if (strncmp(p1, tmp, strlen(p1))) 237 continue; 238 239 *tmp = '\0'; 240 continue; 241 } 242 243 if (!strcmp(var, "Version:")) { 244 strncpy(ver, p1, sizeof(ver) - 1); 245 continue; 246 } 247 248 if (p2 && p3 && 249 !strcmp(var, "Status:") && 250 !strcmp(p1, "install") && 251 (all || strstr(p2, "user")) && 252 !strcmp(p3, "installed") && pkg[0] && ver[0]) { 253 blobmsg_add_string(&buf, pkg, ver); 254 pkg[0] = ver[0] = '\0'; 255 } 256 } 257 258 blobmsg_close_table(&buf, tbl); 259 ubus_send_reply(ctx, req, buf.head); 260 blob_buf_free(&buf); 261 fclose(f); 262 263 return 0; 264 } 265 266 static int 267 rpc_sys_upgrade_test(struct ubus_context *ctx, struct ubus_object *obj, 268 struct ubus_request_data *req, const char *method, 269 struct blob_attr *msg) 270 { 271 const char *cmd[4] = { "sysupgrade", "--test", "/tmp/firmware.bin", NULL }; 272 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 273 } 274 275 static int 276 rpc_sys_upgrade_start(struct ubus_context *ctx, struct ubus_object *obj, 277 struct ubus_request_data *req, const char *method, 278 struct blob_attr *msg) 279 { 280 struct blob_attr *tb[__RPC_UPGRADE_MAX]; 281 char * const cmd[4] = { "/sbin/sysupgrade", "-n", "/tmp/firmware.bin", NULL }; 282 char * const cmd_keep[3] = { "/sbin/sysupgrade", "/tmp/firmware.bin", NULL }; 283 char * const * c = cmd; 284 285 blobmsg_parse(rpc_upgrade_policy, __RPC_UPGRADE_MAX, tb, 286 blob_data(msg), blob_len(msg)); 287 288 if (tb[RPC_UPGRADE_KEEP] && blobmsg_get_bool(tb[RPC_UPGRADE_KEEP])) 289 c = cmd_keep; 290 291 if (!fork()) { 292 /* wait for the RPC call to complete */ 293 sleep(2); 294 return execv(c[0], c); 295 } 296 297 return 0; 298 } 299 300 static int 301 rpc_sys_upgrade_clean(struct ubus_context *ctx, struct ubus_object *obj, 302 struct ubus_request_data *req, const char *method, 303 struct blob_attr *msg) 304 { 305 if (unlink("/tmp/firmware.bin")) 306 return rpc_errno_status(); 307 308 return 0; 309 } 310 311 static int 312 rpc_sys_factory(struct ubus_context *ctx, struct ubus_object *obj, 313 struct ubus_request_data *req, const char *method, 314 struct blob_attr *msg) 315 { 316 char * const cmd[4] = { "/sbin/jffs2reset", "-y", "-r", NULL }; 317 318 if (!fork()) { 319 /* wait for the RPC call to complete */ 320 sleep(2); 321 return execv(cmd[0], cmd); 322 } 323 324 return 0; 325 } 326 327 static int 328 rpc_sys_reboot(struct ubus_context *ctx, struct ubus_object *obj, 329 struct ubus_request_data *req, const char *method, 330 struct blob_attr *msg) 331 { 332 if (!fork()) { 333 sync(); 334 sleep(2); 335 reboot(RB_AUTOBOOT); 336 while (1) 337 ; 338 } 339 340 return 0; 341 } 342 343 static int 344 rpc_sys_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 345 { 346 static const struct ubus_method sys_methods[] = { 347 UBUS_METHOD("packagelist", rpc_sys_packagelist, rpc_packagelist_policy), 348 UBUS_METHOD("password_set", rpc_cgi_password_set, rpc_password_policy), 349 UBUS_METHOD_NOARG("upgrade_test", rpc_sys_upgrade_test), 350 UBUS_METHOD("upgrade_start", rpc_sys_upgrade_start, 351 rpc_upgrade_policy), 352 UBUS_METHOD_NOARG("upgrade_clean", rpc_sys_upgrade_clean), 353 UBUS_METHOD_NOARG("factory", rpc_sys_factory), 354 UBUS_METHOD_NOARG("reboot", rpc_sys_reboot), 355 }; 356 357 static struct ubus_object_type sys_type = 358 UBUS_OBJECT_TYPE("rpcd-plugin-sys", sys_methods); 359 360 static struct ubus_object obj = { 361 .name = "rpc-sys", 362 .type = &sys_type, 363 .methods = sys_methods, 364 .n_methods = ARRAY_SIZE(sys_methods), 365 }; 366 367 ops = o; 368 369 return ubus_add_object(ctx, &obj); 370 } 371 372 struct rpc_plugin rpc_plugin = { 373 .init = rpc_sys_api_init 374 }; 375
This page was automatically generated by LXR 0.3.1. • OpenWrt