summaryrefslogtreecommitdiffstats
path: root/src/sss_client/sudo
diff options
context:
space:
mode:
Diffstat (limited to 'src/sss_client/sudo')
-rw-r--r--src/sss_client/sudo/sss_sudo.c251
-rw-r--r--src/sss_client/sudo/sss_sudo.h195
-rw-r--r--src/sss_client/sudo/sss_sudo_private.h33
-rw-r--r--src/sss_client/sudo/sss_sudo_response.c257
4 files changed, 736 insertions, 0 deletions
diff --git a/src/sss_client/sudo/sss_sudo.c b/src/sss_client/sudo/sss_sudo.c
new file mode 100644
index 0000000..6c86b8f
--- /dev/null
+++ b/src/sss_client/sudo/sss_sudo.c
@@ -0,0 +1,251 @@
+/*
+ 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util/util.h"
+#include "sss_client/sss_cli.h"
+#include "sss_client/sudo/sss_sudo.h"
+#include "sss_client/sudo/sss_sudo_private.h"
+
+static int sss_sudo_create_query(uid_t uid,
+ const char *username,
+ uint8_t **_query,
+ size_t *_query_len);
+
+static void sss_sudo_free_rules(unsigned int num_rules,
+ struct sss_sudo_rule *rules);
+
+static void sss_sudo_free_attrs(unsigned int num_attrs,
+ struct sss_sudo_attr *attrs);
+
+static int sss_sudo_send_recv_generic(enum sss_cli_command command,
+ uid_t uid,
+ const char *username,
+ uint32_t *_error,
+ char **_domainname,
+ struct sss_sudo_result **_result)
+{
+ struct sss_cli_req_data request;
+ uint8_t *query_buf = NULL;
+ size_t query_len = 0;
+ uint8_t *reply_buf = NULL;
+ size_t reply_len = 0;
+ int errnop = 0;
+ int ret = 0;
+
+ /* create query */
+
+ ret = sss_sudo_create_query(uid, username, &query_buf, &query_len);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ request.len = query_len;
+ request.data = (const void*)query_buf;
+
+ /* send query and receive response */
+
+ errnop = 0;
+ ret = sss_sudo_make_request(command, &request,
+ &reply_buf, &reply_len, &errnop);
+ if (ret != SSS_STATUS_SUCCESS) {
+ ret = errnop;
+ goto done;
+ }
+
+ /* parse structure */
+
+ ret = sss_sudo_parse_response((const char*)reply_buf, reply_len,
+ _domainname, _result, _error);
+
+done:
+ free(query_buf);
+ free(reply_buf);
+ return ret;
+}
+
+int sss_sudo_send_recv(uid_t uid,
+ const char *username,
+ const char *domainname,
+ uint32_t *_error,
+ struct sss_sudo_result **_result)
+{
+ int ret;
+
+ if (username == NULL || strlen(username) == 0) {
+ return EINVAL;
+ }
+
+ /* send query and receive response */
+
+ ret = sss_sudo_send_recv_generic(SSS_SUDO_GET_SUDORULES, uid, username,
+ _error, NULL, _result);
+ return ret;
+}
+
+int sss_sudo_send_recv_defaults(uid_t uid,
+ const char *username,
+ uint32_t *_error,
+ char **_domainname,
+ struct sss_sudo_result **_result)
+{
+ if (username == NULL || strlen(username) == 0) {
+ return EINVAL;
+ }
+
+ return sss_sudo_send_recv_generic(SSS_SUDO_GET_DEFAULTS, uid, username,
+ _error, _domainname, _result);
+}
+
+static int sss_sudo_create_query(uid_t uid, const char *username,
+ uint8_t **_query, size_t *_query_len)
+{
+ uint8_t *data = NULL;
+ size_t username_len = strlen(username) * sizeof(char) + 1;
+ size_t data_len = sizeof(uid_t) + username_len;
+ size_t offset = 0;
+
+ data = (uint8_t*)malloc(data_len * sizeof(uint8_t));
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ SAFEALIGN_SET_VALUE(data, uid, uid_t, &offset);
+ memcpy(data + offset, username, username_len);
+
+ *_query = data;
+ *_query_len = data_len;
+
+ return EOK;
+}
+
+int sss_sudo_get_values(struct sss_sudo_rule *e,
+ const char *attrname, char ***_values)
+{
+ struct sss_sudo_attr *attr = NULL;
+ char **values = NULL;
+ int i, j;
+
+ for (i = 0; i < e->num_attrs; i++) {
+ attr = e->attrs + i;
+ if (strcasecmp(attr->name, attrname) == 0) {
+ values = calloc(attr->num_values + 1, sizeof(char*));
+ if (values == NULL) {
+ return ENOMEM;
+ }
+
+ for (j = 0; j < attr->num_values; j++) {
+ values[j] = strdup(attr->values[j]);
+ if (values[j] == NULL) {
+ sss_sudo_free_values(values);
+ return ENOMEM;
+ }
+ }
+
+ values[attr->num_values] = NULL;
+
+ break;
+ }
+ }
+
+ if (values == NULL) {
+ return ENOENT;
+ }
+
+ *_values = values;
+
+ return EOK;
+}
+
+void sss_sudo_free_values(char **values)
+{
+ char **value = NULL;
+
+ if (values == NULL) {
+ return;
+ }
+
+ for (value = values; *value != NULL; value++) {
+ free(*value);
+ }
+
+ free(values);
+}
+
+void sss_sudo_free_result(struct sss_sudo_result *result)
+{
+ if (result == NULL) {
+ return;
+ }
+
+ sss_sudo_free_rules(result->num_rules, result->rules);
+ free(result);
+}
+
+void sss_sudo_free_rules(unsigned int num_rules, struct sss_sudo_rule *rules)
+{
+ struct sss_sudo_rule *rule = NULL;
+ int i;
+
+ if (rules == NULL) {
+ return;
+ }
+
+ for (i = 0; i < num_rules; i++) {
+ rule = rules + i;
+
+ sss_sudo_free_attrs(rule->num_attrs, rule->attrs);
+ rule->attrs = NULL;
+ }
+
+ free(rules);
+}
+
+void sss_sudo_free_attrs(unsigned int num_attrs, struct sss_sudo_attr *attrs)
+{
+ struct sss_sudo_attr *attr = NULL;
+ int i, j;
+
+ if (attrs == NULL) {
+ return;
+ }
+
+ for (i = 0; i < num_attrs; i++) {
+ attr = attrs + i;
+
+ free(attr->name);
+ attr->name = NULL;
+
+ for (j = 0; j < attr->num_values; j++) {
+ free(attr->values[j]);
+ attr->values[j] = NULL;
+ }
+
+ free(attr->values);
+ }
+
+ free(attrs);
+}
diff --git a/src/sss_client/sudo/sss_sudo.h b/src/sss_client/sudo/sss_sudo.h
new file mode 100644
index 0000000..dc41d9f
--- /dev/null
+++ b/src/sss_client/sudo/sss_sudo.h
@@ -0,0 +1,195 @@
+/*
+ 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/>.
+*/
+
+#ifndef SSS_SUDO_H_
+#define SSS_SUDO_H_
+
+/**
+ * @defgroup libsss_sudo A library for communication between SUDO and SSSD
+ * libsss_sudo provides a mechanism to for a SUDO plugin
+ * to communicate with the sudo responder of SSSD.
+ *
+ * @{
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/** The value returned when the communication with SUDO is successful and
+ * the user was found in one of the domains
+ */
+#define SSS_SUDO_ERROR_OK 0
+
+/**
+ * Component of an sss_rule structure. The component
+ * has exactly one name and one or more values.
+ *
+ */
+struct sss_sudo_attr {
+ /** The attribute name */
+ char *name;
+ /** A string array that contains all the attribute values */
+ char **values;
+
+ /** The number of values the attribute contains.
+ *
+ * Attributes are multivalued in general.
+ */
+ unsigned int num_values;
+};
+
+/**
+ * One sudo rule. The rule consists of one or more
+ * attributes of sss_attr type
+ */
+struct sss_sudo_rule {
+ /** The number of attributes in the rule */
+ unsigned int num_attrs;
+
+ /** List of rule attributes */
+ struct sss_sudo_attr *attrs;
+};
+
+/**
+ * A result object returned from SSSD.
+ *
+ * The result consists of zero or more sss_rule elements.
+ */
+struct sss_sudo_result {
+ /**
+ * The number of rules for the user
+ *
+ * In case the user exists in one of SSSD domains
+ * but no rules match for him, the num_rules element
+ * is 0.
+ */
+ unsigned int num_rules;
+
+ /** List of rules found */
+ struct sss_sudo_rule *rules;
+};
+
+/**
+ * @brief Send a request to SSSD to retrieve all SUDO rules for a given
+ * user.
+ *
+ * @param[in] uid The uid of the user to retrieve the rules for.
+ * @param[in] username The username to retrieve the rules for
+ * @param[in] domainname The domain name the user is a member of.
+ * @param[out] _error The result of the search in SSSD's domains. If the
+ * user was present in the domain, the _error code is
+ * SSS_SUDO_ERROR_OK and the _result structure is
+ * returned even if it was empty (in other words
+ * _result->num_rules == 0). Other problems are returned
+ * as errno codes. Most prominently these are ENOENT
+ * (the user was not found with SSSD), EIO (SSSD
+ * encountered an internal problem) and EINVAL
+ * (malformed query).
+ * @param[out] _result Newly allocated structure sss_result that contains
+ * the rules for the user. If no rules were found but
+ * the user was valid, this structure is "empty", which
+ * means that the num_rules member is 0.
+ *
+ * @return 0 on success and other errno values on failure. The return value
+ * denotes whether communication with SSSD was successful. It does not
+ * tell whether the result contains any rules or whether SSSD knew the
+ * user at all. That information is transferred in the _error parameter.
+ */
+int sss_sudo_send_recv(uid_t uid,
+ const char *username,
+ const char *domainname,
+ uint32_t *_error,
+ struct sss_sudo_result **_result);
+
+/**
+ * @brief Send a request to SSSD to retrieve the default options, commonly
+ * stored in the "cn=defaults" record,
+ *
+ * @param[in] uid The uid of the user to retrieve the rules for.
+ *
+ * @param[in] username The username to retrieve the rules for.
+ *
+ * @param[out] _error The result of the search in SSSD's domains. If the
+ * options were present in the domain, the _error code
+ * is SSS_SUDO_ERROR_OK and the _result structure is
+ * returned even if it was empty (in other words
+ * _result->num_rules == 0). Other problems are returned
+ * as errno codes.
+ *
+ * @param[out] _domainname The domain name the user is a member of.
+ *
+ * @param[out] _result Newly allocated structure sss_result that contains
+ * the options. If no options were found this structure
+ * is "empty", which means that the num_rules member
+ * is 0.
+ *
+ * @return 0 on success and other errno values on failure. The return value
+ * denotes whether communication with SSSD was successful. It does not
+ * tell whether the result contains any rules or whether SSSD knew the
+ * user at all. That information is transferred in the _error parameter.
+ *
+ * @note The _domainname should be freed using free().
+ */
+int sss_sudo_send_recv_defaults(uid_t uid,
+ const char *username,
+ uint32_t *_error,
+ char **_domainname,
+ struct sss_sudo_result **_result);
+
+/**
+ * @brief Free the sss_result structure returned by sss_sudo_send_recv
+ *
+ * @param[in] result The sss_result structure to free. The structure was
+ * previously returned by sss_sudo_get_values().
+ */
+void sss_sudo_free_result(struct sss_sudo_result *result);
+
+/**
+ * @brief Get all values for a given attribute in an sss_rule
+ *
+ * @param[in] e The sss_rule to get values from
+ * @param[in] attrname The name of the attribute to query from the rule
+ * @param[out] values A newly allocated list of values the attribute has in
+ * rule. On success, this parameter is an array of
+ * NULL-terminated strings, the last element is a NULL
+ * pointer. On failure (including when the attribute is
+ * not found), the pointer address is not changed.
+ *
+ * @return 0 on success, ENOENT in case the attribute is not found and other
+ * errno values on failure.
+ *
+ * @note the returned values should be freed using sss_sudo_free_values()
+ */
+int sss_sudo_get_values(struct sss_sudo_rule *e,
+ const char *attrname,
+ char ***values);
+
+/**
+ * @brief Free the values returned by sss_sudo_get_values
+ *
+ * @param[in] values The list of values to free. The values were previously
+ * returned by sss_sudo_get_values()
+ */
+void sss_sudo_free_values(char **values);
+
+/**
+ * @}
+ */
+#endif /* SSS_SUDO_H_ */
diff --git a/src/sss_client/sudo/sss_sudo_private.h b/src/sss_client/sudo/sss_sudo_private.h
new file mode 100644
index 0000000..2827a94
--- /dev/null
+++ b/src/sss_client/sudo/sss_sudo_private.h
@@ -0,0 +1,33 @@
+/*
+ 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/>.
+*/
+
+#ifndef SSS_SUDO_PRIVATE_H_
+#define SSS_SUDO_PRIVATE_H_
+
+#include <stdint.h>
+#include "sss_client/sudo/sss_sudo.h"
+
+int sss_sudo_parse_response(const char *message,
+ size_t message_len,
+ char **_domainname,
+ struct sss_sudo_result **_result,
+ uint32_t *_error);
+
+#endif /* SSS_SUDO_PRIVATE_H_ */
diff --git a/src/sss_client/sudo/sss_sudo_response.c b/src/sss_client/sudo/sss_sudo_response.c
new file mode 100644
index 0000000..7d4bcc5
--- /dev/null
+++ b/src/sss_client/sudo/sss_sudo_response.c
@@ -0,0 +1,257 @@
+/*
+ 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 "config.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "sss_client/sss_cli.h"
+#include "sss_client/sudo/sss_sudo.h"
+#include "sss_client/sudo/sss_sudo_private.h"
+
+static int sss_sudo_parse_rule(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ struct sss_sudo_rule *_rule);
+
+static int sss_sudo_parse_attr(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ struct sss_sudo_attr *_attr);
+
+static int sss_sudo_parse_uint32(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ uint32_t *_number);
+
+static int sss_sudo_parse_string(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ char **_str);
+
+int sss_sudo_parse_response(const char *message,
+ size_t message_len,
+ char **_domainname,
+ struct sss_sudo_result **_result,
+ uint32_t *_error)
+{
+ struct sss_sudo_result *result = NULL;
+ char *domainname = NULL;
+ size_t cursor = 0;
+ int ret = EOK;
+ int i = 0;
+
+ /* error code */
+ ret = sss_sudo_parse_uint32(message, message_len, &cursor, _error);
+ if (ret != EOK || *_error != SSS_SUDO_ERROR_OK) {
+ return ret;
+ }
+
+ /* domain name - deprecated
+ * it won't be used, but we will read it anyway to ease parsing
+ * TODO: when possible change the protocol */
+ ret = sss_sudo_parse_string(message, message_len, &cursor, &domainname);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ free(domainname);
+ if (_domainname != NULL) {
+ *_domainname = NULL;
+ }
+
+ /* result */
+ result = malloc(sizeof(struct sss_sudo_result));
+ if (result == NULL) {
+ return ENOMEM;
+ }
+
+ memset(result, 0, sizeof(struct sss_sudo_result));
+
+ /* rules_num */
+ ret = sss_sudo_parse_uint32(message, message_len,
+ &cursor, &result->num_rules);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ /* rules */
+ result->rules = calloc(result->num_rules, sizeof(struct sss_sudo_rule));
+ if (result->rules == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < result->num_rules; i++) {
+ ret = sss_sudo_parse_rule(message, message_len,
+ &cursor, &result->rules[i]);
+ if (ret != EOK) {
+ goto fail;
+ }
+ }
+
+ *_result = result;
+
+ return EOK;
+
+fail:
+ sss_sudo_free_result(result);
+ return ret;
+}
+
+int sss_sudo_parse_rule(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ struct sss_sudo_rule *_rule)
+{
+ int ret = EOK;
+ int i = 0;
+
+ /* attrs_num */
+ ret = sss_sudo_parse_uint32(message, message_len,
+ _cursor, &_rule->num_attrs);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* attrs */
+ _rule->attrs = calloc(_rule->num_attrs, sizeof(struct sss_sudo_attr));
+ if (_rule->attrs == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < _rule->num_attrs; i++) {
+ ret = sss_sudo_parse_attr(message, message_len,
+ _cursor, &_rule->attrs[i]);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+int sss_sudo_parse_attr(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ struct sss_sudo_attr *_attr)
+{
+ char *str = NULL;
+ int ret = EOK;
+ int i = 0;
+
+ /* name */
+ ret = sss_sudo_parse_string(message, message_len, _cursor, &str);
+ if (ret != EOK) {
+ return ret;
+ }
+ _attr->name = str;
+
+ /* values_num */
+ ret = sss_sudo_parse_uint32(message, message_len,
+ _cursor, &_attr->num_values);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* values */
+ _attr->values = calloc(_attr->num_values, sizeof(const char*));
+ if (_attr->values == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < _attr->num_values; i++) {
+ ret = sss_sudo_parse_string(message, message_len, _cursor, &str);
+ if (ret != EOK) {
+ return ret;
+ }
+ _attr->values[i] = str;
+ }
+
+ return EOK;
+}
+
+int sss_sudo_parse_uint32(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ uint32_t *_number)
+{
+ size_t start_pos = 0;
+
+ if (_cursor == NULL) {
+ return EINVAL;
+ }
+
+ start_pos = *_cursor;
+
+ if (start_pos + sizeof(uint32_t) > message_len) {
+ return EINVAL;
+ }
+
+ /* expanded SAFEALIGN_COPY_UINT32 macro from util.h */
+ memcpy(_number, message + start_pos, sizeof(uint32_t));
+ *_cursor = start_pos + sizeof(uint32_t);
+
+ return EOK;
+}
+
+int sss_sudo_parse_string(const char *message,
+ size_t message_len,
+ size_t *_cursor,
+ char **_str)
+{
+ const char *current = NULL;
+ char *str = NULL;
+ size_t start_pos = 0;
+ size_t len = 0;
+ size_t maxlen = 0;
+
+ if (_cursor == NULL) {
+ return EINVAL;
+ }
+
+ start_pos = *_cursor;
+ maxlen = message_len - start_pos;
+
+ if (start_pos >= message_len ) {
+ return EINVAL;
+ }
+
+ current = message + start_pos;
+ len = strnlen(current, maxlen);
+ if (len == maxlen) {
+ /* the string exceeds message length */
+ return EINVAL;
+ }
+
+ str = strndup(current, len);
+ if (str == NULL) {
+ return ENOMEM;
+ }
+
+ /* go after \0 */
+ *_cursor = start_pos + len + 1;
+ *_str = str;
+
+ return EOK;
+}