diff options
Diffstat (limited to 'src/responder/sudo/sudosrv_cmd.c')
-rw-r--r-- | src/responder/sudo/sudosrv_cmd.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c new file mode 100644 index 00000000..29e975ae --- /dev/null +++ b/src/responder/sudo/sudosrv_cmd.c @@ -0,0 +1,284 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2011 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <talloc.h> +#include <sudo_plugin.h> + +#include "util/util.h" +#include "responder/common/responder.h" +#include "responder/common/responder_packet.h" +#include "sss_client/sudo_plugin/sss_sudoplugin.h" + +static int sudo_cmd_check_response(struct cli_ctx *cctx, + int return_code, + int argc, + char **argv, + char *command_info, + int command_info_length, + char **user_env) +{ +#define APPEND_ELEMENT(element, length) do { \ + iter_length = length; \ + sss_packet_grow(packet_out, iter_length * sizeof(char)); \ + sss_packet_get_body(packet_out, &body, &blen); \ + memcpy(body + packet_offset, element, iter_length); \ + packet_offset += iter_length; \ +} while(0) + +#define APPEND_ZERO() do { \ + sss_packet_grow(packet_out, 1 * sizeof(char)); \ + sss_packet_get_body(packet_out, &body, &blen); \ + body[packet_offset] = '\0'; \ + packet_offset++; \ +} while(0) + + int i; + int ret; + int iter_length; + uint8_t *body; + size_t blen; + size_t packet_offset = 0; + struct sss_packet *packet_out = NULL; + + ret = sss_packet_new(cctx->creq, 0, + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return ret; + } + packet_out = cctx->creq->out; + + sss_packet_set_error(packet_out, EOK); + + /* fill data */ + + /* result */ + ret = sss_packet_grow(packet_out, sizeof(int)); + if (ret != EOK) { + return ret; + } + sss_packet_get_body(packet_out, &body, &blen); + SAFEALIGN_SET_VALUE(&body[packet_offset], return_code, int, &packet_offset); + + if (return_code == SSS_SUDO_RESPONSE_ALLOW) { + /* argv */ + for (i = 0; i < argc; i++) { + APPEND_ELEMENT(argv[i], strlen(argv[i]) + 1); + } + APPEND_ZERO(); + + /* command_info */ + APPEND_ELEMENT(command_info, command_info_length); + APPEND_ZERO(); + + /* user_env */ + APPEND_ZERO(); + APPEND_ZERO(); + } + + return EOK; + +#undef APPEND_ELEMENT +#undef APPEND_ZERO +} + +static int sudo_cmd_check_parse_query(TALLOC_CTX *mem_ctx, + char *query, + int query_length, + char **_command_out, + char ***_argv_out, + int *_argc_out) +{ + TALLOC_CTX *tmp_ctx; + char *current_position = query; + char **argv_out; + int argc_out = 0; + int ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed")); + ret = ENOMEM; + goto done; + } + + /* get command */ + *_command_out = current_position; + current_position = strchr(current_position, '\0'); + if (current_position == NULL) { + ret = ESPIPE; + goto done; + } + current_position++; + + /* get argv */ + while (*current_position != '\0') { + argc_out++; + argv_out = talloc_realloc(tmp_ctx, argv_out, char*, argc_out); + argv_out[argc_out - 1] = current_position; + + current_position = strchr(current_position, '\0'); + if (current_position == NULL) { + ret = ESPIPE; + goto done; + } + current_position++; + } + current_position++; + + /* TODO get env_add */ + + /* TODO get user_env */ + + /* TODO get settings */ + + /* TODO get user_info */ + + + *_argc_out = argc_out; + *_argv_out = talloc_steal(mem_ctx, argv_out); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +static int sudo_cmd_check_create_command_info(TALLOC_CTX *mem_ctx, + char *command, + char **command_info_out, + int *command_info_length_out) +{ + TALLOC_CTX *tmp_ctx; + char *command_info; + int command_info_length = 0; + int ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed")); + ret = ENOMEM; + goto done; + } + + command_info = talloc_asprintf(tmp_ctx, "command=%s", command); + if (command_info == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed")); + ret = ENOMEM; + goto done; + } + command_info_length += strlen(command_info) + 1; /* with \0 */ + + /* TODO support other fields */ + + *command_info_length_out = command_info_length; + *command_info_out = talloc_steal(mem_ctx, command_info); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +static int sudo_cmd_check(struct cli_ctx *cctx) { + TALLOC_CTX *mem_ctx; + uint8_t *body; + size_t blen; + char *query = NULL; + char *command_in = NULL; + char **argv_in = NULL; + char *command_info_out = NULL; + int command_info_out_length = 0; + int argc_in = 0; + int ret; + int sudo_result; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed")); + return ENOMEM; + } + + /* get query string */ + sss_packet_get_body(cctx->creq->in, &body, &blen); + if (blen <= 0 || body == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Query string is empty")); + ret = EINVAL; + goto done; + } + query = (char*)body; + + /* parse query string */ + ret = sudo_cmd_check_parse_query(mem_ctx, query, blen, &command_in, + &argv_in, &argc_in); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Unable to parse query string")); + goto done; + } + + /* TODO can user run this command? */ + + sudo_result = SSS_SUDO_RESPONSE_ALLOW; + + /* create command info */ + if (sudo_result == SSS_SUDO_RESPONSE_ALLOW) { + ret = sudo_cmd_check_create_command_info(mem_ctx, command_in, + &command_info_out, + &command_info_out_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create command info string")); + return ENOMEM; + } + } + + /* send response */ + sudo_cmd_check_response(cctx, sudo_result, argc_in, argv_in, + command_info_out, command_info_out_length, NULL); + + ret = EOK; + +done: + sss_cmd_done(cctx, NULL); + talloc_free(mem_ctx); + + return ret; +} + +struct cli_protocol_version *register_cli_protocol_version(void) +{ + static struct cli_protocol_version sudo_cli_protocol_version[] = { + {0, NULL, NULL} + }; + + return sudo_cli_protocol_version; +} + +struct sss_cmd_table *get_sudo_cmds(void) { + static struct sss_cmd_table sudo_cmds[] = { + {SSS_GET_VERSION, sss_cmd_get_version}, + {SSS_SUDO_CHECK, sudo_cmd_check}, + {SSS_CLI_NULL, NULL} + }; + + return sudo_cmds; +} |