From: Vincent Bernat Date: Thu, 10 Jul 2014 20:55:58 +0000 (+0200) Subject: lldpcli: change how privileged commands are declared X-Git-Tag: 0.7.10~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e13945c02c443c3783660e18dac0e6ec9d188524;p=thirdparty%2Flldpd.git lldpcli: change how privileged commands are declared Even when not privileged, we declare privileged commands but tag them accordingly. We need to be careful when executing the commands to check the new bit. This is a preliminary change to allow a completion command to complete privileged commands even when not privileged. --- diff --git a/src/client/client.h b/src/client/client.h index 4a97fd4e..8c306edc 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -68,15 +68,16 @@ struct cmd_node *commands_new( int(*execute)(struct lldpctl_conn_t*, struct writer*, struct cmd_env*, void *), void *); +struct cmd_node* commands_privileged(struct cmd_node *); void commands_free(struct cmd_node *); const char *cmdenv_arg(struct cmd_env*); const char *cmdenv_get(struct cmd_env*, const char*); int cmdenv_put(struct cmd_env*, const char*, const char*); int cmdenv_pop(struct cmd_env*, int); int commands_execute(struct lldpctl_conn_t *, struct writer *, - struct cmd_node *, int argc, const char **argv); -char *commands_complete(struct cmd_node *, int argc, const char **argv, - int all); + struct cmd_node *, int, const char **, int); +char *commands_complete(struct cmd_node *, int, const char **, + int, int); /* helpers */ int cmd_check_no_env(struct cmd_env *, void *); int cmd_check_env(struct cmd_env *, void *); diff --git a/src/client/commands.c b/src/client/commands.c index e18c8f13..d1bf242b 100644 --- a/src/client/commands.c +++ b/src/client/commands.c @@ -67,6 +67,7 @@ struct cmd_node { const char *token; /**< Token to enter this cnode */ const char *doc; /**< Documentation string */ + int privileged; /**< Privileged command? */ /** * Function validating entry in this node. Can be @c NULL. @@ -97,7 +98,22 @@ commands_root(void) } /** - * Create a new node. + * Make a node accessible only to privileged users. + * + * @param node Node to change privileges + * @return the modified node + * + * The node is modified. It is returned to ease chaining. + */ +struct cmd_node* +commands_privileged(struct cmd_node *node) +{ + if (node) node->privileged = 1; + return node; +} + +/** + * Create a new node acessible by any user. * * @param root The node we want to attach this node. * @param token Token to enter this node. Or @c NULL if no token is needed. @@ -300,12 +316,13 @@ struct candidate_word { * @param argv Array of arguments. * @param word Completed word. Or NULL when no completion is required. * @param all When completing, display possible completions even if only one choice is possible. + * @param priv Is the current user privileged? * @return 0 on success, -1 otherwise. */ static int _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_node *root, int argc, const char **argv, - char **word, int all) + char **word, int all, int priv) { int n, rc = 0, completion = (word != NULL); int help = 0; /* Are we asking for help? */ @@ -322,6 +339,11 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, log_debug("lldpctl", "argument %02d: `%s`", n, argv[n]); if (completion) *word = NULL; +#define CAN_EXECUTE(candidate) \ + ((!candidate->privileged || priv) && \ + (!candidate->validate || \ + candidate->validate(&env, candidate->arg) == 1)) + /* When completion is in progress, we use the same algorithm than for * execution until we reach the cursor position. */ struct cmd_node *current = NULL; @@ -340,31 +362,29 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, env.argp, token); TAILQ_FOREACH(candidate, ¤t->subentries, next) { if (candidate->token && - !strncmp(candidate->token, token, strlen(token))) { - if (!candidate->validate || - candidate->validate(&env, candidate->arg) == 1) { - if (candidate->token && - !strcmp(candidate->token, token)) { - /* Exact match */ - best = candidate; - break; - } - if (!best) best = candidate; - else { - if (!completion) - log_warnx("lldpctl", "ambiguous token: %s (%s or %s)", - token, candidate->token, best->token); - rc = -1; - goto end; - } + !strncmp(candidate->token, token, strlen(token)) && + CAN_EXECUTE(candidate)) { + if (candidate->token && + !strcmp(candidate->token, token)) { + /* Exact match */ + best = candidate; + break; + } + if (!best) best = candidate; + else { + if (!completion) + log_warnx("lldpctl", "ambiguous token: %s (%s or %s)", + token, candidate->token, best->token); + rc = -1; + goto end; } } } if (!best) { /* Take first that validate */ TAILQ_FOREACH(candidate, ¤t->subentries, next) { - if (!candidate->token && (!candidate->validate || - candidate->validate(&env, candidate->arg) == 1)) { + if (!candidate->token && + CAN_EXECUTE(candidate)) { best = candidate; break; } @@ -405,8 +425,7 @@ end: if ((!candidate->token || help || !strncmp(env.argv[env.argc - 1], candidate->token, strlen(env.argv[env.argc -1 ]))) && - (!candidate->validate || - candidate->validate(&env, candidate->arg) == 1)) { + CAN_EXECUTE(candidate)) { struct candidate_word *cword = malloc(sizeof(struct candidate_word)); if (!cword) break; @@ -483,11 +502,11 @@ end: */ char * commands_complete(struct cmd_node *root, int argc, const char **argv, - int all) + int all, int privileged) { char *word = NULL; if (_commands_execute(NULL, NULL, root, argc, argv, - &word, all) == 0) + &word, all, privileged) == 0) return word; return NULL; } @@ -497,9 +516,9 @@ commands_complete(struct cmd_node *root, int argc, const char **argv, */ int commands_execute(struct lldpctl_conn_t *conn, struct writer *w, - struct cmd_node *root, int argc, const char **argv) + struct cmd_node *root, int argc, const char **argv, int privileged) { - return _commands_execute(conn, w, root, argc, argv, NULL, 0); + return _commands_execute(conn, w, root, argc, argv, NULL, 0, privileged); } /** diff --git a/src/client/conf.c b/src/client/conf.c index 7e7c67a2..d9f0111e 100644 --- a/src/client/conf.c +++ b/src/client/conf.c @@ -37,6 +37,8 @@ register_commands_configure(struct cmd_node *root) "unconfigure", "Unconfigure system settings", NULL, NULL, NULL); + commands_privileged(configure); + commands_privileged(unconfigure); cmd_restrict_ports(configure); cmd_restrict_ports(unconfigure); diff --git a/src/client/lldpcli.c b/src/client/lldpcli.c index c68cb3a6..f96b9c57 100644 --- a/src/client/lldpcli.c +++ b/src/client/lldpcli.c @@ -206,7 +206,7 @@ _cmd_complete(int all) if (tokenize_line(line, &argc, &argv) != 0) goto end; - char *compl = commands_complete(root, argc, (const char **)argv, all); + char *compl = commands_complete(root, argc, (const char **)argv, all, is_privileged()); if (compl && strlen(argv[argc-1]) < strlen(compl)) { if (rl_insert_text(compl + strlen(argv[argc-1])) < 0) { free(compl); @@ -278,7 +278,7 @@ cmd_exec(lldpctl_conn_t *conn, const char *fmt, int argc, const char **argv) /* Execute command */ int rc = commands_execute(conn, w, - root, argc, argv); + root, argc, argv, is_privileged()); if (rc != 0) { log_info("lldpctl", "an error occurred while executing last command"); w->finish(w); @@ -325,14 +325,12 @@ register_commands() root = commands_root(); register_commands_show(root); register_commands_watch(root); - if (is_privileged()) { - commands_new( - commands_new(root, "update", "Update information and send LLDPU on all ports", - NULL, NULL, NULL), - NEWLINE, "Update information and send LLDPU on all ports", - NULL, cmd_update, NULL); - register_commands_configure(root); - } + commands_privileged(commands_new( + commands_new(root, "update", "Update information and send LLDPU on all ports", + NULL, NULL, NULL), + NEWLINE, "Update information and send LLDPU on all ports", + NULL, cmd_update, NULL)); + register_commands_configure(root); commands_new(root, "help", "Get help on a possible command", NULL, cmd_store_env_and_pop, "help"); commands_new(