[SSSD] [PATCHES] SUDO integration - first iteration

Pavel Březina pbrezina at redhat.com
Mon Oct 10 13:20:02 UTC 2011


https://fedorahosted.org/sssd/ticket/623

Helpful links:
  - SUDO plugin API
    http://www.gratisoft.us/sudo/man/1.8.1/sudo_plugin.man.html

What does it do currently?
  1. sudo plugin sends input data to responder
  2. responder sends back to plugin that user is allowed to run the
     command

What does it not do?
  - Doesn't require any PAM authentication
  - Doesn't read anything from LDAP
  - Doesn't set any environment variables (and reset current environment)
    This actually can cause some troubles to applications, so far I've
    encountered an error message in VIM (no $HOME specified)

How to test it?
  1. Install SUDO version 1.8 or greater
     I am running 1.8.2 built from source:
       ftp://ftp.sudo.ws/pub/sudo/sudo-1.8.2.tar.gz

  2. Enable SUDO plugin in /etc/sudo.conf
     Plugin sss_sudo_policy /usr/lib/sudo/libsss_sudoplugin.so

     Unfortunately, SUDO doesn't allow to have more than one policy
     plugin activated, so comment out standard sudoers plugin.

  3. Enable it in sssd.conf ;-)
     services += sudo

  4. Run sssd

  5. Run sudo

I left there some debug messages, so don't worry when you see:
   CMD Return code: 0
   errnop: 0
   Command exited with status 0

in the output. But tell me if there is anything else than 0 :-)

[PATCH 1/5]
Adds a client function that allows client to send data to responder.
And set sudo responder protocol version.

[PATCH 2/5]
SUDO plugin.

[PATCH 3/5]
SUDO responder.

[PATCH 4/5]
Configure and Makefile updates so we can build plugin and responder.

[PATCH 5/5]
Just a little update that adds sudo responder to known services of monitor.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0001-SUDO-integration-client-common-interface.patch
URL: <https://lists.fedorahosted.org/pipermail/sssd-devel/attachments/20111010/41a704e7/attachment.ksh>
-------------- next part --------------
>From d76242ea5be9c9b7bf2dfbee9ba17b2d63d87612 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
Date: Fri, 30 Sep 2011 14:10:28 +0200
Subject: [PATCH 2/5] SUDO integration - SUDO plugin

---
 src/sss_client/sudo_plugin/sss_sudoplugin.c |  427 +++++++++++++++++++++++++++
 src/sss_client/sudo_plugin/sss_sudoplugin.h |   46 +++
 2 files changed, 473 insertions(+), 0 deletions(-)
 create mode 100644 src/sss_client/sudo_plugin/sss_sudoplugin.c
 create mode 100644 src/sss_client/sudo_plugin/sss_sudoplugin.h

diff --git a/src/sss_client/sudo_plugin/sss_sudoplugin.c b/src/sss_client/sudo_plugin/sss_sudoplugin.c
new file mode 100644
index 0000000..ec62dee
--- /dev/null
+++ b/src/sss_client/sudo_plugin/sss_sudoplugin.c
@@ -0,0 +1,427 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at 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 <limits.h>
+#include <sys/stat.h>
+#include <sudo_plugin.h>
+
+#include "sss_client/sudo_plugin/sss_sudoplugin.h"
+#include "sss_client/sss_cli.h"
+
+int policy_open(unsigned int version,
+                sudo_conv_t conversation,
+                sudo_printf_t plugin_printf,
+                char * const settings[],
+                char * const user_info[],
+                char * const user_env[]);
+
+void policy_close(int exit_status,
+                  int error);
+
+int policy_version(int verbose);
+
+int policy_list(int argc,
+                char * const argv[],
+                int verbose,
+                const char *list_user);
+
+int policy_check(int argc,
+                 char * const argv[],
+                 char *env_add[],
+                 char **command_out[],
+                 char **argv_out[],
+                 char **user_env_out[]);
+
+static errno_t policy_check_create_query(const char *qualified_command_path,
+                                         char * const *settings,
+                                         char * const *user_info,
+                                         char * const *user_env,
+                                         char * const *env_add,
+                                         int argc,
+                                         char * const argv[],
+                                         char **query,
+                                         int *query_length);
+
+static errno_t policy_check_parse_response(char *response,
+                                           int response_length,
+                                           int *result,
+                                           char ***_command_out,
+                                           char ***_argv_out,
+                                           char ***_user_env_out);
+
+static char * get_qualified_command_path(const char *command);
+
+
+/* SUDO Plugin structure */
+struct policy_plugin sss_sudo_policy = {
+    SUDO_POLICY_PLUGIN,
+    SUDO_API_VERSION,
+    policy_open,
+    policy_close,
+    policy_version,
+    policy_check,
+    policy_list,
+    NULL, /* validate */
+    NULL, /* invalidate */
+    NULL /* session init */
+};
+
+/* Global plugin state initialized from policy_check with data passed by SUDO */
+struct plugin_state plugin = {NULL, NULL, NULL, NULL, NULL};
+
+int policy_open(unsigned int version,
+                sudo_conv_t conversation,
+                sudo_printf_t _printf,
+                char * const settings[],
+                char * const user_info[],
+                char * const user_env[])
+{
+    if (conversation == NULL || _printf == NULL) {
+        return SSS_SUDO_USAGE_ERROR;
+    }
+
+    /* check Plugin API version */
+
+    /*
+     * TODO: Do we need to check major and minor version or major is enough?
+     */
+    if (version != SUDO_API_VERSION) {
+        _printf(SUDO_CONV_ERROR_MSG, "The SSS SUDO plugin requires "
+                                     "API version %d. Your version is %d",
+                                     SUDO_API_VERSION, version);
+
+        return SSS_SUDO_GENERAL_ERROR;
+    }
+
+    /* save input variables */
+
+    plugin.conversation = conversation;
+    plugin.printf = _printf;
+    plugin.settings = settings;
+    plugin.user_info = user_info;
+    plugin.user_env = user_env;
+
+    return SSS_SUDO_SUCCESS;
+}
+
+void policy_close(int exit_status, int error)
+{
+    if (error) {
+        plugin.printf(SUDO_CONV_ERROR_MSG, "Command error: %s\n", strerror(error));
+    } else if (WIFEXITED(exit_status)) {
+        plugin.printf(SUDO_CONV_INFO_MSG, "Command exited with status %d\n",
+                    WEXITSTATUS(exit_status));
+    } else if (WIFSIGNALED(exit_status)) {
+        plugin.printf(SUDO_CONV_INFO_MSG, "Command was killed by signal %d\n",
+                    WTERMSIG(exit_status));
+    }
+
+    return;
+}
+
+int policy_version(int verbose)
+{
+    return SSS_SUDO_SUCCESS;
+}
+
+int policy_list(int argc,
+                char * const argv[],
+                int verbose,
+                const char *list_user)
+{
+    return SSS_SUDO_SUCCESS;
+}
+
+int policy_check(int argc,
+                 char * const argv[],
+                 char *env_add[],
+                 char **command_out[],
+                 char **argv_out[],
+                 char **user_env_out[])
+{
+    char *qualified_command_path = NULL;
+    char *query = NULL;
+    int query_length = 0;
+    int ret = 0;
+    int errnop;
+    int sudo_result = SSS_SUDO_FAILURE;
+    struct sss_cli_req_data request_data;
+    uint8_t *reply_buf = NULL;
+    size_t reply_len;
+
+    if (argc <= 0) {
+        plugin.printf(SUDO_CONV_ERROR_MSG, "sudo: no command specified!\n");
+        return SSS_SUDO_USAGE_ERROR;
+    }
+
+    /* Does command exists? */
+    qualified_command_path = get_qualified_command_path(argv[0]);
+    if (qualified_command_path == NULL) {
+        plugin.printf(SUDO_CONV_ERROR_MSG,
+                      "sudo: %s: command not found\n", argv[0]);
+        return SSS_SUDO_GENERAL_ERROR;
+    }
+
+    /* create query data */
+    ret = policy_check_create_query(qualified_command_path, plugin.settings,
+                                    plugin.user_info, plugin.user_env,
+                                    env_add, argc, argv,
+                                    &query, &query_length);
+    if (ret != EOK) {
+        plugin.printf(SUDO_CONV_ERROR_MSG,
+                      "sudo: unable to create query string: %s\n",
+                      strerror(ret));
+        ret = SSS_SUDO_GENERAL_ERROR;
+        goto done;
+    }
+    request_data.len = query_length;
+    request_data.data = (const void*)query;
+
+    /* send query */
+    errnop = 0;
+    ret = sss_sudo_make_request(SSS_SUDO_CHECK, &request_data, &reply_buf,
+                                &reply_len, &errnop);
+    if (errnop != 0) {
+        plugin.printf(SUDO_CONV_ERROR_MSG,
+                      "Unable contact SSSD responder: %s\n", strerror(errnop));
+        ret = SSS_SUDO_GENERAL_ERROR;
+        goto done;
+    }
+
+    /* process response */
+    ret = policy_check_parse_response((char*)reply_buf, reply_len, &sudo_result,
+                                      command_out, argv_out, user_env_out);
+    if (ret != EOK) {
+        plugin.printf(SUDO_CONV_ERROR_MSG,
+                      "sudo: unable to parse response: %s\n",
+                      strerror(ret));
+        ret = SSS_SUDO_GENERAL_ERROR;
+        goto done;
+    }
+
+    plugin.printf(SUDO_CONV_INFO_MSG, "CMD Return code: %d\n", sudo_result);
+    plugin.printf(SUDO_CONV_INFO_MSG, "errnop: %d\n", errnop);
+
+    switch (sudo_result) {
+    case SSS_SUDO_RESPONSE_ALLOW:
+        ret = SSS_SUDO_SUCCESS;
+        break;
+    case SSS_SUDO_RESPONSE_AUTHENTICATE:
+        /* user can run the command, but must authenticate himself first */
+        /* TODO */
+        ret = SSS_SUDO_FAILURE;
+        break;
+    case SSS_SUDO_RESPONSE_DENY:
+        ret = SSS_SUDO_FAILURE;
+        break;
+    case SSS_SUDO_RESPONSE_UNKNOWN:
+        /* possibly local user, run sudoers plugin */
+        /* TODO */
+        ret = SSS_SUDO_GENERAL_ERROR;
+        plugin.printf(SUDO_CONV_ERROR_MSG, "sudo: Unknown user.\n");
+        break;
+    }
+
+done:
+    free(query);
+
+    return ret;
+}
+
+/*
+ * Creates query string in format:
+ * qualified_command_path\0argv[0]\0argv[i]\0\0
+ * env_add\0\0user_env\0\0settings\0\0user_info\0
+ *
+ * where env_add, user_env, settings and user_info are in the form of
+ * NAME=VALUE pairs.
+ */
+errno_t policy_check_create_query(const char *qualified_command_path,
+                                  char * const *settings,
+                                  char * const *user_info,
+                                  char * const *user_env,
+                                  char * const *env_add,
+                                  int argc,
+                                  char * const argv[],
+                                  char **query,
+                                  int *query_length)
+{
+#define APPEND_ELEMENT(element) do { \
+    iter_length = strlen(element) + 1; /* with ending \0 */ \
+    data = (char*)realloc(data, data_length + iter_length); \
+    if (data == NULL) { \
+        return ENOMEM; \
+    } \
+    memcpy(data + data_length, element, iter_length); \
+    data_length += iter_length; \
+} while(0)
+
+#define APPEND_ZERO() do { \
+    data_length++; \
+    data = (char*)realloc(data, data_length); \
+    data[data_length] = '\0'; \
+} while(0)
+
+    char *data = NULL;
+    int data_length = 0;
+    char * const *iter = NULL;
+    int iter_length = 0;
+    int i = 0;
+    char * const *fields[4] = { env_add, user_env, settings, user_info };
+
+    /* append qualified_command_path */
+
+    APPEND_ELEMENT(qualified_command_path);
+
+    /* append argv */
+
+    for (i = 0; i < argc; i++) {
+        APPEND_ELEMENT(argv[i]);
+    }
+    APPEND_ZERO();
+
+    /* append NAME=VALUE fields */
+    for (i = 0; i < 4; i++) {
+        if (*(fields[i]) == NULL) {
+            APPEND_ZERO();
+            APPEND_ZERO();
+        } else {
+            for (iter = fields[i]; *iter != NULL; iter++) {
+                APPEND_ELEMENT(*iter);
+            }
+            APPEND_ZERO();
+        }
+    }
+
+    *query_length = data_length;
+    *query = data;
+
+    return EOK;
+
+#undef APPEND_ELEMENT
+#undef APPEND_ZERO
+}
+
+errno_t policy_check_parse_response(char *response,
+                                    int response_length,
+                                    int *result,
+                                    char ***_command_out,
+                                    char ***_argv_out,
+                                    char ***_user_env_out)
+{
+#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; \
+        } \
+        current_position++; \
+    } \
+    i++; \
+    element = (char**)realloc(element, i * sizeof(char*)); \
+    element[i - 1] = NULL; \
+    current_position++; \
+} while(0)
+
+    char *current_position = NULL;
+    char **command_out = NULL;
+    char **argv_out = NULL;
+    char **user_env_out = NULL;
+    int i = 0;
+    int ret;
+
+    if (response_length <= 0 || response == NULL) {
+        return EINVAL;
+    }
+
+    /* get responder result */
+    *result = *((int*)response);
+    current_position = (char*)(((int*)response) + 1);
+
+    /* get argv_out */
+    LOAD_ARRAY(argv_out);
+
+    /* get command_out */
+    LOAD_ARRAY(command_out);
+
+    /* get user_env_out */
+    LOAD_ARRAY(user_env_out);
+
+    /* copy output */
+    *_command_out = command_out;
+    *_argv_out = argv_out;
+    *_user_env_out = user_env_out;
+
+    ret = EOK;
+
+done:
+    return ret;
+
+#undef LOAD_ARRAY
+}
+
+char * get_qualified_command_path(const char *command)
+{
+    struct stat sb;
+    char *path_env = NULL;
+    char *path = NULL;
+    char *cp = NULL;
+    char *qualified = NULL;
+    char pathbuf[PATH_MAX];
+
+    if (strchr(command, '/') != NULL) {
+        return NULL;
+    }
+
+    path_env = getenv("PATH");
+    path = path_env;
+
+    do {
+        cp = strchr(path, ':');
+        if (cp != NULL) {
+            *cp = '\0';
+        }
+
+        snprintf(pathbuf, sizeof(char) * PATH_MAX, "%s/%s", path, command);
+        if (stat(pathbuf, &sb) == 0) {
+            if (S_ISREG(sb.st_mode)
+                    && (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
+                qualified = pathbuf;
+                break;
+            }
+        }
+
+        path = cp + 1;
+    } while(cp != NULL);
+
+    /* free(path_env); do not free since it is from getenv() */
+    return qualified ? strdup(qualified) : NULL;
+}
diff --git a/src/sss_client/sudo_plugin/sss_sudoplugin.h b/src/sss_client/sudo_plugin/sss_sudoplugin.h
new file mode 100644
index 0000000..464b0e6
--- /dev/null
+++ b/src/sss_client/sudo_plugin/sss_sudoplugin.h
@@ -0,0 +1,46 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at 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_SUDOPLUGIN_H_
+#define SSS_SUDOPLUGIN_H_
+
+#define SSS_SUDO_SUCCESS 1
+#define SSS_SUDO_FAILURE 0
+#define SSS_SUDO_GENERAL_ERROR -1
+#define SSS_SUDO_USAGE_ERROR -2
+
+#define SSS_SUDO_RESPONSE_ALLOW 0        /* allow to run the command */
+#define SSS_SUDO_RESPONSE_DENY 1         /* disallow to run the command */
+#define SSS_SUDO_RESPONSE_UNKNOWN 2      /* user is not known, might be local */
+#define SSS_SUDO_RESPONSE_AUTHENTICATE 3 /* allow but authenticate user first */
+
+#ifndef EOK
+    #define EOK 0
+#endif
+
+struct plugin_state {
+    sudo_conv_t conversation;
+    sudo_printf_t printf;
+    char * const *settings;
+    char * const *user_info;
+    char * const *user_env;
+};
+
+#endif /* SSS_SUDOPLUGIN_H_ */
-- 
1.7.6

-------------- next part --------------
>From f3dee545cb8bd9defc2c55275059dfacd1f22f11 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
Date: Mon, 3 Oct 2011 17:23:35 +0200
Subject: [PATCH 3/5] SUDO integration - SUDO responder

---
 src/confdb/confdb.h              |    3 +
 src/responder/sudo/sudosrv.c     |  217 +++++++++++++++++++++++++++++
 src/responder/sudo/sudosrv.h     |   39 +++++
 src/responder/sudo/sudosrv_cmd.c |  285 ++++++++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h         |    3 +
 5 files changed, 547 insertions(+), 0 deletions(-)
 create mode 100644 src/responder/sudo/sudosrv.c
 create mode 100644 src/responder/sudo/sudosrv.h
 create mode 100644 src/responder/sudo/sudosrv_cmd.c

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 266e4d2..e50829e 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -91,6 +91,9 @@
 #define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
 #define CONFDB_PAM_PWD_EXPIRATION_WARNING "pam_pwd_expiration_warning"
 
+/* SUDO */
+#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
+
 /* Data Provider */
 #define CONFDB_DP_CONF_ENTRY "config/dp"
 
diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
new file mode 100644
index 0000000..7c90c53
--- /dev/null
+++ b/src/responder/sudo/sudosrv.c
@@ -0,0 +1,217 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at 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 <popt.h>
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "monitor/monitor_interfaces.h"
+#include "responder/common/responder.h"
+#include "responder/sudo/sudosrv.h"
+#include "providers/data_provider.h"
+
+struct sbus_method monitor_sudo_methods[] = {
+    { MON_CLI_METHOD_PING, monitor_common_pong },
+    { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
+    { MON_CLI_METHOD_ROTATE, responder_logrotate },
+    { NULL, NULL }
+};
+
+struct sbus_interface monitor_sudo_interface = {
+    MONITOR_INTERFACE,
+    MONITOR_PATH,
+    SBUS_DEFAULT_VTABLE,
+    monitor_sudo_methods,
+    NULL
+};
+
+static struct sbus_method sudo_dp_methods[] = {
+    { NULL, NULL }
+};
+
+struct sbus_interface sudo_dp_interface = {
+    DP_INTERFACE,
+    DP_PATH,
+    SBUS_DEFAULT_VTABLE,
+    sudo_dp_methods,
+    NULL
+};
+
+
+static void sudo_dp_reconnect_init(struct sbus_connection *conn,
+                                  int status, void *pvt)
+{
+    struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
+    int ret;
+
+    /* Did we reconnect successfully? */
+    if (status == SBUS_RECONNECT_SUCCESS) {
+        DEBUG(1, ("Reconnected to the Data Provider.\n"));
+
+        /* Identify ourselves to the data provider */
+        ret = dp_common_send_id(be_conn->conn,
+                                DATA_PROVIDER_VERSION,
+                                "SUDO");
+        /* all fine */
+        if (ret == EOK) {
+            handle_requests_after_reconnect();
+            return;
+        }
+    }
+
+    /* Failed to reconnect */
+    DEBUG(0, ("Could not reconnect to %s provider.\n",
+              be_conn->domain->name));
+}
+
+static int sudo_ctx_destructor(void *memctx)
+{
+    // struct sudo_ctx *sctx = (struct sudo_ctx*)memctx;
+
+    // TODO
+
+    return 0;
+}
+
+int sudo_process_init(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+                     struct confdb_ctx *cdb)
+{
+    struct sss_cmd_table *sudo_cmds;
+    struct be_conn *iter;
+    struct sudo_ctx *sctx;
+    int ret;
+    int max_retries;
+
+    sctx = talloc_zero(mem_ctx, struct sudo_ctx);
+    if (!sctx) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("fatal error initializing sudo_ctx\n"));
+        return ENOMEM;
+    }
+    talloc_set_destructor((TALLOC_CTX *)sctx, sudo_ctx_destructor);
+
+    /*
+     * TODO set up negative cache
+    ret = sss_ncache_init(nctx, &nctx->ncache);
+    if (ret != EOK) {
+        DEBUG(0, ("fatal error initializing negative cache\n"));
+        return ret;
+    }
+    */
+
+    sudo_cmds = get_sudo_cmds();
+    ret = sss_process_init(sctx, ev, cdb,
+                           sudo_cmds,
+                           SSS_SUDO_SOCKET_NAME, NULL,
+                           CONFDB_SUDO_CONF_ENTRY,
+                           SSS_SUDO_SBUS_SERVICE_NAME,
+                           SSS_SUDO_SBUS_SERVICE_VERSION,
+                           &monitor_sudo_interface,
+                           "SUDO",
+                           &sudo_dp_interface,
+                           &sctx->rctx);
+    if (ret != EOK) {
+        return ret;
+    }
+    sctx->rctx->pvt_ctx = sctx;
+
+    /*
+     * TODO get sudo config
+    ret = sudo_get_config(sctx, sctx->rctx, cdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("fatal error getting sudo config\n"));
+        return ret;
+    }
+    */
+
+    /* Enable automatic reconnection to the Data Provider */
+    ret = confdb_get_int(sctx->rctx->cdb, sctx->rctx,
+                         CONFDB_SUDO_CONF_ENTRY,
+                         CONFDB_SERVICE_RECON_RETRIES,
+                         3, &max_retries);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to set up automatic reconnection\n"));
+        return ret;
+    }
+
+    for (iter = sctx->rctx->be_conns; iter; iter = iter->next) {
+        sbus_reconnect_init(iter->conn, max_retries,
+                            sudo_dp_reconnect_init, iter);
+    }
+
+    DEBUG(1, ("SUDO Initialization complete\n"));
+
+    return EOK;
+}
+
+int main(int argc, const char *argv[])
+{
+    int opt;
+    poptContext pc;
+    struct main_context *main_ctx;
+    int ret;
+
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_MAIN_OPTS
+        POPT_TABLEEND
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                  poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+
+    poptFreeContext(pc);
+
+    CONVERT_AND_SET_DEBUG_LEVEL(debug_level);
+
+    /* set up things like debug, signals, daemonization, etc... */
+    debug_log_file = "sssd_sudo";
+
+    ret = server_setup("sssd[sudo]", 0, CONFDB_SUDO_CONF_ENTRY, &main_ctx);
+    if (ret != EOK) return 2;
+
+    ret = die_if_parent_died();
+    if (ret != EOK) {
+        /* This is not fatal, don't return */
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not set up to exit "
+                                  "when parent process does\n"));
+    }
+
+    ret = sudo_process_init(main_ctx,
+                            main_ctx->event_ctx,
+                            main_ctx->confdb_ctx);
+    if (ret != EOK) return 3;
+
+    /* loop on main */
+    server_loop(main_ctx);
+
+    return 0;
+}
diff --git a/src/responder/sudo/sudosrv.h b/src/responder/sudo/sudosrv.h
new file mode 100644
index 0000000..9a453d1
--- /dev/null
+++ b/src/responder/sudo/sudosrv.h
@@ -0,0 +1,39 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at 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 SUDOSRV_H_
+#define SUDOSRV_H_
+
+#define SSS_SUDO_SBUS_SERVICE_VERSION 0x0001
+#define SSS_SUDO_SBUS_SERVICE_NAME "sudo"
+
+struct sudo_ctx {
+    struct resp_ctx *rctx;
+    struct sss_nc_ctx *ncache;
+
+    int neg_timeout;
+    time_t id_timeout;
+};
+
+int sudo_cmd_execute(struct cli_ctx *cctx);
+
+struct sss_cmd_table *get_sudo_cmds(void);
+
+#endif /* SUDOSRV_H_ */
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
new file mode 100644
index 0000000..ee9060f
--- /dev/null
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -0,0 +1,285 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at 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 */
+
+    /* TOOD 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;
+}
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index efd83c9..16dec1a 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -144,6 +144,9 @@ enum sss_cli_command {
     SSS_NSS_ENDSPENT       = 0x00B5,
 #endif
 
+/* SUDO */
+    SSS_SUDO_CHECK = 0x00C1,
+
 /* PAM related calls */
     SSS_PAM_AUTHENTICATE     = 0x00F1, /**< see pam_sm_authenticate(3) for
                                         * details.
-- 
1.7.6

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0004-SUDO-integration-configure-and-makefile-updated.patch
URL: <https://lists.fedorahosted.org/pipermail/sssd-devel/attachments/20111010/41a704e7/attachment-0001.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0005-SUDO-integration-added-to-known-services.patch
URL: <https://lists.fedorahosted.org/pipermail/sssd-devel/attachments/20111010/41a704e7/attachment-0002.ksh>


More information about the sssd-devel mailing list