From 15442844750556e4f3752f3d67384aef33dc5389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Tue, 15 Nov 2011 10:18:51 +0100 Subject: [PATCH 13/13] SUDO Integration - SUDO responder refactored --- Makefile.am | 2 + src/responder/sudo/sudosrv.h | 2 + src/responder/sudo/sudosrv_check.c | 349 +++++++++++++++++++++++++++ src/responder/sudo/sudosrv_cmd.c | 269 +++++---------------- src/responder/sudo/sudosrv_private.h | 107 ++++++++ src/responder/sudo/sudosrv_query.c | 264 ++++++++++++++++++++ src/sss_client/sudo_plugin/sss_sudoplugin.c | 20 +- 7 files changed, 791 insertions(+), 222 deletions(-) create mode 100644 src/responder/sudo/sudosrv_check.c create mode 100644 src/responder/sudo/sudosrv_private.h create mode 100644 src/responder/sudo/sudosrv_query.c diff --git a/Makefile.am b/Makefile.am index c1340e7..29b3d0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -431,6 +431,8 @@ sssd_pam_LDADD = \ sssd_sudo_SOURCES = \ src/responder/sudo/sudosrv.c \ src/responder/sudo/sudosrv_cmd.c \ + src/responder/sudo/sudosrv_check.c \ + src/responder/sudo/sudosrv_query.c \ src/responder/sudo/sudosrv_dp.c \ $(SSSD_RESPONDER_OBJ) sssd_sudo_LDADD = \ diff --git a/src/responder/sudo/sudosrv.h b/src/responder/sudo/sudosrv.h index 314fddd..c1d11a4 100644 --- a/src/responder/sudo/sudosrv.h +++ b/src/responder/sudo/sudosrv.h @@ -21,6 +21,8 @@ #ifndef SUDOSRV_H_ #define SUDOSRV_H_ +#include "responder/common/responder.h" + #define SSS_SUDO_SBUS_SERVICE_VERSION 0x0001 #define SSS_SUDO_SBUS_SERVICE_NAME "sudo" diff --git a/src/responder/sudo/sudosrv_check.c b/src/responder/sudo/sudosrv_check.c new file mode 100644 index 0000000..6f85fd6 --- /dev/null +++ b/src/responder/sudo/sudosrv_check.c @@ -0,0 +1,349 @@ +/* + Authors: + Pavel Březina + + 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 . +*/ + +#include + +#include "util/util.h" +#include "confdb/confdb.h" +#include "responder/common/responder.h" +#include "responder/sudo/sudosrv.h" +#include "responder/sudo/sudosrv_private.h" +#include "sss_client/sudo_plugin/sss_sudoplugin.h" + +struct sudo_check_output * sudosrv_check(TALLOC_CTX *mem_ctx, + struct cli_ctx *cli_ctx, + struct sudo_check_input *input) +{ + struct sudo_command_info command_info; + struct sudo_check_output *output = NULL; + TALLOC_CTX *tmp_ctx; + int ret = EOK; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto fail; + } + + output = talloc_zero(tmp_ctx, struct sudo_check_output); + if (output == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero() failed\n")); + ret = ENOMEM; + goto fail; + } + + /* + * there is no logic yet + * allow everything + */ + + /* set return code */ + output->return_code = SSS_SUDO_RESPONSE_ALLOW; + + /* build argv */ + ret = sudosrv_copy_string_array(output, input->argc, + input->argv, &(output->argv)); + if (ret != EOK) { + goto fail; + } + + /* build command info */ + command_info.command = input->command_name; + ret = sudosrv_check_build_command_info(output, &command_info, + &(output->command_info)); + if (ret != EOK) { + goto fail; + } + + /* build env out */ + ret = sudosrv_copy_string_array(output, input->user_env_count, + input->user_env, &(output->user_env)); + + /* contact DP */ + ret = sudo_dp_refresh_send(cli_ctx, cli_ctx->rctx->domains->name, + SSS_CLI_SOCKET_TIMEOUT / 2); + + talloc_steal(mem_ctx, output); + talloc_free(tmp_ctx); + + return output; + +fail: + talloc_free(tmp_ctx); + errno = ret; + + return NULL; +} + +/* + * This may not be needed in final version. + */ +int sudosrv_copy_string_array(TALLOC_CTX *mem_ctx, + int count, + char **array, + char ***_array_out) +{ + TALLOC_CTX *tmp_ctx = NULL; + char **array_out = NULL; + int ret = EOK; + int i = 0; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto done; + } + + array_out = talloc_array(tmp_ctx, char*, count + 1); + if (array_out == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_array() failed\n")); + ret = ENOMEM; + goto done; + } + + for (i = 0; i < count; i++) { + array_out[i] = talloc_strdup(array, array[i]); + if (array_out[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed\n")); + ret = ENOMEM; + goto done; + } + } + array_out[count] = NULL; + + *_array_out = talloc_steal(mem_ctx, array_out); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +/* + * Currently only "command" is supported. + */ +int sudosrv_check_build_command_info(TALLOC_CTX *mem_ctx, + struct sudo_command_info *command_info, + char ***_command_info_array) +{ + TALLOC_CTX *tmp_ctx = NULL; + char **array = NULL; + int count = 0; + int ret = EOK; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto done; + } + + /* command */ + if (command_info->command != NULL) { + count++; + array = talloc_realloc(tmp_ctx, array, char*, count); + if (array == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n")); + ret = ENOMEM; + goto done; + } + array[count - 1] = talloc_asprintf(array, "command=%s", + command_info->command); + if (array[count - 1] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed\n")); + ret = ENOMEM; + goto done; + } + } + + /* terminate with NULL */ + count++; + array = talloc_realloc(tmp_ctx, array, char*, count); + if (array == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n")); + ret = ENOMEM; + goto done; + } + array[count - 1] = NULL; + + *_command_info_array = talloc_steal(mem_ctx, array); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +struct sudo_check_input * sudosrv_check_parse_query(TALLOC_CTX *mem_ctx, + char *query, + int query_length) +{ + struct sudo_check_input *input = NULL; + TALLOC_CTX *tmp_ctx = NULL; + int next_pos = 0; + int ret = EOK; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto fail; + } + + input = talloc_zero(tmp_ctx, struct sudo_check_input); + if (input == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero() failed\n")); + ret = ENOMEM; + goto fail; + } + + /* command name */ + ret = sudosrv_query_parse_string(input, query, query_length, + next_pos, &next_pos, + &(input->command_name)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - command name\n")); + goto fail; + } + + /* argv */ + ret = sudosrv_query_parse_array(input, query, query_length, + next_pos, &next_pos, + &(input->argc), + &(input->argv)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - argv\n")); + goto fail; + } + + /* env_add */ + ret = sudosrv_query_parse_array(input, query, query_length, + next_pos, &next_pos, + &(input->env_add_count), + &(input->env_add)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - env_add \n")); + goto fail; + } + + + /* user_env */ + ret = sudosrv_query_parse_array(input, query, query_length, + next_pos, &next_pos, + &(input->user_env_count), + &(input->user_env)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - user_env\n")); + goto fail; + } + + /* settings */ + ret = sudosrv_query_parse_array(input, query, query_length, + next_pos, &next_pos, + &(input->settings_count), + &(input->settings)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - settings\n")); + goto fail; + } + + /* user_info */ + ret = sudosrv_query_parse_array(input, query, query_length, + next_pos, &next_pos, + &(input->user_info_count), + &(input->user_info)); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query - user_info\n")); + goto fail; + } + + talloc_steal(mem_ctx, input); + talloc_free(tmp_ctx); + + return input; + +fail: + talloc_free(tmp_ctx); + errno = ret; + + return NULL; +} + +int sudosrv_check_build_response(TALLOC_CTX *mem_ctx, + struct sudo_check_output *output, + uint8_t **_response_body, + size_t *_response_length) +{ + uint8_t *response_body = NULL; + size_t response_length = 0; + TALLOC_CTX *tmp_ctx = NULL; + int ret = EOK; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + /* return code */ + ret = sudosrv_response_append_int(tmp_ctx, output->return_code, + &response_body, &response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to build response - return code\n")); + goto done; + } + + /* argv */ + ret = sudosrv_response_append_array(tmp_ctx, output->argv, + &response_body, &response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to build response - argv\n")); + goto done; + } + + /* command info */ + ret = sudosrv_response_append_array(tmp_ctx, output->command_info, + &response_body, &response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to build response - command_info\n")); + goto done; + } + + /* user env */ + ret = sudosrv_response_append_array(tmp_ctx, output->user_env, + &response_body, &response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to build response - user_env\n")); + goto done; + } + + *_response_body = talloc_steal(mem_ctx, response_body); + *_response_length = response_length; + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c index 11409c4..6cd5b65 100644 --- a/src/responder/sudo/sudosrv_cmd.c +++ b/src/responder/sudo/sudosrv_cmd.c @@ -23,249 +23,90 @@ #include #include "util/util.h" -#include "confdb/confdb.h" #include "responder/common/responder.h" #include "responder/common/responder_packet.h" #include "responder/sudo/sudosrv.h" -#include "sss_client/sudo_plugin/sss_sudoplugin.h" -#include "sss_client/sss_cli.h" +#include "responder/sudo/sudosrv_private.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) +static int sudo_cmd_check(struct cli_ctx *cli_ctx) { -#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) + struct sudo_check_output *output = NULL; + struct sudo_check_input *input = NULL; + struct sss_packet *packet = NULL; + uint8_t *packet_body = NULL; + size_t packet_length = 0; + TALLOC_CTX *mem_ctx = NULL; + uint8_t *response_body = NULL; + size_t response_length = 0; + uint8_t *query_body = NULL; + size_t query_length = 0; + int ret = EOK; -#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; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; } - /* get command */ - *_command_out = current_position; - current_position = strchr(current_position, '\0'); - if (current_position == NULL) { - ret = ESPIPE; + /* get query */ + sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_length); + if (query_length <= 0 || query_body == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Query is empty\n")); + ret = EINVAL; 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; + /* parse query */ + input = sudosrv_check_parse_query(mem_ctx, (char*)query_body, query_length); + if (input == NULL) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to parse query: %s\n", strerror(ret))); goto done; } - command_info = talloc_asprintf(tmp_ctx, "command=%s", command); - if (command_info == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed")); - ret = ENOMEM; + /* evaluate sudo rules */ + output = sudosrv_check(mem_ctx, cli_ctx, input); + if (output == NULL) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to evaluate sudo rules: %s\n", strerror(ret))); 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; + /* create response message */ + ret = sudosrv_check_build_response(mem_ctx, output, + &response_body, &response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to create response message: %s\n", strerror(ret))); goto done; } - query = (char*)body; - /* parse query string */ - ret = sudo_cmd_check_parse_query(mem_ctx, query, blen, &command_in, - &argv_in, &argc_in); + /* set response */ + ret = sss_packet_new(cli_ctx->creq, 0, + sss_packet_get_cmd(cli_ctx->creq->in), + &cli_ctx->creq->out); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Unable to parse query string")); - goto done; + return ret; } + packet = cli_ctx->creq->out; - /* TODO can user run this command? */ - - sudo_result = SSS_SUDO_RESPONSE_ALLOW; + sss_packet_set_error(packet, EOK); - /* 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; - } + ret = sss_packet_grow(packet, response_length); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to create response: %s\n", strerror(ret))); + return ret; } - - /* contact DP */ - ret = sudo_dp_refresh_send(cctx, cctx->rctx->domains->name, - SSS_CLI_SOCKET_TIMEOUT/2); - - /* send response */ - sudo_cmd_check_response(cctx, sudo_result, argc_in, argv_in, - command_info_out, command_info_out_length, NULL); + sss_packet_get_body(packet, &packet_body, &packet_length); + memcpy(packet_body, response_body, response_length); ret = EOK; done: - sss_cmd_done(cctx, NULL); + sss_cmd_done(cli_ctx, NULL); talloc_free(mem_ctx); return ret; diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h new file mode 100644 index 0000000..012f5d9 --- /dev/null +++ b/src/responder/sudo/sudosrv_private.h @@ -0,0 +1,107 @@ +/* + Authors: + Pavel Březina + + 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 . +*/ + +#ifndef SUDOSRV_PRIVATE_H_ +#define SUDOSRV_PRIVATE_H_ + +struct sudo_check_input { + char *command_name; + + int argc; + char **argv; + + int env_add_count; + char **env_add; + + int user_env_count; + char **user_env; + + int settings_count; + char **settings; + + int user_info_count; + char **user_info; +}; + +struct sudo_check_output { + int return_code; + char **argv; + char **command_info; + char **user_env; +}; + +struct sudo_command_info { + char *command; +}; + +struct sudo_check_output * sudosrv_check(TALLOC_CTX *mem_ctx, + struct cli_ctx *cli_ctx, + struct sudo_check_input *input); + +int sudosrv_copy_string_array(TALLOC_CTX *mem_ctx, + int argc, + char **argv, + char ***_argv_out); + +int sudosrv_check_build_command_info(TALLOC_CTX *mem_ctx, + struct sudo_command_info *command_info, + char ***_command_info); + +struct sudo_check_input * sudosrv_check_parse_query(TALLOC_CTX *mem_ctx, + char *query, + int query_length); + +int sudosrv_check_build_response(TALLOC_CTX *mem_ctx, + struct sudo_check_output *output, + uint8_t **_response_body, + size_t *_response_length); + +int sudosrv_query_parse_array(TALLOC_CTX *mem_ctx, + char *query, + int query_length, + int start_pos, + int *_end_pos, + int *_count, + char ***_array); + +int sudosrv_query_parse_string(TALLOC_CTX *mem_ctx, + char *query, + int query_length, + int start_pos, + int *_end_pos, + char **_string); + +int sudosrv_response_append_array(TALLOC_CTX *mem_ctx, + char **array, + uint8_t **_response, + size_t *_response_length); + +int sudosrv_response_append_string(TALLOC_CTX *mem_ctx, + const char *str, + size_t str_length, + uint8_t **_response, + size_t *_response_length); + +int sudosrv_response_append_int(TALLOC_CTX *mem_ctx, + int number, + uint8_t **_response, + size_t *_response_length); + +#endif /* SUDOSRV_PRIVATE_H_ */ diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c new file mode 100644 index 0000000..fcf0133 --- /dev/null +++ b/src/responder/sudo/sudosrv_query.c @@ -0,0 +1,264 @@ +/* + Authors: + Pavel Březina + + 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 . +*/ + +#include +#include +#include + +#include "util/util.h" +#include "responder/sudo/sudosrv.h" +#include "responder/sudo/sudosrv_private.h" + +/* + * Reads null-terminated string. + */ +int sudosrv_query_parse_string(TALLOC_CTX *mem_ctx, + char *query, + int query_length, + int start_pos, + int *_end_pos, + char **_string) +{ + TALLOC_CTX *tmp_ctx = NULL; + char *current_pos = query + start_pos; + char *string = NULL; + int ret = EOK; + + if (start_pos > query_length) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Query is too short\n")); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto done; + } + + if (*current_pos != '\0') { + string = talloc_strdup(tmp_ctx, current_pos); + if (string == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n")); + return ENOMEM; + } + + current_pos = strchr(current_pos, '\0'); + if (current_pos == NULL) { + ret = ESPIPE; + goto done; + } + } + + /* go one char past \0 */ + current_pos++; + + *_end_pos = current_pos - query; + *_string = talloc_steal(mem_ctx, string); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +/* + * Reads array in format: + * value1\0value2\0...\0\0 + */ +int sudosrv_query_parse_array(TALLOC_CTX *mem_ctx, + char *query, + int query_length, + int start_pos, + int *_end_pos, + int *_count, + char ***_array) +{ + TALLOC_CTX *tmp_ctx = NULL; + char *current_pos = query + start_pos; + char **array = NULL; + int count = 0; + int ret = EOK; + + if (start_pos > query_length) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Query is too short\n")); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + ret = ENOMEM; + goto done; + } + + if (*current_pos != '\0') { + /* array with at least one element */ + do { + count++; + + array = talloc_realloc(tmp_ctx, array, char*, count); + if (array == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n")); + ret = ENOMEM; + goto done; + } + + array[count - 1] = talloc_strdup(array, current_pos); + if (array[count - 1] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n")); + return ENOMEM; + } + + /* find end of this element */ + current_pos = strchr(current_pos, '\0'); + if (current_pos == NULL) { + ret = ESPIPE; + goto done; + } + + /* go to the start of the next element (one char past \0) */ + current_pos++; + } while (*current_pos != '\0'); + } else { + /* special case for empty arrays - go one char past \0 */ + current_pos++; + } + + /* go to the next array */ + current_pos++; + + if (_count != NULL) { + *_count = count; + } + *_array = talloc_steal(mem_ctx, array); + *_end_pos = current_pos - query; + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +/* + * Appends null-terminated string array. + */ +int sudosrv_response_append_array(TALLOC_CTX *mem_ctx, + char **array, + uint8_t **_response, + size_t *_response_length) +{ + size_t response_length = *_response_length; + uint8_t *response = *_response; + TALLOC_CTX *tmp_ctx = NULL; + char **iter = NULL; + int ret = EOK; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed")); + ret = ENOMEM; + goto done; + } + + if (array == NULL || *array == NULL) { + /* empty array - append two \0 */ + ret = sudosrv_response_append_string(tmp_ctx, "\0\0", 2, + &response, &response_length); + if (ret != EOK) { + goto done; + } + } else { + for (iter = array; *iter != NULL; iter++) { + /* append element with ending \0 */ + ret = sudosrv_response_append_string(tmp_ctx, *iter, + strlen(*iter) + 1, + &response, &response_length); + if (ret != EOK) { + goto done; + } + } + + /* append \0 to mark end of this array */ + ret = sudosrv_response_append_string(tmp_ctx, "\0", 1, + &response, &response_length); + if (ret != EOK) { + goto done; + } + } + + *_response_length = response_length; + *_response = talloc_steal(mem_ctx, response); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +int sudosrv_response_append_string(TALLOC_CTX *mem_ctx, + const char *str, + size_t str_length, + uint8_t **_response, + size_t *_response_length) +{ + size_t response_length = *_response_length; + uint8_t *response = *_response; + + response = talloc_realloc(mem_ctx, response, uint8_t, + response_length + (str_length * sizeof(char))); + if (response == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n")); + return ENOMEM; + } + memcpy(response + response_length, str, str_length); + response_length += str_length; + + *_response = response; + *_response_length = response_length; + + return EOK; +} + +int sudosrv_response_append_int(TALLOC_CTX *mem_ctx, + int number, + uint8_t **_response, + size_t *_response_length) +{ + size_t response_length = *_response_length; + uint8_t *response = *_response; + + response = talloc_realloc(mem_ctx, response, uint8_t, + response_length + sizeof(int)); + if (response == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n")); + return ENOMEM; + } + SAFEALIGN_SET_VALUE(response + response_length, + number, int, &response_length); + + *_response = response; + *_response_length = response_length; + + return EOK; +} diff --git a/src/sss_client/sudo_plugin/sss_sudoplugin.c b/src/sss_client/sudo_plugin/sss_sudoplugin.c index 9e2dfce..3e5e2c0 100644 --- a/src/sss_client/sudo_plugin/sss_sudoplugin.c +++ b/src/sss_client/sudo_plugin/sss_sudoplugin.c @@ -347,15 +347,19 @@ errno_t policy_check_parse_response(char *response, { #define LOAD_ARRAY(element) do { \ i = 0; \ - while (*current_position != '\0') { \ - i++; \ - element = (char**)realloc(element, i * sizeof(char*)); \ - element[i - 1] = current_position; \ - current_position = strchr(current_position, '\0'); \ - if (current_position == NULL) { \ - ret = ESPIPE; \ - goto done; \ + if (*current_position != '\0') { \ + while (*current_position != '\0') { \ + i++; \ + element = (char**)realloc(element, i * sizeof(char*)); \ + element[i - 1] = current_position; \ + current_position = strchr(current_position, '\0'); \ + if (current_position == NULL) { \ + ret = ESPIPE; \ + goto done; \ + } \ + current_position++; \ } \ + } else { \ current_position++; \ } \ i++; \ -- 1.7.6.4