mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-02-22 21:43:07 +01:00
1086 lines
40 KiB
C
1086 lines
40 KiB
C
/*
|
|
Copyright (c) 2023 Roger Light <roger@atchoo.org>
|
|
|
|
All rights reserved. This program and the accompanying materials
|
|
are made available under the terms of the Eclipse Public License 2.0
|
|
and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
|
|
The Eclipse Public License is available at
|
|
https://www.eclipse.org/legal/epl-2.0/
|
|
and the Eclipse Distribution License is available at
|
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
|
|
|
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
|
|
|
Contributors:
|
|
Roger Light - initial implementation and documentation.
|
|
*/
|
|
#include <config.h>
|
|
|
|
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "ctrl_shell_internal.h"
|
|
#include "json_help.h"
|
|
|
|
#ifdef WITH_CTRL_SHELL
|
|
|
|
#define UNUSED(A) (void)(A)
|
|
|
|
static struct completion_tree_root *commands_dynsec = NULL;
|
|
static struct completion_tree_arg_list *tree_clients = NULL;
|
|
static struct completion_tree_arg_list *tree_groups = NULL;
|
|
static struct completion_tree_arg_list *tree_roles = NULL;
|
|
static bool do_print_list = false;
|
|
|
|
|
|
static void command_tree_create(void)
|
|
{
|
|
struct completion_tree_cmd *cmd;
|
|
struct completion_tree_arg_list *arg_list;
|
|
struct completion_tree_arg_list *help_arg_list;
|
|
|
|
completion_tree_arg_list_args_free(tree_clients);
|
|
completion_tree_arg_list_args_free(tree_groups);
|
|
completion_tree_arg_list_args_free(tree_roles);
|
|
|
|
if(commands_dynsec){
|
|
return;
|
|
}
|
|
|
|
commands_dynsec = calloc(1, sizeof(struct completion_tree_root));
|
|
|
|
if(!tree_clients){
|
|
tree_clients = completion_tree_cmd_new_arg_list();
|
|
tree_clients->is_shared = true;
|
|
}
|
|
|
|
if(!tree_groups){
|
|
tree_groups = completion_tree_cmd_new_arg_list();
|
|
tree_groups->is_shared = true;
|
|
}
|
|
|
|
if(!tree_roles){
|
|
tree_roles = completion_tree_cmd_new_arg_list();
|
|
tree_roles->is_shared = true;
|
|
}
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, NULL, "help");
|
|
help_arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "addClientRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "addGroupClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "addGroupRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "addRoleACL");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientReceive");
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientSend");
|
|
completion_tree_arg_list_add_arg(arg_list, "subscribeLiteral");
|
|
completion_tree_arg_list_add_arg(arg_list, "subscribePattern");
|
|
completion_tree_arg_list_add_arg(arg_list, "unsubscribeLiteral");
|
|
completion_tree_arg_list_add_arg(arg_list, "unsubscribePattern");
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "allow");
|
|
completion_tree_arg_list_add_arg(arg_list, "deny");
|
|
}
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "createClient");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "createGroup");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "createRole");
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "deleteClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "deleteGroup");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "deleteRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "disableClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "enableClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "getAnonymousGroup");
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "getDetails");
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "getClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "getDefaultACLAccess");
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "getGroup");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "getRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "listClients");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "listGroups");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "listRoles");
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "removeClientRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "removeGroupClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "removeGroupRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "removeRoleACL");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientReceive");
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientSend");
|
|
completion_tree_arg_list_add_arg(arg_list, "subscribeLiteral");
|
|
completion_tree_arg_list_add_arg(arg_list, "subscribePattern");
|
|
completion_tree_arg_list_add_arg(arg_list, "unsubscribeLiteral");
|
|
completion_tree_arg_list_add_arg(arg_list, "unsubscribePattern");
|
|
}
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "setAnonymousGroup");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "setClientId");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "setClientPassword");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "modifyClient");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_clients);
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "textName");
|
|
completion_tree_arg_list_add_arg(arg_list, "textDescription");
|
|
}
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "modifyGroup");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_groups);
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "textName");
|
|
completion_tree_arg_list_add_arg(arg_list, "textDescription");
|
|
}
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "modifyRole");
|
|
completion_tree_cmd_append_arg_list(cmd, tree_roles);
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "allowWildcardSubs");
|
|
completion_tree_arg_list_add_arg(arg_list, "textName");
|
|
completion_tree_arg_list_add_arg(arg_list, "textDescription");
|
|
}
|
|
|
|
{
|
|
cmd = completion_tree_cmd_add(commands_dynsec, help_arg_list, "setDefaultACLAccess");
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientReceive");
|
|
completion_tree_arg_list_add_arg(arg_list, "publishClientSend");
|
|
completion_tree_arg_list_add_arg(arg_list, "subscribe");
|
|
completion_tree_arg_list_add_arg(arg_list, "unsubscribe");
|
|
|
|
arg_list = completion_tree_cmd_add_arg_list(cmd);
|
|
completion_tree_arg_list_add_arg(arg_list, "allow");
|
|
completion_tree_arg_list_add_arg(arg_list, "deny");
|
|
}
|
|
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "disconnect");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "return");
|
|
completion_tree_cmd_add(commands_dynsec, help_arg_list, "exit");
|
|
}
|
|
|
|
|
|
static void print_help(char **saveptr)
|
|
{
|
|
char *command = strtok_r(NULL, " ", saveptr);
|
|
if(command){
|
|
if(!strcasecmp(command, "addClientRole")){
|
|
ctrl_shell_print_help_command("addClientRole <username> <rolename>");
|
|
ctrl_shell_printf("\nAdds a role directly to a client.\n");
|
|
}else if(!strcasecmp(command, "addGroupClient")){
|
|
ctrl_shell_print_help_command("addGroupClient <groupname> <username>");
|
|
ctrl_shell_printf("\nAdds a client to a group.\n");
|
|
}else if(!strcasecmp(command, "addGroupRole")){
|
|
ctrl_shell_print_help_command("addGroupRole <groupname> <rolename>");
|
|
ctrl_shell_printf("\nAdds a role to a group.\n");
|
|
}else if(!strcasecmp(command, "addRoleACL")){
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> publishClientReceive allow|deny [priority] <topic>");
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> publishClientSend allow|deny [priority] <topic>");
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> subscribeLiteral allow|deny [priority] <topic>");
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> subscribePattern allow|deny [priority] <topic>");
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> unsubscribeLiteral allow|deny [priority] <topic>");
|
|
ctrl_shell_print_help_command("addRoleACL <rolename> unsubscribePattern allow|deny [priority] <topic>");
|
|
ctrl_shell_printf("\nAdds an ACL to a role, with an optional priority.\n");
|
|
ctrl_shell_printf("\nACLs of a specific type within a role are processed in order from highest to lowest priority with the first matching ACL applying.\n");
|
|
}else if(!strcasecmp(command, "createClient")){
|
|
ctrl_shell_print_help_command("createClient <username> [password [clientid]]");
|
|
ctrl_shell_printf("\nCreate a client with password and optional client id.\n");
|
|
}else if(!strcasecmp(command, "createGroup")){
|
|
ctrl_shell_print_help_command("createGroup <groupname>");
|
|
ctrl_shell_printf("\nCreate a new group.\n");
|
|
}else if(!strcasecmp(command, "createRole")){
|
|
ctrl_shell_print_help_command("createRole <rolename>");
|
|
ctrl_shell_printf("\nCreate a new role.\n");
|
|
}else if(!strcasecmp(command, "deleteClient")){
|
|
ctrl_shell_print_help_command("deleteClient <username>");
|
|
ctrl_shell_printf("\nDelete a client\n");
|
|
}else if(!strcasecmp(command, "deleteGroup")){
|
|
ctrl_shell_print_help_command("deleteGroup <groupname>");
|
|
ctrl_shell_printf("\nDelete a group\n");
|
|
}else if(!strcasecmp(command, "deleteRole")){
|
|
ctrl_shell_print_help_command("deleteRole <rolename>");
|
|
ctrl_shell_printf("\nDelete a role\n");
|
|
}else if(!strcasecmp(command, "disableClient")){
|
|
ctrl_shell_print_help_command("disableClient <username>");
|
|
ctrl_shell_printf("\nDisable a client. This client will not be able to log in, and will be kicked if it has an existing session.\n");
|
|
}else if(!strcasecmp(command, "enableClient")){
|
|
ctrl_shell_print_help_command("enableClient <username>");
|
|
ctrl_shell_printf("\nEnable a client. Disabled clients are unable to log in.\n");
|
|
}else if(!strcasecmp(command, "getAnonymousGroup")){
|
|
ctrl_shell_print_help_command("getAnonymousGroup");
|
|
ctrl_shell_printf("\nPrint the group configured as the anonymous group.\n");
|
|
}else if(!strcasecmp(command, "getDetails")){
|
|
ctrl_shell_print_help_command("getDetails");
|
|
ctrl_shell_printf("\nPrint details including the client, group, and role count, and the current change index.\n");
|
|
}else if(!strcasecmp(command, "getClient")){
|
|
ctrl_shell_print_help_command("getClient <username>");
|
|
ctrl_shell_printf("\nPrint details of a client and its groups and direct roles.\n");
|
|
}else if(!strcasecmp(command, "getDefaultACLAccess")){
|
|
ctrl_shell_print_help_command("getDefaultACLAccess");
|
|
ctrl_shell_printf("\nPrint the default allow/deny values for the different classes of ACL.\n");
|
|
}else if(!strcasecmp(command, "getGroup")){
|
|
ctrl_shell_print_help_command("getGroup <groupname>");
|
|
ctrl_shell_printf("\nPrint details of a group and its roles.\n");
|
|
}else if(!strcasecmp(command, "getRole")){
|
|
ctrl_shell_print_help_command("getRole <rolename>");
|
|
ctrl_shell_printf("\nPrint details of a role and its ACLs.\n");
|
|
}else if(!strcasecmp(command, "listClients")){
|
|
ctrl_shell_print_help_command("listClients [count [offset]]");
|
|
ctrl_shell_printf("\nPrint a list of clients configured in the dynsec plugin, with an optional total count and list offset.\n");
|
|
}else if(!strcasecmp(command, "listGroups")){
|
|
ctrl_shell_print_help_command("listGroups [count [offset]]");
|
|
ctrl_shell_printf("\nPrint a list of groups configured in the dynsec plugin, with an optional total count and list offset.\n");
|
|
}else if(!strcasecmp(command, "listRoles")){
|
|
ctrl_shell_print_help_command("listRoles [count [offset]]");
|
|
ctrl_shell_printf("\nPrint a list of roles configured in the dynsec plugin, with an optional total count and list offset.\n");
|
|
}else if(!strcasecmp(command, "removeClientRole")){
|
|
ctrl_shell_print_help_command("removeClientRole <username> <rolename>");
|
|
ctrl_shell_printf("\nRemoves a role from a client, where the role was directly attached to the client.\n");
|
|
}else if(!strcasecmp(command, "removeGroupClient")){
|
|
ctrl_shell_print_help_command("removeGroupClient <groupname> <username>");
|
|
ctrl_shell_printf("\nRemoves a client from a group.\n");
|
|
}else if(!strcasecmp(command, "removeGroupRole")){
|
|
ctrl_shell_print_help_command("removeGroupRole <groupname> <rolename>");
|
|
ctrl_shell_printf("\nRemoves a role from a group.\n");
|
|
}else if(!strcasecmp(command, "removeRoleACL")){
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> publishClientReceive <topic>");
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> publishClientSend <topic>");
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> subscribeLiteral <topic>");
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> subscribePattern <topic>");
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> unsubscribeLiteral <topic>");
|
|
ctrl_shell_print_help_command("removeRoleACL <rolename> unsubscribePattern <topic>");
|
|
ctrl_shell_printf("\nRemoves an ACL from a role.\n");
|
|
}else if(!strcasecmp(command, "setAnonymousGroup")){
|
|
ctrl_shell_print_help_command("setAnonymousGroup <groupname>");
|
|
ctrl_shell_printf("\nSets the anonymous group to a new group.\n");
|
|
}else if(!strcasecmp(command, "setClientId")){
|
|
ctrl_shell_print_help_command("setClientId <username>");
|
|
ctrl_shell_print_help_command("setClientId <username> <clientid>");
|
|
ctrl_shell_printf("\nSets or clears the clientid associated with a client. If a client has a clientid, all three of username, password, and clientid must match for a client to be able to authenticate.\n");
|
|
}else if(!strcasecmp(command, "setClientPassword")){
|
|
ctrl_shell_print_help_command("setClientPassword <username> [password]");
|
|
ctrl_shell_printf("\nSets a new password for a client.\n");
|
|
}else if(!strcasecmp(command, "setDefaultACLAccess")){
|
|
ctrl_shell_print_help_command("setDefaultACLAccess publishClientReceive allow|deny");
|
|
ctrl_shell_print_help_command("setDefaultACLAccess publishClientSend allow|deny");
|
|
ctrl_shell_print_help_command("setDefaultACLAccess subscribe allow|deny");
|
|
ctrl_shell_print_help_command("setDefaultACLAccess unsubscribe allow|deny");
|
|
ctrl_shell_printf("\nSets the default ACL access to use for an ACL type. The default access will be applied if no other ACL rules match.\n");
|
|
ctrl_shell_printf("Setting a rule to 'allow' means that if no ACLs match, it will be accepted.\n");
|
|
ctrl_shell_printf("Setting a rule to 'deny' means that if no ACLs match, it will be denied.\n");
|
|
}else if(!strcasecmp(command, "modifyClient")){
|
|
ctrl_shell_print_help_command("modifyClient <username> textName <textname>");
|
|
ctrl_shell_print_help_command("modifyClient <username> textDescription <textdescription>");
|
|
ctrl_shell_printf("\nModify the text name or text description for a client.\n");
|
|
ctrl_shell_printf("These are free-text fields for your own use.\n");
|
|
}else if(!strcasecmp(command, "modifyGroup")){
|
|
ctrl_shell_print_help_command("modifyGroup <groupname> textName <textname>");
|
|
ctrl_shell_print_help_command("modifyGroup <groupname> textDescription <textdescription>");
|
|
ctrl_shell_printf("\nModify the text name or text description for a group.\n");
|
|
ctrl_shell_printf("These are free-text fields for your own use.\n");
|
|
}else if(!strcasecmp(command, "modifyRole")){
|
|
ctrl_shell_print_help_command("modifyRole <rolename> allowWildcardSubs true|false");
|
|
ctrl_shell_print_help_command("modifyRole <rolename> textName <textname>");
|
|
ctrl_shell_print_help_command("modifyRole <rolename> textDescription <textdescription>");
|
|
ctrl_shell_printf("\nModify the text name or text description for a role.\n");
|
|
ctrl_shell_printf("These are free-text fields for your own use.\n");
|
|
}else{
|
|
ctrl_shell_print_help_final(command, "dynsec");
|
|
}
|
|
}else{
|
|
ctrl_shell_printf("This is the mosquitto_ctrl interactive shell, for controlling aspects of a mosquitto broker.\n");
|
|
ctrl_shell_printf("You are in dynsec mode, for controlling the dynamic-security clients, groups, and roles used in authentication and authorisation.\n");
|
|
ctrl_shell_printf("Use '%sreturn%s' to leave dynsec mode.\n", ANSI_INPUT, ANSI_RESET);
|
|
|
|
ctrl_shell_printf("Find help on a command using '%shelp <command>%s'\n", ANSI_INPUT, ANSI_RESET);
|
|
ctrl_shell_printf("Press tab multiple times to find currently available commands.\n\n");
|
|
}
|
|
}
|
|
|
|
|
|
static int send_set_default_acl_access(char **saveptr)
|
|
{
|
|
const char *acltype, *allow_s;
|
|
|
|
acltype = strtok_r(NULL, " ", saveptr);
|
|
if(!acltype ||
|
|
(
|
|
strcasecmp(acltype, "publishClientReceive")
|
|
&& strcasecmp(acltype, "publishClientSend")
|
|
&& strcasecmp(acltype, "subscribe")
|
|
&& strcasecmp(acltype, "unsubscribe")
|
|
)){
|
|
ctrl_shell_printf("setDefaultACLAccess acltype allow|deny\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
allow_s = strtok_r(NULL, " ", saveptr);
|
|
if(!allow_s ||
|
|
(
|
|
strcasecmp(allow_s, "allow")
|
|
&& strcasecmp(allow_s, "deny")
|
|
)){
|
|
ctrl_shell_printf("setDefaultACLAccess acltype allow|deny\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", "setDefaultACLAccess");
|
|
cJSON *j_acls = cJSON_AddArrayToObject(j_command, "acls");
|
|
cJSON *j_acl = cJSON_CreateObject();
|
|
cJSON_AddItemToArray(j_acls, j_acl);
|
|
cJSON_AddStringToObject(j_acl, "acltype", acltype);
|
|
cJSON_AddBoolToObject(j_acl, "allow", !strcmp(allow_s, "allow"));
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static int list_update(const char *command)
|
|
{
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", command);
|
|
|
|
do_print_list = false;
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static int list_generic(const char *command, char **saveptr)
|
|
{
|
|
const char *count, *offset;
|
|
|
|
count = strtok_r(NULL, " ", saveptr);
|
|
offset = strtok_r(NULL, " ", saveptr);
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", command);
|
|
if(count){
|
|
cJSON_AddNumberToObject(j_command, "count", atoi(count));
|
|
}
|
|
if(offset){
|
|
cJSON_AddNumberToObject(j_command, "offset", atoi(offset));
|
|
}
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static int send_create_client(char **saveptr)
|
|
{
|
|
char *username = strtok_r(NULL, " ", saveptr);
|
|
if(!username){
|
|
ctrl_shell_printf("createClient username [password [clientid]]\n");
|
|
ctrl_shell_printf("createClient username password [clientid]\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
char *password = strtok_r(NULL, " ", saveptr);
|
|
char pwbuf1[200];
|
|
char pwbuf2[200];
|
|
char *clientid = NULL;
|
|
if(password){
|
|
clientid = strtok_r(NULL, " ", saveptr);
|
|
}else{
|
|
if(!ctrl_shell_get_password(pwbuf1, sizeof(pwbuf1))
|
|
|| !ctrl_shell_get_password(pwbuf2, sizeof(pwbuf2))){
|
|
|
|
ctrl_shell_printf("No password.\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcmp(pwbuf1, pwbuf2)){
|
|
ctrl_shell_printf("Passwords do not match.\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
password = pwbuf1;
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", "createClient");
|
|
cJSON_AddStringToObject(j_command, "username", username);
|
|
cJSON_AddStringToObject(j_command, "password", password);
|
|
if(clientid){
|
|
cJSON_AddStringToObject(j_command, "clientid", clientid);
|
|
}
|
|
ctrl_shell_publish_blocking(j_command);
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
}
|
|
|
|
|
|
static int send_add_role_acl(char **saveptr)
|
|
{
|
|
char *rolename = strtok_r(NULL, " ", saveptr);
|
|
char *acltype = strtok_r(NULL, " ", saveptr);
|
|
char *allow_s = strtok_r(NULL, " ", saveptr);
|
|
char *s_priority = strtok_r(NULL, " ", saveptr);
|
|
char *topic = strtok_r(NULL, " ", saveptr);
|
|
int priority = -1;
|
|
|
|
if(s_priority){
|
|
if(topic){
|
|
priority = atoi(s_priority);
|
|
}else{
|
|
topic = s_priority;
|
|
}
|
|
}
|
|
|
|
if(!rolename || !acltype || !allow_s || !topic){
|
|
ctrl_shell_printf("addRoleACL rolename acltype allow|deny [priority] topic\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcasecmp(acltype, "publishClientReceive")
|
|
&& strcasecmp(acltype, "publishClientSend")
|
|
&& strcasecmp(acltype, "subscribeLiteral")
|
|
&& strcasecmp(acltype, "subscribePattern")
|
|
&& strcasecmp(acltype, "unsubscribeLiteral")
|
|
&& strcasecmp(acltype, "unsubscribePattern")
|
|
){
|
|
|
|
ctrl_shell_printf("addRoleACL rolename acltype allow|deny [priority] topic\n");
|
|
ctrl_shell_printf("Invalid acltype '%s'\n", acltype);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcasecmp(allow_s, "allow") && strcasecmp(allow_s, "deny")){
|
|
ctrl_shell_printf("addRoleACL rolename acltype allow|deny [priority] topic\n");
|
|
ctrl_shell_printf("Invalid allow/deny '%s'\n", allow_s);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", "addRoleACL");
|
|
cJSON_AddStringToObject(j_command, "rolename", rolename);
|
|
cJSON_AddStringToObject(j_command, "acltype", acltype);
|
|
cJSON_AddNumberToObject(j_command, "priority", priority);
|
|
cJSON_AddStringToObject(j_command, "topic", topic);
|
|
cJSON_AddBoolToObject(j_command, "allow", !strcasecmp(allow_s, "allow"));
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static int send_remove_role_acl(char **saveptr)
|
|
{
|
|
char *rolename = strtok_r(NULL, " ", saveptr);
|
|
char *acltype = strtok_r(NULL, " ", saveptr);
|
|
char *topic = strtok_r(NULL, " ", saveptr);
|
|
|
|
if(!rolename || !acltype || !topic){
|
|
ctrl_shell_printf("removeRoleACL rolename acltype topic\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcasecmp(acltype, "publishClientReceive")
|
|
&& strcasecmp(acltype, "publishClientSend")
|
|
&& strcasecmp(acltype, "subscribeLiteral")
|
|
&& strcasecmp(acltype, "subscribePattern")
|
|
&& strcasecmp(acltype, "unsubscribeLiteral")
|
|
&& strcasecmp(acltype, "unsubscribePattern")
|
|
){
|
|
|
|
|
|
ctrl_shell_printf("removeRoleACL rolename acltype topic\n");
|
|
ctrl_shell_printf("Invalid acltype '%s'\n", acltype);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", "removeRoleACL");
|
|
cJSON_AddStringToObject(j_command, "rolename", rolename);
|
|
cJSON_AddStringToObject(j_command, "acltype", acltype);
|
|
cJSON_AddStringToObject(j_command, "topic", topic);
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
|
|
}
|
|
|
|
|
|
static int send_modify(const char *command, const char *objectname, char **saveptr)
|
|
{
|
|
char *name = strtok_r(NULL, " ", saveptr);
|
|
char *itemlabel = strtok_r(NULL, " ", saveptr);
|
|
char *itemvalue = *saveptr;
|
|
if(!name || !itemlabel || !itemvalue){
|
|
ctrl_shell_printf("%s %s <property> <value>\n", command, objectname);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcasecmp(itemlabel, "textName") && strcasecmp(itemlabel, "textDescription") && strcasecmp(itemlabel, "allowWildcardSubs")){
|
|
ctrl_shell_printf("%s %s <property> <value>\n", command, objectname);
|
|
ctrl_shell_printf("Unknown property '%s'\n", itemlabel);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(!strcasecmp(itemlabel, "allowWildcardSubs")){
|
|
if(strcasecmp(itemvalue, "true") && strcasecmp(itemvalue, "false")){
|
|
ctrl_shell_printf("%s %s <property> <value>\n", command, objectname);
|
|
ctrl_shell_printf("Invalid value '%s'\n", itemvalue);
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", command);
|
|
cJSON_AddStringToObject(j_command, objectname, name);
|
|
if(!strcasecmp(itemlabel, "allowWildcardSubs")){
|
|
cJSON_AddBoolToObject(j_command, itemlabel, !strcasecmp(itemvalue, "true"));
|
|
}else{
|
|
cJSON_AddStringToObject(j_command, itemlabel, itemvalue);
|
|
}
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static int send_set_client_password(char **saveptr)
|
|
{
|
|
char *username, *password;
|
|
char pwbuf1[200], pwbuf2[200];
|
|
|
|
username = strtok_r(NULL, " ", saveptr);
|
|
if(!username){
|
|
ctrl_shell_printf("setClientPassword <username> [password]\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
password = strtok_r(NULL, " ", saveptr);
|
|
if(!password){
|
|
if(!ctrl_shell_get_password(pwbuf1, sizeof(pwbuf1))
|
|
|| !ctrl_shell_get_password(pwbuf2, sizeof(pwbuf2))){
|
|
|
|
ctrl_shell_printf("No password.\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
if(strcmp(pwbuf1, pwbuf2)){
|
|
ctrl_shell_printf("Passwords do not match.\n");
|
|
return MOSQ_ERR_INVAL;
|
|
}
|
|
|
|
password = pwbuf1;
|
|
}
|
|
|
|
cJSON *j_command = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(j_command, "command", "setClientPassword");
|
|
cJSON_AddStringToObject(j_command, "username", username);
|
|
cJSON_AddStringToObject(j_command, "password", password);
|
|
|
|
return ctrl_shell_publish_blocking(j_command);
|
|
}
|
|
|
|
|
|
static void line_callback(char *line)
|
|
{
|
|
if(!line){
|
|
ctrl_shell_callback_final(NULL);
|
|
return;
|
|
}
|
|
ctrl_shell_rtrim(line);
|
|
if(strlen(line) > 0){
|
|
add_history(line);
|
|
}else{
|
|
free(line);
|
|
return;
|
|
}
|
|
|
|
char *saveptr = NULL;
|
|
char *command = strtok_r(line, " ", &saveptr);
|
|
|
|
if(!command){
|
|
free(line);
|
|
return;
|
|
}
|
|
|
|
if(!strcasecmp(command, "addClientRole")){
|
|
ctrl_shell_command_generic_arg2("addClientRole", "username", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "addGroupClient")){
|
|
ctrl_shell_command_generic_arg2("addGroupClient", "groupname", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "addGroupRole")){
|
|
ctrl_shell_command_generic_arg2("addGroupRole", "groupname", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "addRoleACL")){
|
|
send_add_role_acl(&saveptr);
|
|
}else if(!strcasecmp(command, "createClient")){
|
|
if(send_create_client(&saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listClients");
|
|
}
|
|
}else if(!strcasecmp(command, "createGroup")){
|
|
if(ctrl_shell_command_generic_arg1("createGroup", "groupname", &saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listGroups");
|
|
}
|
|
}else if(!strcasecmp(command, "createRole")){
|
|
if(ctrl_shell_command_generic_arg1("createRole", "rolename", &saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listRoles");
|
|
}
|
|
}else if(!strcasecmp(command, "deleteClient")){
|
|
if(ctrl_shell_command_generic_arg1("deleteClient", "username", &saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listClients");
|
|
}
|
|
}else if(!strcasecmp(command, "deleteGroup")){
|
|
if(ctrl_shell_command_generic_arg1("deleteGroup", "groupname", &saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listGroups");
|
|
}
|
|
}else if(!strcasecmp(command, "deleteRole")){
|
|
if(ctrl_shell_command_generic_arg1("deleteRole", "rolename", &saveptr) == MOSQ_ERR_SUCCESS){
|
|
list_update("listRoles");
|
|
}
|
|
}else if(!strcasecmp(command, "disableClient")){
|
|
ctrl_shell_command_generic_arg1("disableClient", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "enableClient")){
|
|
ctrl_shell_command_generic_arg1("enableClient", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "getAnonymousGroup")){
|
|
ctrl_shell_command_generic_arg0("getAnonymousGroup");
|
|
}else if(!strcasecmp(command, "getDetails")){
|
|
ctrl_shell_command_generic_arg0("getDetails");
|
|
}else if(!strcasecmp(command, "getClient")){
|
|
ctrl_shell_command_generic_arg1("getClient", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "getDefaultACLAccess")){
|
|
ctrl_shell_command_generic_arg0("getDefaultACLAccess");
|
|
}else if(!strcasecmp(command, "getGroup")){
|
|
ctrl_shell_command_generic_arg1("getGroup", "groupname", &saveptr);
|
|
}else if(!strcasecmp(command, "getRole")){
|
|
ctrl_shell_command_generic_arg1("getRole", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "listClients")){
|
|
do_print_list = true;
|
|
list_generic("listClients", &saveptr);
|
|
}else if(!strcasecmp(command, "listGroups")){
|
|
do_print_list = true;
|
|
list_generic("listGroups", &saveptr);
|
|
}else if(!strcasecmp(command, "listRoles")){
|
|
do_print_list = true;
|
|
list_generic("listRoles", &saveptr);
|
|
}else if(!strcasecmp(command, "removeClientRole")){
|
|
ctrl_shell_command_generic_arg2("removeClientRole", "username", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "removeGroupClient")){
|
|
ctrl_shell_command_generic_arg2("removeGroupClient", "groupname", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "removeGroupRole")){
|
|
ctrl_shell_command_generic_arg2("removeGroupRole", "groupname", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "removeRoleACL")){
|
|
send_remove_role_acl(&saveptr);
|
|
}else if(!strcasecmp(command, "setAnonymousGroup")){
|
|
ctrl_shell_command_generic_arg1("setAnonymousGroup", "groupname", &saveptr);
|
|
}else if(!strcasecmp(command, "setClientId")){
|
|
ctrl_shell_command_generic_arg2("setClientId", "username", "clientid", &saveptr);
|
|
}else if(!strcasecmp(command, "setClientPassword")){
|
|
send_set_client_password(&saveptr);
|
|
}else if(!strcasecmp(command, "modifyClient")){
|
|
send_modify("modifyClient", "username", &saveptr);
|
|
}else if(!strcasecmp(command, "modifyGroup")){
|
|
send_modify("modifyGroup", "groupname", &saveptr);
|
|
}else if(!strcasecmp(command, "modifyRole")){
|
|
send_modify("modifyRole", "rolename", &saveptr);
|
|
}else if(!strcasecmp(command, "setDefaultACLAccess")){
|
|
send_set_default_acl_access(&saveptr);
|
|
}else if(!strcasecmp(command, "help")){
|
|
print_help(&saveptr);
|
|
}else{
|
|
if(!ctrl_shell_callback_final(line)){
|
|
ctrl_shell_printf("Unknown command '%s'\n", command);
|
|
}
|
|
}
|
|
|
|
free(line);
|
|
}
|
|
|
|
|
|
static void print_json_value(cJSON *value, const char *null_value)
|
|
{
|
|
if(value){
|
|
if(cJSON_IsString(value)){
|
|
if(value->valuestring){
|
|
ctrl_shell_print_value(0, "%s", value->valuestring);
|
|
}
|
|
}else{
|
|
char buffer[1024];
|
|
cJSON_PrintPreallocated(value, buffer, sizeof(buffer), 0);
|
|
ctrl_shell_print_value(0, "%s", buffer);
|
|
}
|
|
}else if(null_value){
|
|
ctrl_shell_print_value(0, "%s", null_value);
|
|
}
|
|
}
|
|
|
|
|
|
static void print_json_array(cJSON *j_list, const char *label, const char *element_name, const char *optional_element_name, const char *optional_element_null_value)
|
|
{
|
|
cJSON *j_elem;
|
|
|
|
if(j_list && cJSON_IsArray(j_list) && cJSON_GetArraySize(j_list) > 0){
|
|
ctrl_shell_print_label(0, label);
|
|
cJSON_ArrayForEach(j_elem, j_list){
|
|
if(cJSON_IsObject(j_elem)){
|
|
const char *stmp;
|
|
if(json_get_string(j_elem, element_name, &stmp, false) != MOSQ_ERR_SUCCESS){
|
|
continue;
|
|
}
|
|
ctrl_shell_print_value(1, "%s", stmp);
|
|
if(optional_element_name){
|
|
ctrl_shell_print_value(0, " (%s: ", optional_element_name);
|
|
print_json_value(cJSON_GetObjectItem(j_elem, optional_element_name), optional_element_null_value);
|
|
ctrl_shell_print_value(0, ")");
|
|
}
|
|
}else if(cJSON_IsString(j_elem) && j_elem->valuestring){
|
|
ctrl_shell_print_value(1, "%s", j_elem->valuestring);
|
|
}
|
|
ctrl_shell_print_value(0, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void print_details(cJSON *j_data)
|
|
{
|
|
int64_t clientcount;
|
|
int64_t groupcount;
|
|
int64_t rolecount;
|
|
int64_t changeindex;
|
|
int align = (int)strlen("Change index: ");
|
|
json_get_int64(j_data, "clientCount", &clientcount, true, 0);
|
|
json_get_int64(j_data, "groupCount", &groupcount, true, 0);
|
|
json_get_int64(j_data, "roleCount", &rolecount, true, 0);
|
|
json_get_int64(j_data, "changeIndex", &changeindex, true, 0);
|
|
|
|
ctrl_shell_print_label_value(0, "Client count:", align, "%ld\n", clientcount);
|
|
ctrl_shell_print_label_value(0, "Group count:", align, "%ld\n", groupcount);
|
|
ctrl_shell_print_label_value(0, "Role count:", align, "%ld\n", rolecount);
|
|
ctrl_shell_print_label_value(0, "Change index:", align, "%ld\n", changeindex);
|
|
}
|
|
|
|
|
|
static void print_client(cJSON *j_data)
|
|
{
|
|
cJSON *j_client, *jtmp;
|
|
|
|
j_client = cJSON_GetObjectItem(j_data, "client");
|
|
if(j_client == NULL){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
|
|
const char *username;
|
|
if(json_get_string(j_client, "username", &username, false) != MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
ctrl_shell_print_label(0, "Username:");
|
|
ctrl_shell_print_value(1, "%s\n", username);
|
|
|
|
const char *clientid;
|
|
if(json_get_string(j_client, "clientid", &clientid, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Clientid:");
|
|
ctrl_shell_print_value(1, "%s\n", clientid);
|
|
}
|
|
|
|
jtmp = cJSON_GetObjectItem(j_client, "disabled");
|
|
if(jtmp && cJSON_IsBool(jtmp) && cJSON_IsTrue(jtmp)){
|
|
ctrl_shell_print_label(0, "Disabled:");
|
|
ctrl_shell_print_value(1, "true\n");
|
|
}
|
|
|
|
const char *textname;
|
|
if(json_get_string(j_client, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text name:");
|
|
ctrl_shell_print_value(1, "%s\n", textname);
|
|
}
|
|
|
|
const char *textdescription;
|
|
if(json_get_string(j_client, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text description:");
|
|
ctrl_shell_print_value(1, "%s\n", textdescription);
|
|
}
|
|
|
|
print_json_array(cJSON_GetObjectItem(j_client, "roles"), "Roles:", "rolename", "priority", "-1");
|
|
print_json_array(cJSON_GetObjectItem(j_client, "groups"), "Groups:", "groupname", "priority", "-1");
|
|
}
|
|
|
|
|
|
static void print_group(cJSON *j_data)
|
|
{
|
|
cJSON *j_group;
|
|
|
|
j_group = cJSON_GetObjectItem(j_data, "group");
|
|
if(j_group == NULL){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
|
|
const char *groupname;
|
|
if(json_get_string(j_group, "groupname", &groupname, false) != MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
ctrl_shell_print_label(0, "Group name:");
|
|
ctrl_shell_print_value(1, "%s\n", groupname);
|
|
|
|
const char *textname;
|
|
if(json_get_string(j_group, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text name:");
|
|
ctrl_shell_print_value(1, "%s\n", textname);
|
|
}
|
|
|
|
const char *textdescription;
|
|
if(json_get_string(j_group, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text description:");
|
|
ctrl_shell_print_value(1, "%s\n", textdescription);
|
|
}
|
|
|
|
print_json_array(cJSON_GetObjectItem(j_group, "roles"), "Roles:", "rolename", "priority", "-1");
|
|
print_json_array(cJSON_GetObjectItem(j_group, "clients"), "Clients:", "username", NULL, NULL);
|
|
}
|
|
|
|
|
|
static void print_role(cJSON *j_data)
|
|
{
|
|
cJSON *j_role;
|
|
|
|
j_role = cJSON_GetObjectItem(j_data, "role");
|
|
if(j_role == NULL){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
|
|
const char *rolename;
|
|
if(json_get_string(j_role, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_printf("Invalid response from broker.\n");
|
|
return;
|
|
}
|
|
ctrl_shell_print_label(0, "Role name:");
|
|
ctrl_shell_print_value(1, "%s\n", rolename);
|
|
|
|
const char *textname;
|
|
if(json_get_string(j_role, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text name:");
|
|
ctrl_shell_print_value(1, "%s\n", textname);
|
|
}
|
|
|
|
const char *textdescription;
|
|
if(json_get_string(j_role, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Text description:");
|
|
ctrl_shell_print_value(1, "%s\n", textdescription);
|
|
}
|
|
|
|
bool allowwildcardsubs;
|
|
if(json_get_bool(j_role, "allowwildcardsubs", &allowwildcardsubs, false, false) == MOSQ_ERR_SUCCESS){
|
|
ctrl_shell_print_label(0, "Allow wildcard subscriptions:");
|
|
ctrl_shell_print_value(1, "%s\n", allowwildcardsubs?"true":"false");
|
|
}
|
|
|
|
cJSON *j_acls = cJSON_GetObjectItem(j_role, "acls");
|
|
if(j_acls && cJSON_GetArraySize(j_acls) > 0){
|
|
ctrl_shell_print_label(0, "ACLs:");
|
|
|
|
cJSON *j_acl;
|
|
cJSON_ArrayForEach(j_acl, j_acls){
|
|
const char *acltype;
|
|
const char *topic;
|
|
int priority;
|
|
bool allow;
|
|
|
|
if(json_get_string(j_acl, "acltype", &acltype, false) == MOSQ_ERR_SUCCESS
|
|
&& json_get_string(j_acl, "topic", &topic, false) == MOSQ_ERR_SUCCESS
|
|
&& json_get_int(j_acl, "priority", &priority, true, -1) == MOSQ_ERR_SUCCESS
|
|
&& json_get_bool(j_acl, "allow", &allow, false, false) == MOSQ_ERR_SUCCESS
|
|
){
|
|
|
|
const char *ANSI_ALLOW = allow?ANSI_POSITIVE:ANSI_NEGATIVE;
|
|
ctrl_shell_print_value(1, "%-*s %s%s%s %s%s%s (priority %d)\n", (int)strlen("publishClientReceive"), acltype, ANSI_ALLOW, allow?"allow":"deny", ANSI_RESET, ANSI_TOPIC, topic, ANSI_RESET, priority);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void print_default_acls(cJSON *j_data)
|
|
{
|
|
cJSON *j_acls = cJSON_GetObjectItem(j_data, "acls");
|
|
|
|
if(j_acls && cJSON_GetArraySize(j_acls) > 0){
|
|
cJSON *j_acl;
|
|
cJSON_ArrayForEach(j_acl, j_acls){
|
|
const char *acltype;
|
|
bool allow;
|
|
|
|
if(json_get_string(j_acl, "acltype", &acltype, false) == MOSQ_ERR_SUCCESS
|
|
&& json_get_bool(j_acl, "allow", &allow, false, false) == MOSQ_ERR_SUCCESS
|
|
){
|
|
|
|
ctrl_shell_print_value(0, "%-*s %s\n", (int)strlen("publishClientReceive"), acltype, allow?"allow":"deny");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void response_callback(const char *command, cJSON *j_data, const char *payload)
|
|
{
|
|
UNUSED(payload);
|
|
|
|
if(!strcmp(command, "listClients")){
|
|
completion_tree_arg_list_args_free(tree_clients);
|
|
|
|
cJSON *clients, *client;
|
|
|
|
clients = cJSON_GetObjectItem(j_data, "clients");
|
|
cJSON_ArrayForEach(client, clients){
|
|
if(do_print_list){
|
|
ctrl_shell_print_value(0, "%s\n", client->valuestring);
|
|
}
|
|
completion_tree_arg_list_add_arg(tree_clients, client->valuestring);
|
|
}
|
|
do_print_list = false;
|
|
}else if(!strcmp(command, "listGroups")){
|
|
completion_tree_arg_list_args_free(tree_groups);
|
|
|
|
cJSON *groups, *group;
|
|
|
|
groups = cJSON_GetObjectItem(j_data, "groups");
|
|
cJSON_ArrayForEach(group, groups){
|
|
if(do_print_list){
|
|
ctrl_shell_print_value(0, "%s\n", group->valuestring);
|
|
}
|
|
completion_tree_arg_list_add_arg(tree_groups, group->valuestring);
|
|
}
|
|
do_print_list = false;
|
|
}else if(!strcmp(command, "listRoles")){
|
|
completion_tree_arg_list_args_free(tree_roles);
|
|
|
|
cJSON *roles, *role;
|
|
|
|
roles = cJSON_GetObjectItem(j_data, "roles");
|
|
cJSON_ArrayForEach(role, roles){
|
|
if(do_print_list){
|
|
ctrl_shell_print_value(0, "%s\n", role->valuestring);
|
|
}
|
|
completion_tree_arg_list_add_arg(tree_roles, role->valuestring);
|
|
}
|
|
do_print_list = false;
|
|
}else if(!strcasecmp(command, "getAnonymousGroup")){
|
|
cJSON *group, *groupname;
|
|
|
|
group = cJSON_GetObjectItem(j_data, "group");
|
|
groupname = cJSON_GetObjectItem(group, "groupname");
|
|
ctrl_shell_print_value(0, "%s\n", groupname->valuestring);
|
|
}else if(!strcasecmp(command, "getDetails")){
|
|
print_details(j_data);
|
|
}else if(!strcasecmp(command, "getClient")){
|
|
print_client(j_data);
|
|
}else if(!strcasecmp(command, "getGroup")){
|
|
print_group(j_data);
|
|
}else if(!strcasecmp(command, "getRole")){
|
|
print_role(j_data);
|
|
}else if(!strcasecmp(command, "getDefaultACLAccess")){
|
|
print_default_acls(j_data);
|
|
}else{
|
|
//ctrl_shell_printf("%s %s\n", command, payload);
|
|
}
|
|
}
|
|
|
|
|
|
static void on_subscribe(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = list_update("listClients");
|
|
if(rc){
|
|
ctrl_shell_printf("Check the dynsec module is configured on the broker.\n");
|
|
return;
|
|
}
|
|
list_update("listGroups");
|
|
list_update("listRoles");
|
|
}
|
|
|
|
|
|
static void ctrl_shell__dynsec_cleanup(void)
|
|
{
|
|
completion_tree_free(commands_dynsec);
|
|
commands_dynsec = NULL;
|
|
|
|
completion_tree_arg_list_args_free(tree_clients);
|
|
completion_tree_arg_list_args_free(tree_groups);
|
|
completion_tree_arg_list_args_free(tree_roles);
|
|
|
|
free(tree_clients);
|
|
free(tree_groups);
|
|
free(tree_roles);
|
|
|
|
tree_clients = NULL;
|
|
tree_groups = NULL;
|
|
tree_roles = NULL;
|
|
}
|
|
|
|
|
|
void ctrl_shell__dynsec_init(struct ctrl_shell__module *mod)
|
|
{
|
|
command_tree_create();
|
|
|
|
mod->completion_commands = commands_dynsec;
|
|
mod->request_topic = "$CONTROL/dynamic-security/v1";
|
|
mod->response_topic = "$CONTROL/dynamic-security/v1/response";
|
|
mod->line_callback = line_callback;
|
|
mod->response_callback = response_callback;
|
|
mod->on_subscribe = on_subscribe;
|
|
mod->cleanup = ctrl_shell__dynsec_cleanup;
|
|
}
|
|
#endif
|