[SSSD] [PATCH] Add experimental support to receive PAC via GSSAPI

Sumit Bose sbose at redhat.com
Thu May 26 10:56:30 UTC 2011


Hi,

this series of patches adds support to receive a windows PAC via GSSAPI
and to create a user based on the data in the PAC. This is useful
because in an environment with lots of trust relationships between AD
server it might be quite time consuming to find out about all the group
memberships of a domain user by querying the domain controllers. But the
PAC contains all information about group memberships of the
corresponding user.

The general idea is to add the user, if it doesn't exist in the cache,
to the cache of the corresponding domain (see thread about sub-domains,
currently this patch add the user to the local domain for simplicity)
and to add all group memberships (currently not implemented). If one of
the groups cannot be found in the cache a dummy entry with all data
needed to resolve this group quickly is added to the cache.

Currently there are a couple of loose end, e.g.
- groups and group memberships are not handled
- PAC is not validated
- missing sub-domains
- no real SID to uid/gid mapping

etc, but I like to start the discussion about the code and the general
direction as soon as possible. Currently sssd with these patches can
only be build on rawhide, because of the dependencies to the samba4
package (libndr-krb5pac).

Patch 0007 contains a little example that demonstrates that the pac
responder can also be used to add user and groups based on other input,
e.g. it can be used as a backend for the sss_* utilities. This would
allow a much better control about which user is allowed to do what kind
of operation. Currently only the root user can add and modify user and
group entries with the sss_* tools.

I have used 'pac' as a part of names here because this was the original
target, but I would be happy to change it to a more generic keyword if
anyone has a good suggestion.

bye,
Sumit
-------------- next part --------------
From 7b69bdf15e4e01255071a52fc5d67eabd284ff9f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 13 May 2011 18:44:15 +0200
Subject: [PATCH 1/7] Add configure option to build pac responder

---
 configure.ac                  |    1 +
 src/external/pac_responder.m4 |   29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)
 create mode 100644 src/external/pac_responder.m4

diff --git a/configure.ac b/configure.ac
index 972c24c..71dc14e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,6 +113,7 @@ m4_include([src/external/nsupdate.m4])
 m4_include([src/external/libkeyutils.m4])
 m4_include([src/external/libnl.m4])
 m4_include([src/external/systemd.m4])
+m4_include([src/external/pac_responder.m4])
 m4_include([src/util/signal.m4])
 
 WITH_INITSCRIPT
diff --git a/src/external/pac_responder.m4 b/src/external/pac_responder.m4
new file mode 100644
index 0000000..a3f997e
--- /dev/null
+++ b/src/external/pac_responder.m4
@@ -0,0 +1,29 @@
+AC_SUBST(NDR_KRB5PAC_CFLAGS)
+AC_SUBST(NDR_KRB5PAC_LIBS)
+
+AC_ARG_ENABLE([experimental-pac-responder],
+              [AS_HELP_STRING([--enable-experimental-pac-responder],
+                              [build experimental pac responder])],
+              [build_pac_responder=$enableval],
+              [build_pac_responder=no])
+
+if test x$build_pac_responder == xyes
+then
+    PKG_CHECK_MODULES(NDR_KRB5PAC, ndr_krb5pac,,
+        AC_MSG_ERROR([Cannot build pac responder without libndr_krb5pac]))
+
+    AC_PATH_PROG(KRB5_CONFIG, krb5-config)
+    AC_MSG_CHECKING(for supported MIT krb5 version)
+    KRB5_VERSION="`$KRB5_CONFIG --version`"
+    case $KRB5_VERSION in
+        Kerberos\ 5\ release\ 1.9*)
+            AC_MSG_RESULT(yes)
+            ;;
+        *)
+            AC_MSG_ERROR([Cannot build authdata plugin with this version of
+                          MIT Kerberos, please use 1.9.x])
+    esac
+fi
+
+AM_CONDITIONAL([BUILD_PAC_RESPONDER], [test x$build_pac_responder = xyes ])
+
-- 
1.7.5.1

-------------- next part --------------
From 5cc254403d56e3c2bbf0ba6b543d92e33ae3d71e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 19 Apr 2011 15:49:01 +0200
Subject: [PATCH 2/7] Add infrastructure for pac responder

---
 Makefile.am                    |   20 ++++
 src/confdb/confdb.h            |    3 +
 src/monitor/monitor.c          |    2 +-
 src/responder/pac/pacsrv.c     |  229 ++++++++++++++++++++++++++++++++++++++++
 src/responder/pac/pacsrv.h     |   51 +++++++++
 src/responder/pac/pacsrv_cmd.c |   60 +++++++++++
 6 files changed, 364 insertions(+), 1 deletions(-)
 create mode 100644 src/responder/pac/pacsrv.c
 create mode 100644 src/responder/pac/pacsrv.h
 create mode 100644 src/responder/pac/pacsrv_cmd.c

diff --git a/Makefile.am b/Makefile.am
index 8bde56b..1716be6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,6 +65,10 @@ sssdlibexec_PROGRAMS = \
     ldap_child \
     proxy_child
 
+if BUILD_PAC_RESPONDER
+    sssdlibexec_PROGRAMS += sssd_pac
+endif
+
 if HAVE_CHECK
     non_interactive_check_based_tests = \
         sysdb-tests \
@@ -190,6 +194,7 @@ AM_CPPFLAGS = \
     -DSSSD_CONF_DIR=\"$(sssdconfdir)\" \
     -DSSS_NSS_SOCKET_NAME=\"$(pipepath)/nss\" \
     -DSSS_PAM_SOCKET_NAME=\"$(pipepath)/pam\" \
+    -DSSS_PAC_SOCKET_NAME=\"$(pipepath)/pac\" \
     -DSSS_PAM_PRIV_SOCKET_NAME=\"$(pipepath)/private/pam\" \
     -DLOCALEDIR=\"$(localedir)\"
 
@@ -288,6 +293,7 @@ dist_noinst_HEADERS = \
     src/responder/nss/nsssrv.h \
     src/responder/nss/nsssrv_private.h \
     src/responder/nss/nsssrv_netgroup.h \
+    src/responder/pac/pacsrv.h \
     src/responder/common/negcache.h \
     src/sbus/sbus_client.h \
     src/sbus/sssd_dbus.h \
@@ -398,6 +404,20 @@ sssd_pam_LDADD = \
     $(SSSD_LIBS) \
     libsss_util.la
 
+sssd_pac_SOURCES = \
+    src/responder/pac/pacsrv.c \
+    src/responder/pac/pacsrv_cmd.c \
+    $(SSSD_UTIL_OBJ) \
+    $(SSSD_RESPONDER_OBJ)
+sssd_pac_CFLAGS = \
+    $(AM_CFLAGS) \
+    $(NDR_KRB5PAC_CFLAGS)
+sssd_pac_LDADD = \
+    $(NDR_KRB5PAC_LIBS) \
+    $(TDB_LIBS) \
+    $(SSSD_LIBS) \
+    libsss_util.la
+
 sssd_be_SOURCES = \
     src/providers/data_provider_be.c \
     src/providers/data_provider_fo.c \
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index c2ae9fc..4f75af8 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -88,6 +88,9 @@
 #define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
 #define CONFDB_PAM_PWD_EXPIRATION_WARNING "pam_pwd_expiration_warning"
 
+/* PAC */
+#define CONFDB_PAC_CONF_ENTRY "config/pac"
+
 /* Data Provider */
 #define CONFDB_DP_CONF_ENTRY "config/dp"
 
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index d1f2e66..bb47a53 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -818,7 +818,7 @@ static int check_local_domain_unique(struct sss_domain_info *domains)
 
 static char *check_services(char **services)
 {
-    const char *known_services[] = { "nss", "pam", NULL };
+    const char *known_services[] = { "nss", "pam", "pac", NULL };
     int i;
     int ii;
 
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
new file mode 100644
index 0000000..e8a9842
--- /dev/null
+++ b/src/responder/pac/pacsrv.c
@@ -0,0 +1,229 @@
+/*
+   SSSD
+
+   PAC Responder
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2011
+
+   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 <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "popt.h"
+#include "util/util.h"
+#include "responder/pac/pacsrv.h"
+#include "db/sysdb.h"
+#include "confdb/confdb.h"
+#include "dbus/dbus.h"
+#include "sbus/sssd_dbus.h"
+#include "responder/common/responder_packet.h"
+#include "responder/common/responder.h"
+#include "providers/data_provider.h"
+#include "monitor/monitor_interfaces.h"
+#include "sbus/sbus_client.h"
+
+#define SSS_PAC_PIPE_NAME "pac"
+
+struct sbus_method monitor_pac_methods[] = {
+    { MON_CLI_METHOD_PING, monitor_common_pong },
+    { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
+    { MON_CLI_METHOD_ROTATE, monitor_common_rotate_logs },
+    { NULL, NULL }
+};
+
+struct sbus_interface monitor_pac_interface = {
+    MONITOR_INTERFACE,
+    MONITOR_PATH,
+    SBUS_DEFAULT_VTABLE,
+    monitor_pac_methods,
+    NULL
+};
+
+static int pac_get_config(struct pac_ctx *pac_ctx,
+                          struct resp_ctx *rctx,
+                          struct confdb_ctx *cdb)
+{
+    TALLOC_CTX *tmpctx;
+    int ret = 0;
+
+    tmpctx = talloc_new(pac_ctx);
+    if (!tmpctx) return ENOMEM;
+
+    goto done;
+
+    ret = 0;
+done:
+    talloc_free(tmpctx);
+    return ret;
+}
+
+static struct sbus_method pac_dp_methods[] = {
+    { NULL, NULL }
+};
+
+struct sbus_interface pac_dp_interface = {
+    DP_INTERFACE,
+    DP_PATH,
+    SBUS_DEFAULT_VTABLE,
+    pac_dp_methods,
+    NULL
+};
+
+
+/* TODO: check if this can be made generic for all responders */
+static void pac_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,
+                                "PAC");
+        /* 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));
+
+    /* FIXME: kill the frontend and let the monitor restart it ? */
+    /* nss_shutdown(rctx); */
+}
+
+int pac_process_init(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+                     struct confdb_ctx *cdb)
+{
+    struct sss_cmd_table *pac_cmds;
+    struct be_conn *iter;
+    struct pac_ctx *pac_ctx;
+    int ret, max_retries;
+
+    pac_ctx = talloc_zero(mem_ctx, struct pac_ctx);
+    if (!pac_ctx) {
+        DEBUG(0, ("fatal error initializing pac_ctx\n"));
+        return ENOMEM;
+    }
+
+    pac_cmds = get_pac_cmds();
+
+    ret = sss_process_init(pac_ctx, ev, cdb,
+                           pac_cmds,
+                           SSS_PAC_SOCKET_NAME, NULL,
+                           CONFDB_PAC_CONF_ENTRY,
+                           PAC_SBUS_SERVICE_NAME,
+                           PAC_SBUS_SERVICE_VERSION,
+                           &monitor_pac_interface,
+                           "PAC", &pac_dp_interface,
+                           &pac_ctx->rctx);
+    if (ret != EOK) {
+        return ret;
+    }
+    pac_ctx->rctx->pvt_ctx = pac_ctx;
+
+    ret = pac_get_config(pac_ctx, pac_ctx->rctx, cdb);
+    if (ret != EOK) {
+        DEBUG(0, ("fatal error getting pac config\n"));
+        return ret;
+    }
+
+    /* Enable automatic reconnection to the Data Provider */
+    ret = confdb_get_int(pac_ctx->rctx->cdb, pac_ctx->rctx,
+                         CONFDB_PAC_CONF_ENTRY,
+                         CONFDB_SERVICE_RECON_RETRIES,
+                         3, &max_retries);
+    if (ret != EOK) {
+        DEBUG(0, ("Failed to set up automatic reconnection\n"));
+        return ret;
+    }
+
+    for (iter = pac_ctx->rctx->be_conns; iter; iter = iter->next) {
+        sbus_reconnect_init(iter->conn, max_retries,
+                            pac_dp_reconnect_init, iter);
+    }
+
+    DEBUG(1, ("PAC 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
+    };
+
+    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);
+
+   /* set up things like debug, signals, daemonization, etc... */
+    debug_log_file = "sssd_pac";
+
+    ret = server_setup("sssd[pac]", 0, CONFDB_PAC_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(2, ("Could not set up to exit when parent process does\n"));
+    }
+
+    ret = pac_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/pac/pacsrv.h b/src/responder/pac/pacsrv.h
new file mode 100644
index 0000000..1b28254
--- /dev/null
+++ b/src/responder/pac/pacsrv.h
@@ -0,0 +1,51 @@
+/*
+   SSSD
+
+   PAC Responder, header file
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2011
+
+   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 __PACSRV_H__
+#define __PACSRV_H__
+
+#include <stdint.h>
+#include <sys/un.h>
+#include "config.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "ldb.h"
+#include "dbus/dbus.h"
+#include "sbus/sssd_dbus.h"
+#include "responder/common/responder_packet.h"
+#include "responder/common/responder.h"
+
+#define PAC_SBUS_SERVICE_VERSION 0x0001
+#define PAC_SBUS_SERVICE_NAME "pac"
+
+#define PAC_PACKET_MAX_RECV_SIZE 1024
+
+struct getent_ctx;
+
+struct pac_ctx {
+    struct resp_ctx *rctx;
+};
+
+int pac_cmd_execute(struct cli_ctx *cctx);
+
+struct sss_cmd_table *get_pac_cmds(void);
+
+#endif /* __PACSRV_H__ */
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
new file mode 100644
index 0000000..42ff3f8
--- /dev/null
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -0,0 +1,60 @@
+/*
+   SSSD
+
+   PAC Responder
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2011
+
+   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 "util/util.h"
+#include "responder/pac/pacsrv.h"
+#include "confdb/confdb.h"
+#include "db/sysdb.h"
+
+struct cli_protocol_version *register_cli_protocol_version(void)
+{
+    static struct cli_protocol_version pac_cli_protocol_version[] = {
+        {1, "2011-04-12", "initial version"},
+        {0, NULL, NULL}
+    };
+
+    return pac_cli_protocol_version;
+}
+
+static struct sss_cmd_table pac_cmds[] = {
+    {SSS_GET_VERSION, sss_cmd_get_version},
+    {SSS_CLI_NULL, NULL}
+};
+
+struct sss_cmd_table *get_pac_cmds(void) {
+    return pac_cmds;
+}
+
+int pac_cmd_execute(struct cli_ctx *cctx)
+{
+    enum sss_cli_command cmd;
+    int i;
+
+    cmd = sss_packet_get_cmd(cctx->creq->in);
+
+    for (i = 0; pac_cmds[i].cmd != SSS_CLI_NULL; i++) {
+        if (cmd == pac_cmds[i].cmd) {
+            return pac_cmds[i].fn(cctx);
+        }
+    }
+
+    return EINVAL;
+}
-- 
1.7.5.1

-------------- next part --------------
From a0e30f1b7478d76f67dcf9375dedc5aa2e24a0d1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 13 May 2011 18:41:16 +0200
Subject: [PATCH 3/7] Add pac support to client

---
 src/sss_client/common.c  |   33 +++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h |    5 +++++
 2 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index b603305..537f28e 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -373,6 +373,8 @@ static bool sss_cli_check_version(const char *socket_name)
     } else if (strcmp(socket_name, SSS_PAM_SOCKET_NAME) == 0 ||
                strcmp(socket_name, SSS_PAM_PRIV_SOCKET_NAME) == 0) {
         expected_version = SSS_PAM_PROTOCOL_VERSION;
+    } else if (strcmp(socket_name, SSS_PAC_SOCKET_NAME) == 0) {
+        expected_version = SSS_PAC_PROTOCOL_VERSION;
     } else {
         return false;
     }
@@ -705,6 +707,37 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
     }
 }
 
+int sss_pac_make_request(enum sss_cli_command cmd,
+                         struct sss_cli_req_data *rd,
+                         uint8_t **repbuf, size_t *replen,
+                         int *errnop)
+{
+    enum sss_status ret;
+    char *envval;
+
+    /* avoid looping in the nss daemon */
+    envval = getenv("_SSS_LOOPS");
+    if (envval && strcmp(envval, "NO") == 0) {
+        return NSS_STATUS_NOTFOUND;
+    }
+
+    ret = sss_cli_check_socket(errnop, SSS_PAC_SOCKET_NAME);
+    if (ret != SSS_STATUS_SUCCESS) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
+    switch (ret) {
+    case SSS_STATUS_TRYAGAIN:
+        return NSS_STATUS_TRYAGAIN;
+    case SSS_STATUS_SUCCESS:
+        return NSS_STATUS_SUCCESS;
+    case SSS_STATUS_UNAVAIL:
+    default:
+        return NSS_STATUS_UNAVAIL;
+    }
+}
+
 errno_t check_server_cred(int sockfd)
 {
 #ifdef HAVE_UCRED
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index ebdcc26..7c0ec11 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -37,6 +37,7 @@ typedef int errno_t;
 
 #define SSS_NSS_PROTOCOL_VERSION 1
 #define SSS_PAM_PROTOCOL_VERSION 3
+#define SSS_PAC_PROTOCOL_VERSION 1
 
 /**
  * @defgroup sss_cli_command SSS client commands
@@ -444,6 +445,10 @@ int sss_pam_make_request(enum sss_cli_command cmd,
                                      struct sss_cli_req_data *rd,
                                      uint8_t **repbuf, size_t *replen,
                                      int *errnop);
+int sss_pac_make_request(enum sss_cli_command cmd,
+                         struct sss_cli_req_data *rd,
+                         uint8_t **repbuf, size_t *replen,
+                         int *errnop);
 
 #ifndef SAFEALIGN_COPY_UINT32
 static inline void
-- 
1.7.5.1

-------------- next part --------------
From 0f8453a07102da842b77538756dffe661f14c72c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 18 May 2011 13:28:17 +0200
Subject: [PATCH 4/7] Add server-side pac support

---
 src/responder/pac/pacsrv.c     |    2 +-
 src/responder/pac/pacsrv_cmd.c |  156 ++++++++++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h       |    3 +
 3 files changed, 160 insertions(+), 1 deletions(-)

diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index e8a9842..bc4a805 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -48,7 +48,7 @@
 struct sbus_method monitor_pac_methods[] = {
     { MON_CLI_METHOD_PING, monitor_common_pong },
     { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
-    { MON_CLI_METHOD_ROTATE, monitor_common_rotate_logs },
+    { MON_CLI_METHOD_ROTATE, responder_logrotate },
     { NULL, NULL }
 };
 
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
index 42ff3f8..b9b1efb 100644
--- a/src/responder/pac/pacsrv_cmd.c
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -24,6 +24,161 @@
 #include "confdb/confdb.h"
 #include "db/sysdb.h"
 
+#include <util/data_blob.h>
+#include <ndr.h>
+
+#include "gen_ndr/krb5pac.h"
+#include "gen_ndr/ndr_krb5pac.h"
+
+#define PAC_USER_OFFSET 200000
+#define PAC_HOME_PATH "/home/"
+#define PAC_DEFAULT_SHELL "/bin/bash"
+
+static errno_t pac_cmd_done(struct cli_ctx *cctx, int cmd_ret)
+{
+    int ret;
+
+    ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
+                         &cctx->creq->out);
+    if (ret != EOK) {
+        DEBUG(1, ("sss_packet_new failed [%d][%s].\n", ret, strerror(ret)));
+        return ret;
+    }
+
+    sss_packet_set_error(cctx->creq->out, cmd_ret);
+
+    sss_cmd_done(cctx, NULL);
+
+    return EOK;
+}
+
+static errno_t pac_add_pac_user(struct cli_ctx *cctx)
+{
+    struct ndr_pull *ndr_pull;
+    DATA_BLOB blob;
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct PAC_DATA *pac_data;
+    enum ndr_err_code ndr_err;
+    int ret;
+    struct sysdb_ctx *sysdb;
+    struct sss_domain_info *dom = NULL;
+    size_t c;
+    struct passwd pwd;
+    uint8_t *body;
+    size_t blen;
+
+    sss_packet_get_body(cctx->creq->in, &body, &blen);
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(1, ("talloc_new failed.\n"));
+        return ENOMEM;
+    }
+
+    blob.data = body;
+    blob.length = blen;
+
+    ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx);
+    if (ndr_pull == NULL) {
+        DEBUG(1, ("ndr_pull_init_blob failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; /* FIXME: is this really needed ? */
+
+    pac_data = talloc_zero(tmp_ctx, struct PAC_DATA);
+    if (pac_data == NULL) {
+        DEBUG(1, ("talloc_zero failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ndr_err = ndr_pull_PAC_DATA(ndr_pull, NDR_SCALARS|NDR_BUFFERS, pac_data);
+    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+        DEBUG(1, ("ndr_pull_PAC_DATA failed [%d]\n", ndr_err));
+        ret = EBADMSG;
+        goto done;
+    }
+
+    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
+        if (strcasecmp(dom->provider, "local") == 0) break;
+    }
+    if (!dom) {
+        DEBUG(1, ("No local domain found.\n"));
+        ret = ENOENT;
+        goto done;
+    }
+
+
+    ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, dom, &sysdb);
+    if (ret != EOK) {
+        DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
+        goto done;
+    }
+
+    for(c = 0; c < pac_data->num_buffers; c++) {
+        if (pac_data->buffers[c].type == PAC_TYPE_LOGON_INFO) {
+            break;
+        }
+    }
+
+    memset(&pwd, 0, sizeof(pwd));
+
+    if (pac_data->buffers[c].info->logon_info.info->info3.base.account_name.size != 0) {
+        pwd.pw_name = discard_const(pac_data->buffers[c].info->logon_info.info->info3.base.account_name.string);
+    } else {
+        DEBUG(1, ("Missing account name in PAC.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (pac_data->buffers[c].info->logon_info.info->info3.base.rid > 0) {
+        pwd.pw_uid = PAC_USER_OFFSET + pac_data->buffers[c].info->logon_info.info->info3.base.rid;
+    } else {
+        DEBUG(1, ("Missing user RID in PAC.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (pac_data->buffers[c].info->logon_info.info->info3.base.primary_gid > 0) {
+        pwd.pw_gid = PAC_USER_OFFSET + pac_data->buffers[c].info->logon_info.info->info3.base.primary_gid;
+    } else {
+        DEBUG(1, ("Missing primary GID in PAC.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+    pwd.pw_gid = 0; /* FIXME: for local domain tests */
+
+    if (pac_data->buffers[c].info->logon_info.info->info3.base.full_name.size != 0) {
+        pwd.pw_gecos = discard_const(pac_data->buffers[c].info->logon_info.info->info3.base.full_name.string);
+    } else {
+        DEBUG(1, ("Missing full name in PAC using account name for gecos.\n"));
+        pwd.pw_gecos = discard_const(pac_data->buffers[c].info->logon_info.info->info3.base.account_name.string);
+    }
+
+    pwd.pw_dir = talloc_asprintf(tmp_ctx, PAC_HOME_PATH"%s", pac_data->buffers[c].info->logon_info.info->info3.base.account_name.string);
+    if (pwd.pw_dir == NULL) {
+        DEBUG(1, ("talloc_asprintf failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    pwd.pw_shell = discard_const(PAC_DEFAULT_SHELL);
+
+    ret = sysdb_store_user(tmp_ctx, sysdb, dom, pwd.pw_name, NULL,
+                           pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
+                           pwd.pw_shell, NULL, NULL, 0);
+    if (ret != EOK) {
+        DEBUG(1, ("sysdb_store_user failed [%d][%s].\n", ret, strerror(ret)));
+        goto done;
+    }
+
+done:
+    talloc_free(tmp_ctx);
+
+    return pac_cmd_done(cctx, ret);
+}
+
 struct cli_protocol_version *register_cli_protocol_version(void)
 {
     static struct cli_protocol_version pac_cli_protocol_version[] = {
@@ -36,6 +191,7 @@ struct cli_protocol_version *register_cli_protocol_version(void)
 
 static struct sss_cmd_table pac_cmds[] = {
     {SSS_GET_VERSION, sss_cmd_get_version},
+    {SSS_PAC_ADD_PAC_USER, pac_add_pac_user},
     {SSS_CLI_NULL, NULL}
 };
 
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 7c0ec11..c5751fd 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
 
+/* PAC responder calls */
+    SSS_PAC_ADD_PAC_USER     = 0x00E1,
+
 /* PAM related calls */
     SSS_PAM_AUTHENTICATE     = 0x00F1, /**< see pam_sm_authenticate(3) for
                                         * details.
-- 
1.7.5.1

-------------- next part --------------
From 48f2cbe4361d34bd7d56fb78daa7b6dcdd38da83 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 24 May 2011 11:12:28 +0200
Subject: [PATCH 5/7] Add krb5 authdata plugin to send the pac

---
 Makefile.am                        |   21 +++
 configure.ac                       |    1 +
 src/conf_macros.m4                 |   14 ++
 src/sss_client/krb5_authdata_int.h |  185 ++++++++++++++++++++++++
 src/sss_client/sssd_pac.c          |  278 ++++++++++++++++++++++++++++++++++++
 5 files changed, 499 insertions(+), 0 deletions(-)
 create mode 100644 src/sss_client/krb5_authdata_int.h
 create mode 100644 src/sss_client/sssd_pac.c

diff --git a/Makefile.am b/Makefile.am
index 1716be6..20b3213 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,9 @@ ldblibdir = @ldblibdir@
 if BUILD_KRB5_LOCATOR_PLUGIN
 krb5plugindir = @krb5pluginpath@
 endif
+if BUILD_PAC_RESPONDER
+krb5authdata_plugindir = @krb5authdatapluginpath@
+endif
 sssdconfdir = $(sysconfdir)/sssd
 sssdapiplugindir = $(sssdconfdir)/sssd.api.d
 dbusintrospectdir = $(datarootdir)/sssd/introspect
@@ -116,6 +119,11 @@ krb5plugin_LTLIBRARIES = \
     sssd_krb5_locator_plugin.la
 endif
 
+if BUILD_PAC_RESPONDER
+krb5authdata_plugin_LTLIBRARIES = \
+    sssd_pac_plugin.la
+endif
+
 noinst_LTLIBRARIES = \
     libsss_crypt.la
 
@@ -986,6 +994,19 @@ sssd_krb5_locator_plugin_la_LDFLAGS = \
     -module
 endif
 
+sssd_pac_plugin_la_SOURCES = \
+    src/sss_client/sssd_pac.c \
+    src/sss_client/common.c \
+    src/sss_client/sss_cli.h \
+    src/sss_client/krb5_authdata_int.h
+sssd_pac_plugin_la_CFLAGS = \
+    $(AM_CFLAGS) \
+    $(KRB5_CFLAGS)
+sssd_pac_plugin_la_LDFLAGS = \
+    -lkrb5 \
+    -avoid-version \
+    -module
+
 if BUILD_PYTHON_BINDINGS
 pysss_la_SOURCES = \
     $(SSSD_TOOLS_OBJ) \
diff --git a/configure.ac b/configure.ac
index 71dc14e..212e9f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,7 @@ WITH_TEST_DIR
 WITH_MANPAGES
 WITH_XML_CATALOG
 WITH_KRB5_PLUGIN_PATH
+WITH_KRB5AUTHDATA_PLUGIN_PATH
 WITH_PYTHON_BINDINGS
 WITH_SELINUX
 WITH_NSCD
diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
index af9cb4f..626772b 100644
--- a/src/conf_macros.m4
+++ b/src/conf_macros.m4
@@ -204,6 +204,20 @@ AC_DEFUN([WITH_KRB5_PLUGIN_PATH],
     AC_SUBST(krb5pluginpath)
   ])
 
+AC_DEFUN([WITH_KRB5AUTHDATA_PLUGIN_PATH],
+  [ AC_ARG_WITH([krb5authdata-plugin-path],
+                [AC_HELP_STRING([--with-krb5authdata-plugin-path=PATH],
+                                [Path to kerberos authdata plugin store [/usr/lib/krb5/plugins/authdata]]
+                               )
+                ]
+               )
+    krb5authdatapluginpath="${libdir}/krb5/plugins/authdata"
+    if test x"$with_krb5authdata_plugin_path" != x; then
+        krb5authdatapluginpath=$with_krb5authdata_plugin_path
+    fi
+    AC_SUBST(krb5authdatapluginpath)
+  ])
+
 AC_DEFUN([WITH_PYTHON_BINDINGS],
   [ AC_ARG_WITH([python-bindings],
                 [AC_HELP_STRING([--with-python-bindings],
diff --git a/src/sss_client/krb5_authdata_int.h b/src/sss_client/krb5_authdata_int.h
new file mode 100644
index 0000000..5e0cf5e
--- /dev/null
+++ b/src/sss_client/krb5_authdata_int.h
@@ -0,0 +1,185 @@
+/*
+    SSSD - MIT Kerberos authdata plugin
+
+    This file contains definitions and declarations to build authdata plugins
+    for MIT Kerberos outside of the MIT Kerberos source tree.
+*/
+
+#ifndef _KRB5_AUTHDATA_INT_H
+#define _KRB5_AUTHDATA_INT_H
+
+krb5_error_code KRB5_CALLCONV
+krb5_ser_pack_int32(krb5_int32, krb5_octet **, size_t *);
+
+krb5_error_code KRB5_CALLCONV
+krb5_ser_unpack_int32(krb5_int32 *, krb5_octet **, size_t *);
+
+krb5_error_code KRB5_CALLCONV
+krb5_ser_pack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);
+
+#define AD_USAGE_AS_REQ         0x01
+#define AD_USAGE_TGS_REQ        0x02
+#define AD_USAGE_AP_REQ         0x04
+#define AD_USAGE_KDC_ISSUED     0x08
+#define AD_USAGE_MASK           0x0F
+#define AD_INFORMATIONAL        0x10
+
+struct _krb5_authdata_context;
+typedef struct _krb5_authdata_context *krb5_authdata_context;
+
+typedef void
+(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
+                                     void *plugin_context,
+                                     krb5_authdatatype ad_type,
+                                     krb5_flags *flags);
+
+typedef krb5_error_code
+(*authdata_client_plugin_init_proc)(krb5_context context,
+                                    void **plugin_context);
+typedef void
+(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
+                                    void *plugin_context);
+
+typedef krb5_error_code
+(*authdata_client_request_init_proc)(krb5_context kcontext,
+                                     struct _krb5_authdata_context *context,
+                                     void *plugin_context,
+                                     void **request_context);
+
+typedef void
+(*authdata_client_request_fini_proc)(krb5_context kcontext,
+                                     struct _krb5_authdata_context *context,
+                                     void *plugin_context,
+                                     void *request_context);
+
+typedef krb5_error_code
+(*authdata_client_import_authdata_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_authdata **authdata,
+                                        krb5_boolean kdc_issued_flag,
+                                        krb5_const_principal issuer);
+
+typedef krb5_error_code
+(*authdata_client_export_authdata_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_flags usage,
+                                        krb5_authdata ***authdata);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
+                                            struct _krb5_authdata_context *context,
+                                            void *plugin_context,
+                                            void *request_context,
+                                            krb5_data **attrs);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      const krb5_data *attribute,
+                                      krb5_boolean *authenticated,
+                                      krb5_boolean *complete,
+                                      krb5_data *value,
+                                      krb5_data *display_value,
+                                      int *more);
+
+typedef krb5_error_code
+(*authdata_client_set_attribute_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      krb5_boolean complete,
+                                      const krb5_data *attribute,
+                                      const krb5_data *value);
+
+typedef krb5_error_code
+(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
+                                         struct _krb5_authdata_context *context,
+                                         void *plugin_context,
+                                         void *request_context,
+                                         const krb5_data *attribute);
+
+typedef krb5_error_code
+(*authdata_client_export_internal_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_boolean restrict_authenticated,
+                                        void **ptr);
+
+typedef void
+(*authdata_client_free_internal_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      void *ptr);
+
+typedef krb5_error_code
+(*authdata_client_verify_proc)(krb5_context kcontext,
+                               struct _krb5_authdata_context *context,
+                               void *plugin_context,
+                               void *request_context,
+                               const krb5_auth_context *auth_context,
+                               const krb5_keyblock *key,
+                               const krb5_ap_req *req);
+
+typedef krb5_error_code
+(*authdata_client_size_proc)(krb5_context kcontext,
+                             struct _krb5_authdata_context *context,
+                             void *plugin_context,
+                             void *request_context,
+                             size_t *sizep);
+
+typedef krb5_error_code
+(*authdata_client_externalize_proc)(krb5_context kcontext,
+                                    struct _krb5_authdata_context *context,
+                                    void *plugin_context,
+                                    void *request_context,
+                                    krb5_octet **buffer,
+                                    size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_internalize_proc)(krb5_context kcontext,
+                                    struct _krb5_authdata_context *context,
+                                    void *plugin_context,
+                                    void *request_context,
+                                    krb5_octet **buffer,
+                                    size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_copy_proc)(krb5_context kcontext,
+                             struct _krb5_authdata_context *context,
+                             void *plugin_context,
+                             void *request_context,
+                             void *dst_plugin_context,
+                             void *dst_request_context);
+
+typedef struct krb5plugin_authdata_client_ftable_v0 {
+    char *name;
+    krb5_authdatatype *ad_type_list;
+    authdata_client_plugin_init_proc init;
+    authdata_client_plugin_fini_proc fini;
+    authdata_client_plugin_flags_proc flags;
+    authdata_client_request_init_proc request_init;
+    authdata_client_request_fini_proc request_fini;
+    authdata_client_get_attribute_types_proc get_attribute_types;
+    authdata_client_get_attribute_proc get_attribute;
+    authdata_client_set_attribute_proc set_attribute;
+    authdata_client_delete_attribute_proc delete_attribute;
+    authdata_client_export_authdata_proc export_authdata;
+    authdata_client_import_authdata_proc import_authdata;
+    authdata_client_export_internal_proc export_internal;
+    authdata_client_free_internal_proc free_internal;
+    authdata_client_verify_proc verify;
+    authdata_client_size_proc size;
+    authdata_client_externalize_proc externalize;
+    authdata_client_internalize_proc internalize;
+    authdata_client_copy_proc copy; /* optional */
+} krb5plugin_authdata_client_ftable_v0;
+
+#endif /* _KRB5_AUTHDATA_INT_H */
diff --git a/src/sss_client/sssd_pac.c b/src/sss_client/sssd_pac.c
new file mode 100644
index 0000000..6fcf87c
--- /dev/null
+++ b/src/sss_client/sssd_pac.c
@@ -0,0 +1,278 @@
+/*
+    Authors:
+        Sumit Bose <sbose 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 Lesser 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 Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* A short documentation about authdata plugins can be found in
+ * http://http://k5wiki.kerberos.org/wiki/Projects/VerifyAuthData */
+
+#include <krb5/krb5.h>
+#include <errno.h>
+
+#include "krb5_authdata_int.h"
+#include "sss_cli.h"
+
+
+struct sssd_context {
+    krb5_data data;
+};
+
+static krb5_error_code
+sssdpac_init(krb5_context kcontext, void **plugin_context)
+{
+    *plugin_context = NULL;
+    return 0;
+}
+
+static void
+sssdpac_flags(krb5_context kcontext,
+            void *plugin_context,
+            krb5_authdatatype ad_type,
+            krb5_flags *flags)
+{
+    *flags = AD_USAGE_TGS_REQ;
+}
+
+static void
+sssdpac_fini(krb5_context kcontext, void *plugin_context)
+{
+    return;
+}
+
+static krb5_error_code
+sssdpac_request_init(krb5_context kcontext,
+                   krb5_authdata_context context,
+                   void *plugin_context,
+                   void **request_context)
+{
+    struct sssd_context *sssdctx;
+
+    sssdctx = (struct sssd_context *)calloc(1, sizeof(*sssdctx));
+    if (sssdctx == NULL)
+        return ENOMEM;
+
+    *request_context = sssdctx;
+
+    return 0;
+}
+
+static krb5_error_code
+sssdpac_import_authdata(krb5_context kcontext,
+                      krb5_authdata_context context,
+                      void *plugin_context,
+                      void *request_context,
+                      krb5_authdata **authdata,
+                      krb5_boolean kdc_issued,
+                      krb5_const_principal kdc_issuer)
+{
+    struct sss_cli_req_data sss_data;
+    int ret;
+    uint8_t *repbuf;
+    size_t replen;
+    int errnop;
+    char *data = NULL;
+    struct sssd_context *sssdctx = (struct sssd_context *)request_context;
+
+    if (authdata[0] == NULL) {
+        return EINVAL;
+    }
+
+    sss_data.len = authdata[0]->length;
+    sss_data.data = authdata[0]->contents;
+
+    ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
+                               &repbuf, &replen, &errnop);
+    if (ret != 0) {
+        /* Ignore the error */
+    }
+
+    if (authdata[0]->length > 0) {
+        data = malloc(sizeof(char) * authdata[0]->length);
+        if (data == NULL) {
+            return ENOMEM;
+        }
+        memcpy(data, authdata[0]->contents, authdata[0]->length);
+    }
+
+    if (sssdctx->data.data != NULL) {
+        krb5_free_data_contents(kcontext, &sssdctx->data);
+    }
+
+    sssdctx->data.length = authdata[0]->length;
+    sssdctx->data.data = data;
+    return 0;
+}
+
+static void
+sssdpac_request_fini(krb5_context kcontext,
+                   krb5_authdata_context context,
+                   void *plugin_context,
+                   void *request_context)
+{
+    struct sssd_context *sssdctx = (struct sssd_context *)request_context;
+
+    if (sssdctx != NULL) {
+        if (sssdctx->data.data != NULL)
+            krb5_free_data_contents(kcontext, &sssdctx->data);
+
+        free(sssdctx);
+    }
+}
+
+#define STRLENOF(x) (sizeof((x)) - 1)
+
+static krb5_error_code
+sssdpac_size(krb5_context kcontext,
+           krb5_authdata_context context,
+           void *plugin_context,
+           void *request_context,
+           size_t *sizep)
+{
+    struct sssd_context *sssdctx = (struct sssd_context *)request_context;
+
+    *sizep += sizeof(krb5_int32);
+
+    *sizep += sssdctx->data.length;
+
+    *sizep += sizeof(krb5_int32);
+
+    return 0;
+}
+
+static krb5_error_code
+sssdpac_externalize(krb5_context kcontext,
+                  krb5_authdata_context context,
+                  void *plugin_context,
+                  void *request_context,
+                  krb5_octet **buffer,
+                  size_t *lenremain)
+{
+    krb5_error_code code = 0;
+    struct sssd_context *sssdctx = (struct sssd_context *)request_context;
+    size_t required = 0;
+    krb5_octet *bp;
+    size_t remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+
+    if (sssdctx->data.data != NULL) {
+        sssdpac_size(kcontext, context, plugin_context,
+                   request_context, &required);
+
+        if (required <= remain) {
+            krb5_ser_pack_int32((krb5_int32)sssdctx->data.length,
+                                &bp, &remain);
+            krb5_ser_pack_bytes((krb5_octet *)sssdctx->data.data,
+                                (size_t)sssdctx->data.length,
+                                &bp, &remain);
+            krb5_ser_pack_int32(0,
+                                &bp, &remain);
+        } else {
+            code = ENOMEM;
+        }
+    } else {
+        krb5_ser_pack_int32(0, &bp, &remain); /* length */
+        krb5_ser_pack_int32(0, &bp, &remain); /* verified */
+    }
+
+    *buffer = bp;
+    *lenremain = remain;
+
+    return code;
+}
+
+static krb5_error_code
+sssdpac_internalize(krb5_context kcontext,
+                  krb5_authdata_context context,
+                  void *plugin_context,
+                  void *request_context,
+                  krb5_octet **buffer,
+                  size_t *lenremain)
+{
+    struct sssd_context *sssdctx = (struct sssd_context *)request_context;
+    krb5_error_code code;
+    krb5_int32 ibuf;
+    krb5_octet *bp;
+    size_t remain;
+    krb5_data data;
+
+    bp = *buffer;
+    remain = *lenremain;
+
+    /* length */
+    code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+    if (code != 0)
+        return code;
+
+    if (ibuf != 0) {
+
+        data.length = ibuf;
+        data.data = malloc(sizeof(char) * ibuf);
+        if (data.data == NULL) {
+            return ENOMEM;
+        }
+        memcpy(data.data, bp, ibuf);
+
+        bp += ibuf;
+        remain -= ibuf;
+    }
+
+    /* verified */
+    code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+    if (code != 0) {
+        return code;
+    }
+
+    if (sssdctx->data.data != NULL) {
+        krb5_free_data_contents(kcontext, &sssdctx->data);
+    }
+
+    sssdctx->data.length = data.length;
+    sssdctx->data.data = data.data;
+
+    *buffer = bp;
+    *lenremain = remain;
+
+    return 0;
+}
+
+static krb5_authdatatype sssdpac_ad_types[] = { KRB5_AUTHDATA_WIN2K_PAC, 0 };
+
+krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
+    ((void *)((uintptr_t)("sssd_sssdpac"))),
+    sssdpac_ad_types,
+    sssdpac_init,
+    sssdpac_fini,
+    sssdpac_flags,
+    sssdpac_request_init,
+    sssdpac_request_fini,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    sssdpac_import_authdata,
+    NULL,
+    NULL,
+    NULL,
+    sssdpac_size,
+    sssdpac_externalize,
+    sssdpac_internalize,
+    NULL
+};
-- 
1.7.5.1

-------------- next part --------------
From 92fb986d5ef094676cfde423bfa4562141955b03 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 24 May 2011 11:57:09 +0200
Subject: [PATCH 6/7] Build pac responder in example spec file

---
 contrib/sssd.spec.in |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 2bd6774..af50504 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -132,6 +132,7 @@ done
 autoreconf -ivf
 
 %configure \
+    --enable-experimental-pac-responder \
     --with-db-path=%{dbpath} \
     --with-pipe-path=%{pipepath} \
     --with-pubconf-path=%{pubconfpath} \
@@ -181,6 +182,7 @@ rm -f \
     $RPM_BUILD_ROOT/%{_libdir}/sssd/libsss_ipa.la \
     $RPM_BUILD_ROOT/%{_libdir}/sssd/libsss_simple.la \
     $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.la \
+    $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.la \
     $RPM_BUILD_ROOT/%{python_sitearch}/pysss.la
 
 # Older versions of rpmbuild can only handle one -f option
@@ -243,6 +245,7 @@ rm -rf $RPM_BUILD_ROOT
 /%{_lib}/libnss_sss.so.2
 /%{_lib}/security/pam_sss.so
 %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
+%{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
 %{_mandir}/man8/pam_sss.8*
 %{_mandir}/man8/sssd_krb5_locator_plugin.8*
 
-- 
1.7.5.1

-------------- next part --------------
From e7ee24655cf217d39e56ba938f078de29f06247d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 2 May 2011 10:47:25 +0200
Subject: [PATCH 7/7] Implement SSS_PAC_PUTPWENT in pac responder

---
 src/responder/pac/pacsrv_cmd.c |  188 ++++++++++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h       |    2 +
 2 files changed, 190 insertions(+), 0 deletions(-)

diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
index b9b1efb..13dc9ae 100644
--- a/src/responder/pac/pacsrv_cmd.c
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -179,6 +179,192 @@ done:
     return pac_cmd_done(cctx, ret);
 }
 
+static errno_t pac_putpwent(struct cli_ctx *cctx, uint8_t *body, size_t blen)
+{
+    struct passwd pwd;
+    size_t c = 0;
+    uint32_t id;
+    TALLOC_CTX *tmp_ctx;
+    struct sysdb_ctx *sysdb;
+    struct sss_domain_info *dom = NULL;
+    int ret;
+
+    if (blen < 13) {
+        DEBUG(1, ("putpwent message too short.\n"));
+        return EBADMSG;
+    }
+
+    if (body[blen -1] != '\0') {
+        DEBUG(1, ("putpwent message is not terminated by \\0.\n"));
+        return EBADMSG;
+    }
+
+    memset(&pwd, 0, sizeof(pwd));
+
+    SAFEALIGN_COPY_UINT32(&id, body, NULL);
+    pwd.pw_uid = id;
+    c += sizeof(uint32_t);
+    DEBUG(9, ("Got uid [%d].\n", pwd.pw_uid));
+
+    SAFEALIGN_COPY_UINT32(&id, body+c, NULL);
+    pwd.pw_gid = id;
+    c += sizeof(uint32_t);
+    DEBUG(9, ("Got gid [%d].\n", pwd.pw_gid));
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(1, ("talloc_new failed.\n"));
+        return ENOMEM;
+    }
+
+    pwd.pw_name = talloc_strdup(tmp_ctx, (const char *) body+c);
+    if (pwd.pw_name == NULL && body+c != '\0') {
+        DEBUG(1, ("talloc_strdup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    c += strlen(pwd.pw_name) + 1;
+    if (c >= blen) {
+        DEBUG(1, ("putpwent message is too short.\n"));
+        ret = EBADMSG;
+        goto done;
+    }
+    DEBUG(9, ("Got name [%s].\n", pwd.pw_name));
+
+    pwd.pw_passwd = talloc_strdup(tmp_ctx, (const char *) body+c);
+    if (pwd.pw_passwd == NULL && body+c != '\0') {
+        DEBUG(1, ("talloc_strdup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    c += strlen(pwd.pw_passwd) + 1;
+    if (c >= blen) {
+        DEBUG(1, ("putpwent message is too short.\n"));
+        ret = EBADMSG;
+        goto done;
+    }
+    DEBUG(9, ("Got passwd [%s].\n", pwd.pw_passwd));
+
+    pwd.pw_gecos = talloc_strdup(tmp_ctx, (const char *) body+c);
+    if (pwd.pw_gecos == NULL && body+c != '\0') {
+        DEBUG(1, ("talloc_strdup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    c += strlen(pwd.pw_gecos) + 1;
+    if (c >= blen) {
+        DEBUG(1, ("putpwent message is too short.\n"));
+        ret = EBADMSG;
+        goto done;
+    }
+    DEBUG(9, ("Got gecos [%s].\n", pwd.pw_gecos));
+
+    pwd.pw_dir = talloc_strdup(tmp_ctx, (const char *) body+c);
+    if (pwd.pw_dir == NULL && body+c != '\0') {
+        DEBUG(1, ("talloc_strdup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    c += strlen(pwd.pw_dir) + 1;
+    if (c >= blen) {
+        DEBUG(1, ("putpwent message is too short.\n"));
+        ret = EBADMSG;
+        goto done;
+    }
+    DEBUG(9, ("Got dir [%s].\n", pwd.pw_dir));
+
+    pwd.pw_shell = talloc_strdup(tmp_ctx, (const char *) body+c);
+    if (pwd.pw_shell == NULL && body+c != '\0') {
+        DEBUG(1, ("talloc_strdup failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    c += strlen(pwd.pw_shell) + 1;
+    if (c != blen) {
+        DEBUG(1, ("putpwent message has the wrong size.\n"));
+        ret = EBADMSG;
+        goto done;
+    }
+    DEBUG(9, ("Got shell [%s].\n", pwd.pw_shell));
+
+    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
+        if (strcasecmp(dom->provider, "local") == 0) break;
+    }
+    if (!dom) {
+        DEBUG(1, ("No local domain found.\n"));
+        ret = ENOENT;
+        goto done;
+    }
+
+
+    ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, dom, &sysdb);
+    if (ret != EOK) {
+        DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
+        goto done;
+    }
+
+    ret = sysdb_store_user(tmp_ctx, sysdb, dom, pwd.pw_name, pwd.pw_passwd,
+                           pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
+                           pwd.pw_shell, NULL, NULL, 0);
+    if (ret != EOK) {
+        DEBUG(1, ("sysdb_store_user failed [%d][%s].\n", ret, strerror(ret)));
+        goto done;
+    }
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static errno_t pac_putgrent(struct cli_ctx *cctx, uint8_t *body, size_t blen)
+{
+    return EOPNOTSUPP;
+}
+
+static errno_t pac_cmd_handler(struct cli_ctx *cctx,
+                               enum sss_cli_command pac_cmd)
+{
+    int ret;
+    uint8_t *body;
+    size_t blen;
+
+    sss_packet_get_body(cctx->creq->in, &body, &blen);
+
+    switch(pac_cmd) {
+        case SSS_PAC_PUTPWENT:
+            ret = pac_putpwent(cctx, body, blen);
+            if (ret != EOK) {
+                DEBUG(1, ("pac_putpwent failed [%d][%s].\n",
+                          ret, strerror(ret)));
+            }
+            break;
+        case SSS_PAC_PUTGRENT:
+            ret = pac_putgrent(cctx, body, blen);
+            if (ret != EOK) {
+                DEBUG(1, ("pac_putgrent failed [%d][%s].\n",
+                          ret, strerror(ret)));
+            }
+            break;
+        default:
+            DEBUG(1, ("Unsupported PAC command [%d].\n", pac_cmd));
+            ret = EINVAL;
+    }
+
+    return pac_cmd_done(cctx, ret);
+}
+
+static int pac_cmd_putpwent(struct cli_ctx *cctx)
+{
+    DEBUG(4, ("entering pac_cmd_putpwent.\n"));
+    return pac_cmd_handler(cctx, SSS_PAC_PUTPWENT);
+}
+
+static int pac_cmd_putgrent(struct cli_ctx *cctx)
+{
+    DEBUG(4, ("entering pac_cmd_putgrent.\n"));
+    return pac_cmd_handler(cctx, SSS_PAC_PUTGRENT);
+}
+
 struct cli_protocol_version *register_cli_protocol_version(void)
 {
     static struct cli_protocol_version pac_cli_protocol_version[] = {
@@ -192,6 +378,8 @@ struct cli_protocol_version *register_cli_protocol_version(void)
 static struct sss_cmd_table pac_cmds[] = {
     {SSS_GET_VERSION, sss_cmd_get_version},
     {SSS_PAC_ADD_PAC_USER, pac_add_pac_user},
+    {SSS_PAC_PUTPWENT, pac_cmd_putpwent},
+    {SSS_PAC_PUTGRENT, pac_cmd_putgrent},
     {SSS_CLI_NULL, NULL}
 };
 
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index c5751fd..09800d5 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -146,6 +146,8 @@ enum sss_cli_command {
 
 /* PAC responder calls */
     SSS_PAC_ADD_PAC_USER     = 0x00E1,
+    SSS_PAC_PUTPWENT         = 0x00E2, /* only for testing */
+    SSS_PAC_PUTGRENT         = 0x00E3, /* only for testing */
 
 /* PAM related calls */
     SSS_PAM_AUTHENTICATE     = 0x00F1, /**< see pam_sm_authenticate(3) for
-- 
1.7.5.1



More information about the sssd-devel mailing list