2 * rpcd - UBUS RPC server
4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
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.
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.
22 #include <rpcd/exec.h>
23 #include <rpcd/plugin.h>
24 #include <rpcd/session.h>
25 #include <sys/reboot.h>
27 static const struct rpc_daemon_ops
*ops
;
35 static const struct blobmsg_policy rpc_password_policy
[__RPC_P_MAX
] = {
36 [RPC_P_USER
] = { .name
= "user", .type
= BLOBMSG_TYPE_STRING
},
37 [RPC_P_PASSWORD
] = { .name
= "password", .type
= BLOBMSG_TYPE_STRING
},
45 static const struct blobmsg_policy rpc_upgrade_policy
[__RPC_UPGRADE_MAX
] = {
46 [RPC_UPGRADE_KEEP
] = { .name
= "keep", .type
= BLOBMSG_TYPE_BOOL
},
54 static const struct blobmsg_policy rpc_packagelist_policy
[__RPC_PACKAGELIST_MAX
] = {
55 [RPC_PACKAGELIST_ALL
] = { .name
= "all", .type
= BLOBMSG_TYPE_BOOL
},
59 rpc_errno_status(void)
64 return UBUS_STATUS_PERMISSION_DENIED
;
67 return UBUS_STATUS_INVALID_ARGUMENT
;
70 return UBUS_STATUS_NOT_FOUND
;
73 return UBUS_STATUS_INVALID_ARGUMENT
;
76 return UBUS_STATUS_UNKNOWN_ERROR
;
81 rpc_cgi_password_set(struct ubus_context
*ctx
, struct ubus_object
*obj
,
82 struct ubus_request_data
*req
, const char *method
,
83 struct blob_attr
*msg
)
88 struct blob_attr
*tb
[__RPC_P_MAX
];
91 const char *const passwd
= "/bin/passwd";
92 const struct timespec ts
= {0, 100 * 1000 * 1000};
94 blobmsg_parse(rpc_password_policy
, __RPC_P_MAX
, tb
,
95 blob_data(msg
), blob_len(msg
));
97 if (!tb
[RPC_P_USER
] || !tb
[RPC_P_PASSWORD
])
98 return UBUS_STATUS_INVALID_ARGUMENT
;
100 if (stat(passwd
, &s
))
101 return UBUS_STATUS_NOT_FOUND
;
103 if (!(s
.st_mode
& S_IXUSR
))
104 return UBUS_STATUS_PERMISSION_DENIED
;
107 return rpc_errno_status();
109 switch ((pid
= fork()))
114 return rpc_errno_status();
123 if ((fd
= open("/dev/null", O_RDWR
)) > -1)
132 return rpc_errno_status();
134 if (execl(passwd
, passwd
,
135 blobmsg_data(tb
[RPC_P_USER
]), NULL
))
136 return rpc_errno_status();
141 n
= write(fds
[1], blobmsg_data(tb
[RPC_P_PASSWORD
]),
142 blobmsg_data_len(tb
[RPC_P_PASSWORD
]) - 1);
144 return rpc_errno_status();
146 n
= write(fds
[1], "\n", 1);
148 return rpc_errno_status();
150 nanosleep(&ts
, NULL
);
152 n
= write(fds
[1], blobmsg_data(tb
[RPC_P_PASSWORD
]),
153 blobmsg_data_len(tb
[RPC_P_PASSWORD
]) - 1);
155 return rpc_errno_status();
156 n
= write(fds
[1], "\n", 1);
158 return rpc_errno_status();
162 waitpid(pid
, NULL
, 0);
169 is_field(const char *type
, const char *line
)
171 return strncmp(line
, type
, strlen(type
)) == 0;
175 is_blank(const char *line
)
177 for (; *line
; line
++)
184 rpc_sys_packagelist(struct ubus_context
*ctx
, struct ubus_object
*obj
,
185 struct ubus_request_data
*req
, const char *method
,
186 struct blob_attr
*msg
)
188 struct blob_attr
*tb
[__RPC_PACKAGELIST_MAX
];
189 bool all
= false, installed
= false, auto_installed
= false;
190 struct blob_buf buf
= { 0 };
191 char line
[256], tmp
[128], pkg
[128], ver
[128];
195 blobmsg_parse(rpc_packagelist_policy
, __RPC_PACKAGELIST_MAX
, tb
,
196 blob_data(msg
), blob_len(msg
));
198 if (tb
[RPC_PACKAGELIST_ALL
] && blobmsg_get_bool(tb
[RPC_PACKAGELIST_ALL
]))
201 FILE *f
= fopen("/usr/lib/opkg/status", "r");
203 return UBUS_STATUS_NOT_FOUND
;
205 blob_buf_init(&buf
, 0);
206 tbl
= blobmsg_open_table(&buf
, "packages");
207 pkg
[0] = ver
[0] = '\0';
209 while (fgets(line
, sizeof(line
), f
)) {
212 if (is_field("ABIVersion", line
)) {
213 /* if there is ABIVersion, remove that suffix */
214 if (sscanf(line
, "ABIVersion: %127s", tmp
) == 1
215 && strlen(tmp
) < strlen(pkg
)) {
216 pkg_abi
= pkg
+ (strlen(pkg
) - strlen(tmp
));
217 if (strncmp(pkg_abi
, tmp
, strlen(tmp
)) == 0)
220 } else if (is_field("Auto-Installed", line
))
221 if (sscanf(line
, "Auto-Installed: %63s", tmp
) == 1)
222 auto_installed
= (strcmp(tmp
, "yes") == 0);
225 if (is_field("Package", line
))
226 if (sscanf(line
, "Package: %127s", pkg
) != 1)
230 if (is_field("Version", line
))
231 if (sscanf(line
, "Version: %127s", ver
) != 1)
235 if (is_field("Status", line
))
236 if (sscanf(line
, "Status: install %63s installed", tmp
) == 1)
240 if (is_blank(line
)) {
241 if (installed
&& (all
|| !auto_installed
) && pkg
[0] && ver
[0])
242 blobmsg_add_string(&buf
, pkg
, ver
);
243 pkg
[0] = ver
[0] = '\0';
244 installed
= auto_installed
= false;
250 blobmsg_close_table(&buf
, tbl
);
251 ubus_send_reply(ctx
, req
, buf
.head
);
259 rpc_sys_upgrade_test(struct ubus_context
*ctx
, struct ubus_object
*obj
,
260 struct ubus_request_data
*req
, const char *method
,
261 struct blob_attr
*msg
)
263 const char *cmd
[4] = { "sysupgrade", "--test", "/tmp/firmware.bin", NULL
};
264 return ops
->exec(cmd
, NULL
, NULL
, NULL
, NULL
, NULL
, ctx
, req
);
268 rpc_sys_upgrade_start(struct ubus_context
*ctx
, struct ubus_object
*obj
,
269 struct ubus_request_data
*req
, const char *method
,
270 struct blob_attr
*msg
)
272 struct blob_attr
*tb
[__RPC_UPGRADE_MAX
];
273 char * const cmd
[4] = { "/sbin/sysupgrade", "-n", "/tmp/firmware.bin", NULL
};
274 char * const cmd_keep
[3] = { "/sbin/sysupgrade", "/tmp/firmware.bin", NULL
};
275 char * const * c
= cmd
;
277 blobmsg_parse(rpc_upgrade_policy
, __RPC_UPGRADE_MAX
, tb
,
278 blob_data(msg
), blob_len(msg
));
280 if (tb
[RPC_UPGRADE_KEEP
] && blobmsg_get_bool(tb
[RPC_UPGRADE_KEEP
]))
284 /* wait for the RPC call to complete */
286 return execv(c
[0], c
);
293 rpc_sys_upgrade_clean(struct ubus_context
*ctx
, struct ubus_object
*obj
,
294 struct ubus_request_data
*req
, const char *method
,
295 struct blob_attr
*msg
)
297 if (unlink("/tmp/firmware.bin"))
298 return rpc_errno_status();
304 rpc_sys_factory(struct ubus_context
*ctx
, struct ubus_object
*obj
,
305 struct ubus_request_data
*req
, const char *method
,
306 struct blob_attr
*msg
)
308 char * const cmd
[4] = { "/sbin/jffs2reset", "-y", "-r", NULL
};
311 /* wait for the RPC call to complete */
313 return execv(cmd
[0], cmd
);
320 rpc_sys_reboot(struct ubus_context
*ctx
, struct ubus_object
*obj
,
321 struct ubus_request_data
*req
, const char *method
,
322 struct blob_attr
*msg
)
336 rpc_sys_api_init(const struct rpc_daemon_ops
*o
, struct ubus_context
*ctx
)
338 static const struct ubus_method sys_methods
[] = {
339 UBUS_METHOD("packagelist", rpc_sys_packagelist
, rpc_packagelist_policy
),
340 UBUS_METHOD("password_set", rpc_cgi_password_set
, rpc_password_policy
),
341 UBUS_METHOD_NOARG("upgrade_test", rpc_sys_upgrade_test
),
342 UBUS_METHOD("upgrade_start", rpc_sys_upgrade_start
,
344 UBUS_METHOD_NOARG("upgrade_clean", rpc_sys_upgrade_clean
),
345 UBUS_METHOD_NOARG("factory", rpc_sys_factory
),
346 UBUS_METHOD_NOARG("reboot", rpc_sys_reboot
),
349 static struct ubus_object_type sys_type
=
350 UBUS_OBJECT_TYPE("rpcd-plugin-sys", sys_methods
);
352 static struct ubus_object obj
= {
355 .methods
= sys_methods
,
356 .n_methods
= ARRAY_SIZE(sys_methods
),
361 return ubus_add_object(ctx
, &obj
);
364 struct rpc_plugin rpc_plugin
= {
365 .init
= rpc_sys_api_init