summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2009-02-24 19:28:40 -0500
committerSimo Sorce <ssorce@redhat.com>2009-02-24 21:00:56 -0500
commit98531e56318b65eb1bb6883fdfe12e771d8a1efe (patch)
treea339a5948604ff62cfafd62a9682130f30df689e /server
parent4c6c0f77a505b6b0790cfa8eedd3133abebd4edb (diff)
downloadsssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.tar.gz
sssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.tar.bz2
sssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.zip
Add PAM responder
Also move responders under server/responder with shared code in server/responder/common Signed-off-by: Simo Sorce <ssorce@redhat.com>
Diffstat (limited to 'server')
-rw-r--r--server/Makefile.in24
-rw-r--r--server/configure.ac2
-rw-r--r--server/external/ldap.m451
-rw-r--r--server/external/pam.m45
-rw-r--r--server/providers/data_provider.c274
-rw-r--r--server/providers/data_provider.h6
-rw-r--r--server/providers/data_provider_be.c138
-rw-r--r--server/providers/dp_backend.h8
-rw-r--r--server/providers/ldap_be.c676
-rw-r--r--server/providers/proxy.c132
-rw-r--r--server/responder/common/responder_cmd.c78
-rw-r--r--server/responder/common/responder_cmd.h71
-rw-r--r--server/responder/common/responder_common.c518
-rw-r--r--server/responder/common/responder_common.h24
-rw-r--r--server/responder/common/responder_dp.c123
-rw-r--r--server/responder/common/responder_dp.h4
-rw-r--r--server/responder/common/responder_packet.c (renamed from server/nss/nsssrv_packet.c)46
-rw-r--r--server/responder/common/responder_packet.h39
-rw-r--r--server/responder/nss/nsssrv.c (renamed from server/nss/nsssrv.c)9
-rw-r--r--server/responder/nss/nsssrv.h (renamed from server/nss/nsssrv.h)26
-rw-r--r--server/responder/nss/nsssrv_cmd.c (renamed from server/nss/nsssrv_cmd.c)235
-rw-r--r--server/responder/nss/nsssrv_dp.c (renamed from server/nss/nsssrv_dp.c)3
-rw-r--r--server/responder/pam/pamsrv.c171
-rw-r--r--server/responder/pam/pamsrv.h33
-rw-r--r--server/responder/pam/pamsrv_cmd.c196
-rw-r--r--server/responder/pam/pamsrv_dp.c215
-rw-r--r--server/responder/pam/pamsrv_util.c16
-rw-r--r--server/server.mk44
28 files changed, 2991 insertions, 176 deletions
diff --git a/server/Makefile.in b/server/Makefile.in
index 1cde271e..158202ca 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -43,6 +43,16 @@ DBUS_CFLAGS = @DBUS_CFLAGS@
CHECK_LIBS = @CHECK_LIBS@
CHECK_CFLAGS = @CHECK_CFLAGS@
+PAM_LIBS = @PAM_LIBS@
+
+OPENLDAP_LIBS = @OPENLDAP_LIBS@
+
+MOZLDAP_CFLAGS = @MOZLDAP_CFLAGS@
+MOZLDAP_LIBS = @MOZLDAP_LIBS@
+
+LDAP_CFLAGS = $(MOZLDAP_CFLAGS) $(OPENLDAP_CFLAGS)
+LDAP_LIBS = $(MOZLDAP_LIBS) $(OPENLDAP_LIBS)
+
LIBDL = @LIBDL@
SHLIBEXT = @SHLIBEXT@
@@ -75,6 +85,10 @@ PROXY_BE_SOBASE=libsss_proxy.$(SHLIBEXT)
PROXY_BE_SONAME=$(PROXY_BE_SOBASE).0
PROXY_BE_SOLIB=$(PROXY_BE_SOBASE).$(PACKAGE_VERSION)
+LDAP_BE_SOBASE=libsss_ldap.$(SHLIBEXT)
+LDAP_BE_SONAME=$(LDAP_BE_SOBASE).0
+LDAP_BE_SOLIB=$(LDAP_BE_SOBASE).$(PACKAGE_VERSION)
+
default: all
include $(srvdir)/rules.mk
@@ -86,7 +100,7 @@ headers =
DBUS_SYSBUS_POLICY_DIR = @sysconfdir@/dbus-1/system.d
-LIBEXECBINS = sbin/sssd_nss sbin/sssd_dp sbin/sssd_be
+LIBEXECBINS = sbin/sssd_nss sbin/sssd_dp sbin/sssd_be sbin/sssd_pam
ifneq (x$(HAVE_INFOPIPE), x)
LIBEXECBINS += sbin/sssd_info
DBUS_SYSBUS_POLICIES = infopipe/org.freeipa.sssd.infopipe.conf
@@ -100,9 +114,9 @@ BINS = sbin/sssd $(LIBEXECBINS)
TESTS = tests/sysdb-tests tests/infopipe-tests
TESTS_DATA = tests/tests.ldb tests/tests_conf.ldb tests/introspect.ref
-SOLIBS = lib/$(MEMBEROF_SOLIB) lib/$(PROXY_BE_SOLIB)
-SONAMELIBS = lib/$(PROXY_BE_SONAME) lib/$(MEMBEROF_SONAME)
-SOBASELIBS = lib/$(PROXY_BE_SOBASE) lib/$(MEMBEROF_SOBASE)
+SOLIBS = lib/$(MEMBEROF_SOLIB) lib/$(PROXY_BE_SOLIB) lib/$(LDAP_BE_SOLIB)
+SONAMELIBS = lib/$(PROXY_BE_SONAME) lib/$(MEMBEROF_SONAME) lib/$(LDAP_BE_SONAME)
+SOBASELIBS = lib/$(PROXY_BE_SOBASE) lib/$(MEMBEROF_SOBASE) lib/$(LDAP_BE_SOBASE)
DIRS = sbin lib
@@ -158,6 +172,8 @@ endif
${INSTALLCMD} -m 755 $(SOLIBS) $(DESTDIR)$(SSSD_LIBDIR)
ln -fs $(PROXY_BE_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(PROXY_BE_SONAME)
ln -fs $(PROXY_BE_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(PROXY_BE_SOBASE)
+ ln -fs $(LDAP_BE_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(LDAP_BE_SONAME)
+ ln -fs $(LDAP_BE_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(LDAP_BE_SOBASE)
ln -fs $(MEMBEROF_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(MEMBEROF_SONAME)
ln -fs $(MEMBEROF_SOLIB) $(DESTDIR)$(SSSD_LIBDIR)/$(MEMBEROF_SOBASE)
diff --git a/server/configure.ac b/server/configure.ac
index b2f73b2e..a06dfdab 100644
--- a/server/configure.ac
+++ b/server/configure.ac
@@ -50,6 +50,8 @@ m4_include(libtalloc.m4)
m4_include(libtdb.m4)
m4_include(libevents.m4)
m4_include(libldb.m4)
+m4_include(pam.m4)
+m4_include(ldap.m4)
m4_include(util/signal.m4)
PKG_CHECK_MODULES([DBUS],[dbus-1])
diff --git a/server/external/ldap.m4 b/server/external/ldap.m4
new file mode 100644
index 00000000..535c2890
--- /dev/null
+++ b/server/external/ldap.m4
@@ -0,0 +1,51 @@
+dnl AC_SUBST(LDAP_LIBS)
+dnl
+dnl AC_CHECK_HEADERS(lber.h ldap.h, , AC_MSG_ERROR("could not locate ldap header files please install devel package"))
+dnl
+dnl AC_CHECK_LIB(lber, main, LDAP_LIBS="-llber $LDAP_LIBS")
+dnl AC_CHECK_LIB(ldap, main, LDAP_LIBS="-lldap $LDAP_LIBS")
+dnl
+dnl ---------------------------------------------------------------------------
+dnl - Check for Mozilla LDAP or OpenLDAP SDK
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(openldap, [ --with-openldap Use OpenLDAP])
+
+if test x$with_openldap = xyes; then
+ AC_CHECK_LIB(ldap, ldap_search, with_ldap=yes)
+ dnl Check for other libraries we need to link with to get the main routines.
+ test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes], , -llber) }
+ test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes with_ldap_krb=yes], , -llber -lkrb) }
+ test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes with_ldap_krb=yes with_ldap_des=yes], , -llber -lkrb -ldes) }
+ dnl Recently, we need -lber even though the main routines are elsewhere,
+ dnl because otherwise be get link errors w.r.t. ber_pvt_opt_on. So just
+ dnl check for that (it's a variable not a fun but that doesn't seem to
+ dnl matter in these checks) and stick in -lber if so. Can't hurt (even to
+ dnl stick it in always shouldn't hurt, I don't think) ... #### Someone who
+ dnl #### understands LDAP needs to fix this properly.
+ test "$with_ldap_lber" != "yes" && { AC_CHECK_LIB(lber, ber_pvt_opt_on, with_ldap_lber=yes) }
+
+ if test "$with_ldap" = "yes"; then
+ if test "$with_ldap_des" = "yes" ; then
+ OPENLDAP_LIBS="${OPENLDAP_LIBS} -ldes"
+ fi
+ if test "$with_ldap_krb" = "yes" ; then
+ OPENLDAP_LIBS="${OPENLDAP_LIBS} -lkrb"
+ fi
+ if test "$with_ldap_lber" = "yes" ; then
+ OPENLDAP_LIBS="${OPENLDAP_LIBS} -llber"
+ fi
+ OPENLDAP_LIBS="${OPENLDAP_LIBS} -lldap"
+ else
+ AC_MSG_ERROR([OpenLDAP not found])
+ fi
+
+ AC_SUBST(OPENLDAP_LIBS)
+else
+ PKG_CHECK_MODULES(MOZLDAP, mozldap > 6)
+ MOZLDAP_CFLAGS="${MOZLDAP_CFLAGS} -DWITH_MOZLDAP"
+ AC_SUBST(MOZLDAP_CFLAGS)
+ AC_SUBST(MOZLDAP_LIBS)
+fi
+
+
diff --git a/server/external/pam.m4 b/server/external/pam.m4
new file mode 100644
index 00000000..f99a2e69
--- /dev/null
+++ b/server/external/pam.m4
@@ -0,0 +1,5 @@
+AC_SUBST(PAM_LIBS)
+
+AC_CHECK_HEADERS(security/pam_appl.h security/pam_misc.h security/pam_modules.h)
+
+AC_CHECK_LIB(pam, pam_get_item, [ PAM_LIBS="-lpam" ])
diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c
index c6dc8d12..a0e3b08d 100644
--- a/server/providers/data_provider.c
+++ b/server/providers/data_provider.c
@@ -29,6 +29,8 @@
#include <string.h>
#include <sys/time.h>
#include <errno.h>
+#include <security/pam_modules.h>
+
#include "popt.h"
#include "util/util.h"
#include "confdb/confdb.h"
@@ -39,6 +41,7 @@
#include "dp_interfaces.h"
#include "monitor/monitor_sbus.h"
#include "monitor/monitor_interfaces.h"
+#include "responder/pam/pamsrv.h"
struct dp_backend;
struct dp_frontend;
@@ -88,9 +91,11 @@ struct sbus_method mon_sbus_methods[] = {
};
static int dp_get_account_info(DBusMessage *message, struct sbus_conn_ctx *sconn);
+static int dp_pamhandler(DBusMessage *message, struct sbus_conn_ctx *sconn);
struct sbus_method dp_sbus_methods[] = {
{ DP_SRV_METHOD_GETACCTINFO, dp_get_account_info },
+ { DP_SRV_METHOD_PAMHANDLER, dp_pamhandler },
{ NULL, NULL }
};
@@ -721,6 +726,275 @@ respond:
return EOK;
}
+static void be_got_pam_reply(DBusPendingCall *pending, void *data)
+{
+ struct dp_be_request *bereq;
+ DBusMessage *reply;
+ DBusConnection *conn;
+ DBusError dbus_error;
+ dbus_bool_t ret;
+ uint32_t pam_status;
+ char *domain;
+ int type;
+
+ bereq = talloc_get_type(data, struct dp_be_request);
+ dbus_error_init(&dbus_error);
+
+ reply = dbus_pending_call_steal_reply(pending);
+ if (!reply) {
+ /* reply should never be null. This function shouldn't be called
+ * until reply is valid or timeout has occurred. If reply is NULL
+ * here, something is seriously wrong and we should bail out.
+ */
+ DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n"));
+
+ /* Destroy this connection */
+ sbus_disconnect(bereq->be->dpcli->conn_ctx);
+ goto done;
+ }
+
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ ret = dbus_message_get_args(reply, &dbus_error,
+ DBUS_TYPE_UINT32, &pam_status,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to parse message, killing connection\n"));
+ if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+ sbus_disconnect(bereq->be->dpcli->conn_ctx);
+ pam_status = PAM_SYSTEM_ERR;
+ domain = "";
+ goto done;
+ }
+
+ DEBUG(4, ("Got reply (%d, %s) from %s(%s)\n", pam_status, domain,
+ bereq->be->name, bereq->be->domain));
+
+ break;
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+ DEBUG(0,("The Data Provider returned an error [%s], closing connection.\n",
+ dbus_message_get_error_name(reply)));
+ /* Falling through to default intentionally*/
+ default:
+ /*
+ * Timeout or other error occurred or something
+ * unexpected happened.
+ * It doesn't matter which, because either way we
+ * know that this connection isn't trustworthy.
+ * We'll destroy it now.
+ */
+ DEBUG(1,("Maybe timeout?\n"));
+ sbus_disconnect(bereq->be->dpcli->conn_ctx);
+ goto done;
+ }
+
+ conn = sbus_get_connection(bereq->req->src_cli->conn_ctx);
+ ret = dbus_message_append_args(bereq->req->reply,
+ DBUS_TYPE_UINT32, &pam_status,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1, ("Failed to build reply ... frontend will wait for timeout ...\n"));
+ talloc_free(bereq->req);
+ goto done;
+ }
+
+ /* finally send it */
+ dbus_connection_send(conn, bereq->req->reply, NULL);
+ dbus_message_unref(bereq->req->reply);
+ talloc_free(bereq->req);
+
+done:
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(reply);
+}
+
+static int dp_call_pamhandler(struct dp_be_request *bereq, struct pam_data *pd)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending_reply;
+ DBusConnection *conn;
+ dbus_bool_t ret;
+
+ conn = sbus_get_connection(bereq->be->dpcli->conn_ctx);
+
+ /* create the message */
+ msg = dbus_message_new_method_call(NULL,
+ DP_CLI_PATH,
+ DP_CLI_INTERFACE,
+ DP_CLI_METHOD_PAMHANDLER);
+ if (msg == NULL) {
+ DEBUG(0,("Out of memory?!\n"));
+ return ENOMEM;
+ }
+
+ DEBUG(4, ("Sending request with to following data\n"));
+ DEBUG_PAM_DATA(4, pd);
+
+ ret = dbus_message_append_args(msg,
+ DBUS_TYPE_INT32, &(pd->cmd),
+ DBUS_TYPE_STRING, &(pd->domain),
+ DBUS_TYPE_STRING, &(pd->user),
+ DBUS_TYPE_STRING, &(pd->service),
+ DBUS_TYPE_STRING, &(pd->tty),
+ DBUS_TYPE_STRING, &(pd->ruser),
+ DBUS_TYPE_STRING, &(pd->rhost),
+ DBUS_TYPE_INT32, &(pd->authtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->authtok),
+ (pd->authtok_size),
+ DBUS_TYPE_INT32, &(pd->newauthtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->newauthtok),
+ pd->newauthtok_size,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to build message\n"));
+ return EIO;
+ }
+
+ ret = dbus_connection_send_with_reply(conn, msg, &pending_reply,
+ 600000 /* TODO: set timeout */);
+ if (!ret) {
+ /*
+ * Critical Failure
+ * We can't communicate on this connection
+ * We'll drop it using the default destructor.
+ */
+ DEBUG(0, ("D-BUS send failed.\n"));
+ dbus_message_unref(msg);
+ return EIO;
+ }
+
+ /* Set up the reply handler */
+ dbus_pending_call_set_notify(pending_reply, be_got_pam_reply,
+ bereq, NULL);
+ dbus_message_unref(msg);
+
+ return EOK;
+}
+
+static int dp_pamhandler(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+ DBusMessage *reply;
+ DBusError dbus_error;
+ struct dp_client *dpcli;
+ struct dp_backend *dpbe;
+ struct dp_be_request *bereq;
+ struct dp_request *dpreq = NULL;
+ dbus_bool_t dbret;
+ void *user_data;
+ int ret;
+ struct pam_data *pd;
+ int pam_status=PAM_SUCCESS;
+ int domain_found=0;
+
+ user_data = sbus_conn_get_private_data(sconn);
+ if (!user_data) return EINVAL;
+ dpcli = talloc_get_type(user_data, struct dp_client);
+ if (!dpcli) return EINVAL;
+
+/* FIXME: free arrays returned by dbus_message_get_args() */
+ pd = talloc(NULL, struct pam_data);
+ if (!pd) return ENOMEM;
+
+ dbus_error_init(&dbus_error);
+
+ ret = dbus_message_get_args(message, &dbus_error,
+ DBUS_TYPE_INT32, &(pd->cmd),
+ DBUS_TYPE_STRING, &(pd->domain),
+ DBUS_TYPE_STRING, &(pd->user),
+ DBUS_TYPE_STRING, &(pd->service),
+ DBUS_TYPE_STRING, &(pd->tty),
+ DBUS_TYPE_STRING, &(pd->ruser),
+ DBUS_TYPE_STRING, &(pd->rhost),
+ DBUS_TYPE_INT32, &(pd->authtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->authtok),
+ &(pd->authtok_size),
+ DBUS_TYPE_INT32, &(pd->newauthtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->newauthtok),
+ &(pd->newauthtok_size),
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(0,("Failed, to parse message!\n"));
+ if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+ talloc_free(pd);
+ return EIO;
+ }
+
+ DEBUG(4, ("Got the following data:\n"));
+ DEBUG_PAM_DATA(4, pd);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ DEBUG(0,("Out of memory?!\n"));
+ talloc_free(pd);
+ return ENOMEM;
+ }
+
+ dpreq = talloc(dpcli->dpctx, struct dp_request);
+ if (!dpreq) {
+ ret = ENOMEM;
+ pam_status = PAM_ABORT;
+ goto respond;
+ }
+
+ dpreq->reply = reply;
+ dpreq->src_cli = dpcli;
+ dpreq->pending_replies = 0;
+ /* FIXME: add handling of default domain */
+ dpbe = dpcli->dpctx->be_list;
+ while (dpbe) {
+ DEBUG(4, ("Checking [%s][%s]\n", pd->domain, dpbe->domain));
+ if (strcasecmp(dpbe->domain, pd->domain) == 0 ) {
+ domain_found=1;
+ bereq = talloc(dpreq, struct dp_be_request);
+ if (!bereq) {
+ DEBUG(1, ("Out of memory while sending requests\n"));
+ dpbe = dpbe->next;
+ continue;
+ }
+ bereq->req = dpreq;
+ bereq->be = dpbe;
+ DEBUG(4, ("Sending wildcard request to [%s]\n", dpbe->domain));
+ ret = dp_call_pamhandler(bereq, pd);
+ if (ret != EOK) {
+ DEBUG(2,("Failed to dispatch request to %s\n", dpbe->domain));
+ dpbe = dpbe->next;
+ continue;
+ }
+ dpreq->pending_replies++;
+ }
+ dpbe = dpbe->next;
+ }
+
+ if (domain_found) {
+ talloc_free(pd);
+ return EOK;
+ }
+
+ pam_status = PAM_MODULE_UNKNOWN;
+
+respond:
+ dbret = dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32, &pam_status,
+ DBUS_TYPE_STRING, &(pd->domain),
+ DBUS_TYPE_INVALID);
+ if (!dbret) return EIO;
+
+ /* send reply back immediately */
+ sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+
+ talloc_free(pd);
+ return EOK;
+}
+
static int dp_backend_destructor(void *ctx)
{
struct dp_backend *dpbe = talloc_get_type(ctx, struct dp_backend);
diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h
index 5dc402ef..2d0e37e1 100644
--- a/server/providers/data_provider.h
+++ b/server/providers/data_provider.h
@@ -52,11 +52,17 @@
#define DP_CLI_FRONTEND 0x0002
#define DP_CLI_TYPE_MASK 0x0003
+#define DP_CLI_PROVIDE_ACC_INFO (1<<8)
+#define DP_CLI_PROVIDE_PAM (1<<9)
+#define DP_CLI_PROVIDE_POLICY (1<<10)
+
#define DP_CLI_METHOD_IDENTITY "getIdentity"
#define DP_CLI_METHOD_ONLINE "getOnline"
#define DP_CLI_METHOD_GETACCTINFO "getAccountInfo"
+#define DP_CLI_METHOD_PAMHANDLER "pamHandler"
#define DP_SRV_METHOD_GETACCTINFO "getAccountInfo"
+#define DP_SRV_METHOD_PAMHANDLER "pamHandler"
#define DP_ERR_OK 0
#define DP_ERR_OFFLINE 1
diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index 26a78efb..9ed3d2ce 100644
--- a/server/providers/data_provider_be.c
+++ b/server/providers/data_provider_be.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <sys/time.h>
#include <errno.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
#include "popt.h"
#include "util/util.h"
#include "confdb/confdb.h"
@@ -40,7 +44,7 @@
#include "providers/dp_sbus.h"
#include "monitor/monitor_sbus.h"
#include "monitor/monitor_interfaces.h"
-
+#include "../sss_client/sss_cli.h"
typedef int (*be_init_fn_t)(TALLOC_CTX *, struct be_mod_ops **, void **);
@@ -56,11 +60,13 @@ struct sbus_method mon_sbus_methods[] = {
static int be_identity(DBusMessage *message, struct sbus_conn_ctx *sconn);
static int be_check_online(DBusMessage *message, struct sbus_conn_ctx *sconn);
static int be_get_account_info(DBusMessage *message, struct sbus_conn_ctx *sconn);
+static int be_pam_handler(DBusMessage *message, struct sbus_conn_ctx *sconn);
struct sbus_method be_methods[] = {
{ DP_CLI_METHOD_IDENTITY, be_identity },
{ DP_CLI_METHOD_ONLINE, be_check_online },
{ DP_CLI_METHOD_GETACCTINFO, be_get_account_info },
+ { DP_CLI_METHOD_PAMHANDLER, be_pam_handler },
{ NULL, NULL }
};
@@ -503,8 +509,138 @@ done:
return EOK;
}
+static void be_pam_handler_callback(struct be_req *req, int status,
+ const char *errstr) {
+ struct be_pam_handler *ph;
+ DBusMessage *reply;
+ DBusConnection *conn;
+ dbus_bool_t dbret;
+
+ ph = talloc_get_type(req->req_data, struct be_pam_handler);
+
+ DEBUG(4, ("Sending result [%d][%s]\n", ph->pam_status, ph->domain));
+ reply = (DBusMessage *)req->pvt;
+ dbret = dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32, &(ph->pam_status),
+ DBUS_TYPE_STRING, &(ph->domain),
+ DBUS_TYPE_INVALID);
+ if (!dbret) {
+ DEBUG(1, ("Failed to generate dbus reply\n"));
+ return;
+ }
+
+ conn = sbus_get_connection(req->be_ctx->dp_ctx->scon_ctx);
+ dbus_connection_send(conn, reply, NULL);
+ dbus_message_unref(reply);
+
+ DEBUG(4, ("Sent result [%d][%s]\n", ph->pam_status, ph->domain));
+
+ talloc_free(req);
+}
+
+static int be_pam_handler(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+ DBusError dbus_error;
+ DBusMessage *reply;
+ struct be_ctx *ctx;
+ struct be_pam_handler *req;
+ struct be_req *be_req;
+ dbus_bool_t ret;
+ void *user_data;
+ struct pam_data *pd;
+ uint32_t pam_status=99;
+
+ user_data = sbus_conn_get_private_data(sconn);
+ if (!user_data) return EINVAL;
+ ctx = talloc_get_type(user_data, struct be_ctx);
+ if (!ctx) return EINVAL;
+
+ pd = talloc(NULL, struct pam_data);
+ if (!pd) return ENOMEM;
+
+ dbus_error_init(&dbus_error);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ DEBUG(1, ("dbus_message_new_method_return failed, cannot send reply.\n"));
+ talloc_free(pd);
+ return ENOMEM;
+ }
+ ret = dbus_message_get_args(message, &dbus_error,
+ DBUS_TYPE_INT32, &(pd->cmd),
+ DBUS_TYPE_STRING, &(pd->domain),
+ DBUS_TYPE_STRING, &(pd->user),
+ DBUS_TYPE_STRING, &(pd->service),
+ DBUS_TYPE_STRING, &(pd->tty),
+ DBUS_TYPE_STRING, &(pd->ruser),
+ DBUS_TYPE_STRING, &(pd->rhost),
+ DBUS_TYPE_INT32, &(pd->authtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->authtok),
+ &(pd->authtok_size),
+ DBUS_TYPE_INT32, &(pd->newauthtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->newauthtok),
+ &(pd->newauthtok_size),
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed, to parse message!\n"));
+ talloc_free(pd);
+ return EIO;
+ }
+
+ DEBUG(4, ("Got request with the following data\n"));
+ DEBUG_PAM_DATA(4, pd);
+
+ be_req = talloc(ctx, struct be_req);
+ if (!be_req) {
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ be_req->be_ctx = ctx;
+ be_req->fn = be_pam_handler_callback;
+ be_req->pvt = reply;
+
+ req = talloc(be_req, struct be_pam_handler);
+ if (!req) {
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ req->domain = ctx->domain;
+ req->pd = pd;
+
+ be_req->req_data = req;
+
+ ret = be_file_request(ctx, ctx->ops->pam_handler, be_req);
+ if (ret != EOK) {
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ return EOK;
+
+done:
+ if (be_req) {
+ talloc_free(be_req);
+ }
+
+ DEBUG(4, ("Sending result [%d][%s]\n", pam_status, ctx->domain));
+ ret = dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32, &pam_status,
+ DBUS_TYPE_STRING, &ctx->domain,
+ DBUS_TYPE_INVALID);
+ if (!ret) return EIO;
+
+ /* send reply back immediately */
+ sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+
+ talloc_free(pd);
+ return EOK;
+}
+
/* mon_cli_init
* sbus channel to the monitor daemon */
static int mon_cli_init(struct be_ctx *ctx)
diff --git a/server/providers/dp_backend.h b/server/providers/dp_backend.h
index 765c16ee..cdd2c51b 100644
--- a/server/providers/dp_backend.h
+++ b/server/providers/dp_backend.h
@@ -24,6 +24,7 @@
#include "providers/data_provider.h"
#include "db/sysdb.h"
+#include "responder/pam/pamsrv.h"
struct be_mod_ops;
@@ -64,11 +65,18 @@ struct be_online_req {
int online;
};
+struct be_pam_handler {
+ int pam_status;
+ const char *domain;
+ struct pam_data *pd;
+};
+
typedef void (*be_req_fn_t)(struct be_req *);
struct be_mod_ops {
be_req_fn_t check_online;
be_req_fn_t get_account_info;
+ be_req_fn_t pam_handler;
};
#endif /* __DP_BACKEND_H___ */
diff --git a/server/providers/ldap_be.c b/server/providers/ldap_be.c
new file mode 100644
index 00000000..6c573b7d
--- /dev/null
+++ b/server/providers/ldap_be.c
@@ -0,0 +1,676 @@
+/*
+ SSSD
+
+ LDAP Backend Module
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2008 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 <ldap.h>
+#include <sys/time.h>
+
+#include <security/pam_modules.h>
+
+#include "util/util.h"
+#include "providers/dp_backend.h"
+#include "db/sysdb.h"
+#include "../sss_client/sss_cli.h"
+
+struct ldap_ctx {
+ char *ldap_uri;
+ char *default_bind_dn;
+ char *default_authtok_type;
+ uint32_t default_authtok_size;
+ char *default_authtok;
+};
+
+struct ldap_ops;
+struct ldap_req;
+
+struct ldap_ops {
+ void (*op)(struct ldap_req *);
+ struct ldap_ops *next;
+};
+
+enum ldap_be_ops {
+ LDAP_NOOP = 0x0000,
+ LDAP_OP_INIT = 0x0001,
+ LDAP_CHECK_INIT_RESULT,
+ LDAP_CHECK_STD_BIND,
+ LDAP_CHECK_SEARCH_DN_RESULT,
+ LDAP_CHECK_USER_BIND
+};
+
+struct ldap_req {
+ struct be_req *req;
+ struct pam_data *pd;
+ struct ldap_ctx *ldap_ctx;
+ LDAP *ldap;
+ struct ldap_ops *ops;
+ char *user_dn;
+ /*event_timed_handler_t next_task;*/
+ event_fd_handler_t next_task;
+ enum ldap_be_ops next_op;
+ int msgid;
+};
+
+static int schedule_next_task(struct ldap_req *lr, struct timeval tv,
+ event_timed_handler_t task) {
+ int ret;
+ struct timed_event *te;
+ struct timeval timeout;
+
+ ret = gettimeofday(&timeout, NULL);
+ if (ret == -1) {
+ DEBUG(1, ("gettimeofday failed [%d][%s].\n", errno, strerror(errno)));
+ return ret;
+ }
+ timeout.tv_sec += tv.tv_sec;
+ timeout.tv_usec += tv.tv_usec;
+
+
+ te = event_add_timed(lr->req->be_ctx->ev, lr, timeout, task, lr);
+ if ( te == NULL ) {
+ return EIO;
+ }
+
+ return EOK;
+}
+
+static int wait_for_fd(struct ldap_req *lr) {
+ int ret;
+ int fd;
+ struct fd_event *fde;
+
+ ret = ldap_get_option(lr->ldap, LDAP_OPT_DESC, &fd);
+ if ( ret != LDAP_OPT_SUCCESS ) {
+ DEBUG(1, ("ldap_get_option failed.\n"));
+ return ret;
+ }
+
+ fde = event_add_fd(lr->req->be_ctx->ev, lr, fd, EVENT_FD_READ, lr->next_task, lr);
+ if ( fde == NULL ) {
+ return EIO;
+ }
+
+ return EOK;
+}
+
+static int ldap_pam_chauthtok(struct ldap_req *lr) {
+ BerElement *ber=NULL;
+ int ret;
+ int pam_status=PAM_SUCCESS;
+ struct berval *bv;
+ int msgid;
+ LDAPMessage *result=NULL;
+ int ldap_ret;
+
+ ber = ber_alloc_t( LBER_USE_DER );
+ if ( ber == NULL ) {
+ DEBUG(1, ("ber_alloc_t failed.\n"));
+ return PAM_SYSTEM_ERR;
+ }
+
+ ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
+ lr->user_dn,
+ LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, lr->pd->authtok,
+ LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, lr->pd->newauthtok);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ber_printf failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto cleanup;
+ }
+
+ ret = ber_flatten(ber, &bv);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ber_flatten failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto cleanup;
+ }
+
+ ret = ldap_extended_operation(lr->ldap, LDAP_EXOP_MODIFY_PASSWD, bv,
+ NULL, NULL, &msgid);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_extended_operation failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto cleanup;
+ }
+
+ ret = ldap_result(lr->ldap, msgid, FALSE, NULL, &result);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ldap_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto cleanup;
+ }
+ ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, NULL, NULL,
+ NULL, 0);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_parse_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto cleanup;
+ }
+ DEBUG(3, ("LDAP_EXOP_MODIFY_PASSWD result: [%d][%s]\n", ldap_ret,
+ ldap_err2string(ldap_ret)));
+
+ ldap_msgfree(result);
+
+ if ( ldap_ret != LDAP_SUCCESS ) pam_status = PAM_SYSTEM_ERR;
+
+cleanup:
+ ber_bvfree(bv);
+ ber_free(ber, 1);
+ return pam_status;
+}
+
+static int ldap_be_init(struct ldap_req *lr) {
+ int ret;
+ int status=EOK;
+ int ldap_vers = LDAP_VERSION3;
+ int msgid;
+
+ ret = ldap_initialize(&(lr->ldap), lr->ldap_ctx->ldap_uri);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(1, ("ldap_initialize failed: %s\n", strerror(errno)));
+ return EIO;
+ }
+
+ /* LDAPv3 is needed for TLS */
+ ret = ldap_set_option(lr->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_vers);
+ if ( ret != LDAP_OPT_SUCCESS) {
+ DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret)));
+ status = EIO;
+ goto cleanup;
+ }
+
+ /* For now TLS is forced. Maybe it would be necessary to make this
+ * configurable to allow people to expose their passwords over the
+ * network. */
+ ret = ldap_start_tls(lr->ldap, NULL, NULL, &msgid);
+ if ( ret != LDAP_SUCCESS) {
+ DEBUG(1, ("ldap_start_tls failed: %s\n", ldap_err2string(ret)));
+ status = EIO;
+ goto cleanup;
+ }
+
+ lr->msgid = msgid;
+
+ return EOK;
+
+cleanup:
+ ldap_unbind_ext(lr->ldap, NULL, NULL);
+ lr->ldap = NULL;
+ return status;
+}
+
+static int ldap_be_bind(struct ldap_req *lr) {
+ int ret;
+ int msgid;
+ char *dn=NULL;
+ struct berval pw;
+
+ pw.bv_len = 0;
+ pw.bv_val = NULL;
+
+ if ( lr->user_dn != NULL ) {
+ dn = lr->user_dn;
+ pw.bv_len = lr->pd->authtok_size;
+ pw.bv_val = (char *) lr->pd->authtok;
+ }
+ if ( lr->user_dn == NULL && lr->ldap_ctx->default_bind_dn != NULL ) {
+ dn = lr->ldap_ctx->default_bind_dn;
+ pw.bv_len = lr->ldap_ctx->default_authtok_size;
+ pw.bv_val = lr->ldap_ctx->default_authtok;
+ }
+
+ DEBUG(3, ("Trying to bind as [%s][%*s]\n", dn, pw.bv_len, pw.bv_val));
+ ret = ldap_sasl_bind(lr->ldap, dn, LDAP_SASL_SIMPLE, &pw, NULL, NULL,
+ &msgid);
+ if ( ret == -1 || msgid == -1 ) {
+ DEBUG(1, ("ldap_bind failed\n"));
+ return LDAP_OTHER;
+ }
+ lr->msgid = msgid;
+ return LDAP_SUCCESS;
+}
+
+static void ldap_be_loop(struct event_context *ev, struct fd_event *te,
+ uint16_t fd, void *pvt) {
+ int ret;
+ int pam_status=PAM_SUCCESS;
+ int ldap_ret;
+ struct ldap_req *lr;
+ struct be_pam_handler *ph;
+ struct be_req *req;
+ LDAPMessage *result=NULL;
+ LDAPMessage *msg=NULL;
+ struct timeval no_timeout={0, 0};
+ char *errmsgp = NULL;
+/* FIXME: user timeout form config */
+ char *filter=NULL;
+ char *attrs[] = { LDAP_NO_ATTRS, NULL };
+
+ lr = talloc_get_type(pvt, struct ldap_req);
+
+ switch ( lr->next_op ) {
+ case LDAP_OP_INIT:
+ ret = ldap_be_init(lr);
+ if (ret != EOK) {
+ DEBUG(1, ("ldap_be_init failed.\n"));
+ lr->ldap = NULL;
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ case LDAP_CHECK_INIT_RESULT:
+ ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ldap_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ if ( ret == 0 ) {
+ DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
+ lr->next_task = ldap_be_loop;
+ lr->next_op = LDAP_CHECK_INIT_RESULT;
+ ret = wait_for_fd(lr);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ return;
+ }
+
+ ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, NULL, NULL, NULL, 0);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_parse_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ DEBUG(3, ("ldap_start_tls result: [%d][%s]\n", ldap_ret, ldap_err2string(ldap_ret)));
+
+ if ( ldap_ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("setting up TLS failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+/* FIXME: take care that ldap_install_tls might block */
+ ret = ldap_install_tls(lr->ldap);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_install_tls failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ ret = ldap_be_bind(lr);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_be_bind failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ case LDAP_CHECK_STD_BIND:
+ ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ldap_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ if ( ret == 0 ) {
+ DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
+ lr->next_task = ldap_be_loop;
+ lr->next_op = LDAP_CHECK_STD_BIND;
+ ret = wait_for_fd(lr);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ return;
+ }
+
+ ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, &errmsgp,
+ NULL, NULL, 0);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_parse_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ DEBUG(3, ("Bind result: [%d][%s][%s]\n", ldap_ret,
+ ldap_err2string(ldap_ret), errmsgp));
+ if ( ldap_ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("bind failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ filter = talloc_asprintf(lr->ldap_ctx,
+ "(&(uid=%s)(objectclass=posixAccount))",
+ lr->pd->user);
+
+ DEBUG(4, ("calling ldap_search_ext with [%s].\n", filter));
+ ret = ldap_search_ext(lr->ldap,
+ "ou=user,dc=my-domain,dc=com",
+ LDAP_SCOPE_SUBTREE,
+ filter,
+ attrs,
+ TRUE,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &(lr->msgid));
+ if ( ret != LDAP_SUCCESS) {
+ DEBUG(1, ("ldap_search_ext failed [%d][%s].\n", ret, ldap_err2string(ret)));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ case LDAP_CHECK_SEARCH_DN_RESULT:
+ ret = ldap_result(lr->ldap, lr->msgid, TRUE, &no_timeout, &result);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ldap_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ if ( ret == 0 ) {
+ DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
+ lr->next_task = ldap_be_loop;
+ lr->next_op = LDAP_CHECK_SEARCH_DN_RESULT;
+ ret = wait_for_fd(lr);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ return;
+ }
+
+ msg = ldap_first_message(lr->ldap, result);
+ if ( msg == NULL ) {
+ DEBUG(1, ("ldap_first_message failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ do {
+ switch ( ldap_msgtype(msg) ) {
+ case LDAP_RES_SEARCH_ENTRY:
+ if ( lr->user_dn != NULL ) {
+ DEBUG(1, ("Found more than one object with filter [%s].\n",
+ filter));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ lr->user_dn = ldap_get_dn(lr->ldap, msg);
+ if ( lr->user_dn == NULL ) {
+ DEBUG(1, ("ldap_get_dn failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ if ( *(lr->user_dn) == '\0' ) {
+ DEBUG(1, ("No user found.\n"));
+ pam_status = PAM_USER_UNKNOWN;
+ goto done;
+ }
+ DEBUG(3, ("Found dn: %s\n",lr->user_dn));
+
+ ldap_msgfree(result);
+ result = NULL;
+ break;
+ default:
+ DEBUG(3, ("ignoring message with type %d.\n", ldap_msgtype(msg)));
+ }
+ } while( (msg=ldap_next_message(lr->ldap, msg)) != NULL );
+
+ ret = ldap_be_bind(lr);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_be_bind failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ case LDAP_CHECK_USER_BIND:
+ ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
+ if ( ret == -1 ) {
+ DEBUG(1, ("ldap_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ if ( ret == 0 ) {
+ DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
+ lr->next_task = ldap_be_loop;
+ lr->next_op = LDAP_CHECK_USER_BIND;
+ ret = wait_for_fd(lr);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ return;
+ }
+
+ ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, &errmsgp,
+ NULL, NULL, 0);
+ if ( ret != LDAP_SUCCESS ) {
+ DEBUG(1, ("ldap_parse_result failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ DEBUG(3, ("Bind result: [%d][%s][%s]\n", ldap_ret,
+ ldap_err2string(ldap_ret), errmsgp));
+ switch (ldap_ret) {
+ case LDAP_SUCCESS:
+ pam_status = PAM_SUCCESS;
+ break;
+ case LDAP_INVALID_CREDENTIALS:
+ pam_status = PAM_CRED_INSUFFICIENT;
+ goto done;
+ break;
+ default:
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+
+
+
+/*
+ ret = pam_setup_ldap_connection(lr);
+ if ( ret != PAM_SUCCESS ) {
+ DEBUG(1, ("pam_setup_ldap_connection failed.\n"));
+ pam_status = ret;
+ goto done;
+ }
+ DEBUG(3, ("Successfully connected as %s.\n", lr->user_dn));
+*/
+
+ switch (lr->pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ pam_status = PAM_SUCCESS;
+ break;
+ case SSS_PAM_CHAUTHTOK:
+ pam_status = ldap_pam_chauthtok(lr);
+ break;
+ case SSS_PAM_ACCT_MGMT:
+ case SSS_PAM_SETCRED:
+ case SSS_PAM_OPEN_SESSION:
+ case SSS_PAM_CLOSE_SESSION:
+ pam_status = PAM_SUCCESS;
+ break;
+ default:
+ DEBUG(1, ("Unknown pam command %d.\n", lr->pd->cmd));
+ pam_status = PAM_SYSTEM_ERR;
+ }
+ break;
+ default:
+ DEBUG(1, ("Unknown ldap backend operation %d.\n", lr->next_op));
+ pam_status = PAM_SYSTEM_ERR;
+ }
+
+done:
+ ldap_memfree(errmsgp);
+ ldap_msgfree(result);
+ talloc_free(filter);
+ if (lr->ldap != NULL ) ldap_unbind_ext(lr->ldap, NULL, NULL);
+ req = lr->req;
+ ph = talloc_get_type(lr->req->req_data, struct be_pam_handler);
+ ph->pam_status = pam_status;
+
+ talloc_free(lr);
+
+ req->fn(req, pam_status, NULL);
+}
+
+static void ldap_start(struct event_context *ev, struct timed_event *te,
+ struct timeval tv, void *pvt) {
+ int ret;
+ int pam_status;
+ struct ldap_req *lr;
+ struct be_req *req;
+ struct be_pam_handler *ph;
+
+ lr = talloc_get_type(pvt, struct ldap_req);
+
+ ret = ldap_be_init(lr);
+ if (ret != EOK) {
+ DEBUG(1, ("ldap_be_init failed.\n"));
+ lr->ldap = NULL;
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ lr->next_task = ldap_be_loop;
+ lr->next_op = LDAP_CHECK_INIT_RESULT;
+ ret = wait_for_fd(lr);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+ return;
+
+done:
+ if (lr->ldap != NULL ) ldap_unbind_ext(lr->ldap, NULL, NULL);
+ req = lr->req;
+ ph = talloc_get_type(lr->req->req_data, struct be_pam_handler);
+ ph->pam_status = pam_status;
+
+ talloc_free(lr);
+
+ req->fn(req, pam_status, NULL);
+}
+
+static void ldap_pam_handler(struct be_req *req) {
+ int ret;
+ int pam_status=PAM_SUCCESS;
+ struct ldap_req *lr;
+ struct ldap_ctx *ldap_ctx;
+ struct be_pam_handler *ph;
+ struct pam_data *pd;
+ struct timeval timeout;
+
+ ph = talloc_get_type(req->req_data, struct be_pam_handler);
+ pd = ph->pd;
+
+ ldap_ctx = talloc_get_type(req->be_ctx->pvt_data, struct ldap_ctx);
+
+ lr = talloc(req, struct ldap_req);
+
+ lr->ldap = NULL;
+ lr->req = req;
+ lr->pd = pd;
+ lr->ldap_ctx = ldap_ctx;
+ lr->user_dn = NULL;
+ lr->next_task = NULL;
+ lr->next_op = LDAP_NOOP;
+
+ timeout.tv_sec=0;
+ timeout.tv_usec=0;
+ ret = schedule_next_task(lr, timeout, ldap_start);
+ if ( ret != EOK ) {
+ DEBUG(1, ("schedule_next_task failed.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ return;
+
+done:
+ talloc_free(lr);
+
+ ph->pam_status = pam_status;
+ req->fn(req, pam_status, NULL);
+}
+
+struct be_mod_ops ldap_mod_ops = {
+ .check_online = NULL,
+ .get_account_info = NULL,
+ .pam_handler = ldap_pam_handler
+};
+
+
+int sssm_ldap_init(struct be_ctx *bectx, struct be_mod_ops **ops, void **pvt_data)
+{
+ struct ldap_ctx *ctx;
+ char *ldap_uri;
+ char *default_bind_dn;
+ char *default_authtok_type;
+ char *default_authtok;
+ int ret;
+
+ ctx = talloc(bectx, struct ldap_ctx);
+ if (!ctx) {
+ return ENOMEM;
+ }
+
+ ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ "ldapUri", "ldap://localhost", &ldap_uri);
+ if (ret != EOK) goto done;
+ ctx->ldap_uri = ldap_uri;
+
+ ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ "defaultBindDn", NULL, &default_bind_dn);
+ if (ret != EOK) goto done;
+ ctx->default_bind_dn = default_bind_dn;
+
+ ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ "defaultAuthtokType", NULL, &default_authtok_type);
+ if (ret != EOK) goto done;
+ ctx->default_authtok_type = default_authtok_type;
+
+
+/* TODO: better to have a blob object than a string here */
+ ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ "defaultAuthtok", NULL, &default_authtok);
+ if (ret != EOK) goto done;
+ ctx->default_authtok = default_authtok;
+ ctx->default_authtok_size = (default_authtok==NULL?0:strlen(default_authtok));
+
+
+
+ *ops = &ldap_mod_ops;
+ *pvt_data = ctx;
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(ctx);
+ }
+ return ret;
+}
diff --git a/server/providers/proxy.c b/server/providers/proxy.c
index 0ec6e530..e072ec3c 100644
--- a/server/providers/proxy.c
+++ b/server/providers/proxy.c
@@ -23,9 +23,14 @@
#include <errno.h>
#include <pwd.h>
#include <grp.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
#include "util/util.h"
#include "providers/dp_backend.h"
#include "db/sysdb.h"
+#include "../sss_client/sss_cli.h"
struct proxy_nss_ops {
enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
@@ -154,6 +159,130 @@ static void get_pw_uid(struct be_req *req, uid_t uid)
return proxy_reply(req, EOK, NULL);
}
+struct authtok_conv {
+ char *authtok;
+ char *oldauthtok;
+};
+
+static int proxy_internal_conv(int num_msg, const struct pam_message **msgm,
+ struct pam_response **response,
+ void *appdata_ptr) {
+ int i;
+ struct pam_response *reply;
+ struct authtok_conv *auth_data;
+
+ auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
+
+ if (num_msg <= 0) return PAM_CONV_ERR;
+
+ reply = (struct pam_response *) calloc(num_msg,
+ sizeof(struct pam_response));
+ if (reply == NULL) return PAM_CONV_ERR;
+
+ for (i=0; i < num_msg; i++) {
+ switch( msgm[i]->msg_style ) {
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG(4, ("Conversation message: %s.\n", msgm[i]->msg));
+ reply[i].resp_retcode = 0;
+ reply[i].resp = strdup(auth_data->authtok);
+ break;
+ default:
+ DEBUG(1, ("Conversation style %d not supported.\n",
+ msgm[i]->msg_style));
+ goto failed;
+ }
+ }
+
+ *response = reply;
+ reply = NULL;
+
+ return PAM_SUCCESS;
+
+failed:
+ free(reply);
+ return PAM_CONV_ERR;
+}
+
+static void proxy_pam_handler(struct be_req *req) {
+ int ret;
+ int pam_status;
+ pam_handle_t *pamh=NULL;
+ struct authtok_conv *auth_data;
+ struct pam_conv conv;
+ struct be_pam_handler *ph;
+ struct pam_data *pd;
+
+ ph = talloc_get_type(req->req_data, struct be_pam_handler);
+ pd = ph->pd;
+
+ conv.conv=proxy_internal_conv;
+ auth_data = talloc_zero(req->be_ctx, struct authtok_conv);
+ conv.appdata_ptr=auth_data;
+
+ ret = pam_start("sssd_be_test", pd->user, &conv, &pamh);
+ if (ret == PAM_SUCCESS) {
+ DEBUG(1, ("Pam transaction started.\n"));
+ pam_set_item(pamh, PAM_TTY, pd->tty);
+ if (ret != PAM_SUCCESS) {
+ DEBUG(1, ("Setting PAM_TTY failed: %s.\n", pam_strerror(pamh, ret)));
+ }
+ pam_set_item(pamh, PAM_RUSER, pd->ruser);
+ if (ret != PAM_SUCCESS) {
+ DEBUG(1, ("Setting PAM_RUSER failed: %s.\n", pam_strerror(pamh, ret)));
+ }
+ pam_set_item(pamh, PAM_RHOST, pd->rhost);
+ if (ret != PAM_SUCCESS) {
+ DEBUG(1, ("Setting PAM_RHOST failed: %s.\n", pam_strerror(pamh, ret)));
+ }
+ switch (pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+/* FIXME: \0 missing at the end */
+ auth_data->authtok=(char *) pd->authtok;
+ auth_data->oldauthtok=NULL;
+ pam_status=pam_authenticate(pamh, 0);
+ break;
+ case SSS_PAM_SETCRED:
+ pam_status=pam_setcred(pamh, 0);
+ break;
+ case SSS_PAM_ACCT_MGMT:
+ pam_status=pam_acct_mgmt(pamh, 0);
+ break;
+ case SSS_PAM_OPEN_SESSION:
+ pam_status=pam_open_session(pamh, 0);
+ break;
+ case SSS_PAM_CLOSE_SESSION:
+ pam_status=pam_close_session(pamh, 0);
+ break;
+ case SSS_PAM_CHAUTHTOK:
+/* FIXME: \0 missing at the end */
+ auth_data->authtok=(char *) pd->newauthtok;
+ auth_data->oldauthtok=(char *) pd->authtok;
+ pam_status=pam_chauthtok(pamh, 0);
+ break;
+ default:
+ DEBUG(1, ("unknown PAM call"));
+ pam_status=PAM_ABORT;
+ }
+
+ DEBUG(4, ("Pam result: [%d][%s]\n", pam_status, pam_strerror(pamh, pam_status)));
+
+ ret = pam_end(pamh, pam_status);
+ if (ret != PAM_SUCCESS) {
+ pamh=NULL;
+ DEBUG(1, ("Cannot terminate pam transaction.\n"));
+ }
+
+ } else {
+ DEBUG(1, ("Failed to initialize pam transaction.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ }
+
+ talloc_free(auth_data);
+
+ ph->pam_status = pam_status;
+ req->fn(req, EOK, NULL);
+}
+
#define MAX_BUF_SIZE 1024*1024 /* max 1MiB */
static void enum_users(struct be_req *req)
@@ -664,7 +793,8 @@ static void proxy_get_account_info(struct be_req *req)
struct be_mod_ops proxy_mod_ops = {
.check_online = proxy_check_online,
- .get_account_info = proxy_get_account_info
+ .get_account_info = proxy_get_account_info,
+ .pam_handler = proxy_pam_handler
};
static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
diff --git a/server/responder/common/responder_cmd.c b/server/responder/common/responder_cmd.c
new file mode 100644
index 00000000..83d55e65
--- /dev/null
+++ b/server/responder/common/responder_cmd.c
@@ -0,0 +1,78 @@
+/*
+ SSSD
+
+ SSS Client Responder, command parser
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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 "util/util.h"
+#include "responder/common/responder_cmd.h"
+#include "responder/common/responder_packet.h"
+
+
+void sss_cmd_done(struct sss_cmd_ctx *nctx)
+{
+ /* now that the packet is in place, unlock queue
+ * making the event writable */
+ EVENT_FD_WRITEABLE(nctx->cctx->cfde);
+
+ /* free all request related data through the talloc hierarchy */
+ talloc_free(nctx);
+}
+
+int sss_cmd_get_version(struct cli_ctx *cctx)
+{
+ struct sss_cmd_ctx *nctx;
+ uint8_t *body;
+ size_t blen;
+ int ret;
+
+ nctx = talloc(cctx, struct sss_cmd_ctx);
+ if (!nctx) {
+ return ENOMEM;
+ }
+ nctx->cctx = cctx;
+
+ /* create response packet */
+ ret = sss_packet_new(cctx->creq, sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
+ &cctx->creq->out);
+ if (ret != EOK) {
+ return ret;
+ }
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
+ ((uint32_t *)body)[0] = SSS_PROTOCOL_VERSION;
+
+ sss_cmd_done(nctx);
+ return EOK;
+}
+
+int sss_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds)
+{
+ enum sss_cli_command cmd;
+ int i;
+
+ cmd = sss_packet_get_cmd(cctx->creq->in);
+
+ for (i = 0; sss_cmds[i].cmd != SSS_CLI_NULL; i++) {
+ if (cmd == sss_cmds[i].cmd) {
+ return sss_cmds[i].fn(cctx);
+ }
+ }
+
+ return EINVAL;
+}
diff --git a/server/responder/common/responder_cmd.h b/server/responder/common/responder_cmd.h
new file mode 100644
index 00000000..ee094ad3
--- /dev/null
+++ b/server/responder/common/responder_cmd.h
@@ -0,0 +1,71 @@
+/*
+ SSSD
+
+ SSS Client Responder, header file
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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 __SSSSRV_CMD_H__
+#define __SSSSRV_CMD_H__
+
+#include <stdint.h>
+#include <sys/un.h>
+#include "talloc.h"
+#include "tevent.h"
+#include "ldb.h"
+#include "../sss_client/sss_cli.h"
+
+/* needed until nsssrv.h is updated */
+#ifndef __NSSSRV_H__
+struct cli_request {
+
+ /* original request from the wire */
+ struct sss_packet *in;
+
+ /* reply data */
+ struct sss_packet *out;
+};
+
+struct cli_ctx {
+ struct event_context *ev;
+ struct nss_ctx *nctx;
+ int cfd;
+ struct fd_event *cfde;
+ struct sockaddr_un addr;
+ struct cli_request *creq;
+ struct getent_ctx *gctx;
+};
+#endif
+
+struct sss_cmd_ctx {
+ struct cli_ctx *cctx;
+ const char *domain;
+ const char *name;
+ uid_t id;
+ bool check_expiration;
+};
+
+struct sss_cmd_table {
+ enum sss_cli_command cmd;
+ int (*fn)(struct cli_ctx *cctx);
+};
+
+int sss_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds);
+void sss_cmd_done(struct sss_cmd_ctx *nctx);
+int sss_cmd_get_version(struct cli_ctx *cctx);
+
+#endif /* __SSSSRV_CMD_H__ */
diff --git a/server/responder/common/responder_common.c b/server/responder/common/responder_common.c
new file mode 100644
index 00000000..b5db7d1e
--- /dev/null
+++ b/server/responder/common/responder_common.c
@@ -0,0 +1,518 @@
+/*
+ SSSD
+
+ Common Responder methods
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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/nss/nsssrv.h"
+#include "db/sysdb.h"
+#include "confdb/confdb.h"
+#include "dbus/dbus.h"
+#include "sbus/sssd_dbus.h"
+#include "util/btreemap.h"
+#include "responder/common/responder_packet.h"
+#include "responder/common/responder_cmd.h"
+#include "responder/common/responder_dp.h"
+#include "providers/data_provider.h"
+#include "monitor/monitor_sbus.h"
+#include "monitor/monitor_interfaces.h"
+#include "sbus/sbus_client.h"
+
+static void set_nonblocking(int fd)
+{
+ unsigned v;
+ v = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, v | O_NONBLOCK);
+}
+
+static void set_close_on_exec(int fd)
+{
+ unsigned v;
+ v = fcntl(fd, F_GETFD, 0);
+ fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+}
+
+static int client_destructor(struct cli_ctx *ctx)
+{
+ if (ctx->cfd > 0) close(ctx->cfd);
+ return 0;
+}
+
+static void client_send(struct event_context *ev, struct cli_ctx *cctx)
+{
+ int ret;
+
+ ret = sss_packet_send(cctx->creq->out, cctx->cfd);
+ if (ret == EAGAIN) {
+ /* not all data was sent, loop again */
+ return;
+ }
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to read request, aborting client!\n"));
+ talloc_free(cctx);
+ return;
+ }
+
+ /* ok all sent */
+ EVENT_FD_NOT_WRITEABLE(cctx->cfde);
+ EVENT_FD_READABLE(cctx->cfde);
+ talloc_free(cctx->creq);
+ cctx->creq = NULL;
+ return;
+}
+
+static void client_recv(struct event_context *ev, struct cli_ctx *cctx)
+{
+ int ret;
+
+ if (!cctx->creq) {
+ cctx->creq = talloc_zero(cctx, struct cli_request);
+ if (!cctx->creq) {
+ DEBUG(0, ("Failed to alloc request, aborting client!\n"));
+ talloc_free(cctx);
+ return;
+ }
+ }
+
+ if (!cctx->creq->in) {
+ ret = sss_packet_new(cctx->creq, NSS_PACKET_MAX_RECV_SIZE,
+ 0, &cctx->creq->in);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to alloc request, aborting client!\n"));
+ talloc_free(cctx);
+ return;
+ }
+ }
+
+ ret = sss_packet_recv(cctx->creq->in, cctx->cfd);
+ switch (ret) {
+ case EOK:
+ /* do not read anymore */
+ EVENT_FD_NOT_READABLE(cctx->cfde);
+ /* execute command */
+ ret = sss_cmd_execute(cctx, cctx->nctx->sss_cmds);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to execute request, aborting client!\n"));
+ talloc_free(cctx);
+ }
+ /* past this point cctx can be freed at any time by callbacks
+ * in case of error, do not use it */
+ return;
+
+ case EAGAIN:
+ /* need to read still some data, loop again */
+ break;
+
+ case EINVAL:
+ DEBUG(6, ("Invalid data from client, closing connection!\n"));
+ talloc_free(cctx);
+ break;
+
+ case ENODATA:
+ DEBUG(5, ("Client disconnected!\n"));
+ talloc_free(cctx);
+ break;
+
+ default:
+ DEBUG(6, ("Failed to read request, aborting client!\n"));
+ talloc_free(cctx);
+ }
+
+ return;
+}
+
+static void client_fd_handler(struct event_context *ev,
+ struct fd_event *fde,
+ uint16_t flags, void *ptr)
+{
+ struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
+
+ if (flags & EVENT_FD_READ) {
+ client_recv(ev, cctx);
+ return;
+ }
+ if (flags & EVENT_FD_WRITE) {
+ client_send(ev, cctx);
+ return;
+ }
+}
+
+static void accept_fd_handler(struct event_context *ev,
+ struct fd_event *fde,
+ uint16_t flags, void *ptr)
+{
+ /* accept and attach new event handler */
+ struct nss_ctx *nctx = talloc_get_type(ptr, struct nss_ctx);
+ struct cli_ctx *cctx;
+ socklen_t len;
+
+ cctx = talloc_zero(nctx, struct cli_ctx);
+ if (!cctx) {
+ struct sockaddr_un addr;
+ int fd;
+ DEBUG(0, ("Out of memory trying to setup client context!\n"));
+ /* accept and close to signal the client we have a problem */
+ memset(&addr, 0, sizeof(addr));
+ len = sizeof(addr);
+ fd = accept(nctx->lfd, (struct sockaddr *)&addr, &len);
+ if (fd == -1) {
+ return;
+ }
+ close(fd);
+ return;
+ }
+
+ len = sizeof(cctx->addr);
+ cctx->cfd = accept(nctx->lfd, (struct sockaddr *)&cctx->addr, &len);
+ if (cctx->cfd == -1) {
+ DEBUG(1, ("Accept failed [%s]", strerror(errno)));
+ talloc_free(cctx);
+ return;
+ }
+
+ cctx->cfde = event_add_fd(ev, cctx, cctx->cfd,
+ EVENT_FD_READ, client_fd_handler, cctx);
+ if (!cctx->cfde) {
+ close(cctx->cfd);
+ talloc_free(cctx);
+ DEBUG(2, ("Failed to queue client handler\n"));
+ }
+
+ cctx->ev = ev;
+ cctx->nctx = nctx;
+
+ talloc_set_destructor(cctx, client_destructor);
+
+ DEBUG(4, ("Client connected!\n"));
+
+ return;
+}
+
+static int sss_sbus_init(struct nss_ctx *nctx)
+{
+ int ret;
+ char *sbus_address;
+ struct service_sbus_ctx *ss_ctx;
+ struct sbus_method_ctx *sm_ctx;
+
+ /* Set up SBUS connection to the monitor */
+ ret = monitor_get_sbus_address(nctx, nctx->cdb, &sbus_address);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not locate monitor address.\n"));
+ return ret;
+ }
+
+ ret = monitor_init_sbus_methods(nctx, nctx->sss_sbus_methods, &sm_ctx);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not initialize SBUS methods.\n"));
+ return ret;
+ }
+
+ ret = sbus_client_init(nctx, nctx->ev,
+ sbus_address, sm_ctx,
+ NULL /* Private Data */,
+ NULL /* Destructor */,
+ &ss_ctx);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to connect to monitor services.\n"));
+ return ret;
+ }
+
+ /* Set up NSS-specific listeners */
+ /* None currently used */
+
+ nctx->ss_ctx = ss_ctx;
+
+ return EOK;
+}
+
+/* create a unix socket and listen to it */
+static int set_unix_socket(struct nss_ctx *nctx)
+{
+ struct sockaddr_un addr;
+ char *default_pipe;
+ int ret;
+
+ default_pipe = talloc_asprintf(nctx, "%s/%s", PIPE_PATH,
+ nctx->sss_pipe_name);
+ if (!default_pipe) {
+ return ENOMEM;
+ }
+
+ ret = confdb_get_string(nctx->cdb, nctx,
+ nctx->confdb_socket_path, "unixSocket",
+ default_pipe, &nctx->sock_name);
+ if (ret != EOK) {
+ talloc_free(default_pipe);
+ return ret;
+ }
+ talloc_free(default_pipe);
+
+ nctx->lfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (nctx->lfd == -1) {
+ return EIO;
+ }
+
+ /* Set the umask so that permissions are set right on the socket.
+ * It must be readable and writable by anybody on the system. */
+ umask(0111);
+
+ set_nonblocking(nctx->lfd);
+ set_close_on_exec(nctx->lfd);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, nctx->sock_name, sizeof(addr.sun_path));
+
+ /* make sure we have no old sockets around */
+ unlink(nctx->sock_name);
+
+ if (bind(nctx->lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ DEBUG(0,("Unable to bind on socket '%s'\n", nctx->sock_name));
+ goto failed;
+ }
+ if (listen(nctx->lfd, 10) != 0) {
+ DEBUG(0,("Unable to listen on socket '%s'\n", nctx->sock_name));
+ goto failed;
+ }
+
+ nctx->lfde = event_add_fd(nctx->ev, nctx, nctx->lfd,
+ EVENT_FD_READ, accept_fd_handler, nctx);
+
+ /* we want default permissions on created files to be very strict,
+ so set our umask to 0177 */
+ umask(0177);
+ return EOK;
+
+failed:
+ /* we want default permissions on created files to be very strict,
+ so set our umask to 0177 */
+ umask(0177);
+ close(nctx->lfd);
+ return EIO;
+}
+
+/* domain names are case insensitive for now
+ * NOTE: this function is not utf-8 safe,
+ * only ASCII names for now */
+static int _domain_comparator(const void *key1, const void *key2)
+{
+ return strcasecmp((const char *)key1, (const char *)key2);
+}
+
+static int sss_init_domains(struct nss_ctx *nctx)
+{
+ char *path;
+ char **domains;
+ char *provider;
+ TALLOC_CTX *tmp_ctx;
+ struct nss_domain_info *info;
+ int ret, i, c;
+ int retval;
+
+ tmp_ctx = talloc_new(nctx);
+ ret = confdb_get_domains(nctx->cdb, tmp_ctx, &domains);
+ if (ret != EOK) {
+ retval = ret;
+ goto done;
+ }
+
+ i = 0;
+ c = 0;
+ while (domains[i] != NULL) {
+ DEBUG(3, ("Adding domain %s to the map\n", domains[i]));
+
+ path = talloc_asprintf(tmp_ctx, "config/domains/%s", domains[i]);
+ if (!path) {
+ retval = ENOMEM;
+ goto done;
+ }
+
+ /* alloc on tmp_ctx, it will be stolen by btreemap_set_value */
+ info = talloc_zero(tmp_ctx, struct nss_domain_info);
+ if (!info) {
+ retval = ENOMEM;
+ goto done;
+ }
+
+ /* Build the basedn for this domain */
+ info->basedn = talloc_asprintf(info, SYSDB_DOM_BASE, domains[i]);
+ DEBUG(3, ("BaseDN: %s\n", info->basedn));
+
+ ret = confdb_get_int(nctx->cdb, tmp_ctx, path,
+ "enumerate", false, &(info->enumerate));
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to fetch enumerate for [%s]!\n", domains[i]));
+ }
+
+ ret = confdb_get_bool(nctx->cdb, tmp_ctx, path,
+ "legacy", false, &(info->legacy));
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to fetch legacy for [%s]!\n", domains[i]));
+ }
+
+ ret = confdb_get_string(nctx->cdb, tmp_ctx, path, "provider",
+ NULL, &provider);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to fetch provider for [%s]!\n", domains[i]));
+ }
+ if (provider) info->has_provider = true;
+
+ ret = btreemap_set_value(nctx, &nctx->domain_map,
+ domains[i], info,
+ _domain_comparator);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to store domain info, aborting!\n"));
+ retval = ret;
+ goto done;
+ }
+
+ i++;
+ c++;
+ }
+ if (c == 0) {
+ /* No domains configured!
+ * Note: this should never happen, since LOCAL should
+ * always be configured */
+ DEBUG(0, ("No domains configured on this client!\n"));
+ retval = EINVAL;
+ goto done;
+ }
+
+ ret = confdb_get_string(nctx->cdb, nctx,
+ "config/domains", "default",
+ NULL, &nctx->default_domain);
+ if (ret != EOK) {
+ retval = ret;
+ goto done;
+ }
+
+ retval = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return retval;
+}
+
+int sss_process_init(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct confdb_ctx *cdb,
+ struct sbus_method sss_sbus_methods[],
+ struct sss_cmd_table sss_cmds[],
+ const char *sss_pipe_name,
+ const char *confdb_socket_path,
+ struct sbus_method dp_methods[])
+{
+ struct nss_ctx *nctx;
+ int ret;
+
+ nctx = talloc_zero(mem_ctx, struct nss_ctx);
+ if (!nctx) {
+ DEBUG(0, ("fatal error initializing nss_ctx\n"));
+ return ENOMEM;
+ }
+ nctx->ev = ev;
+ nctx->cdb = cdb;
+ nctx->sss_sbus_methods = sss_sbus_methods;
+ nctx->sss_cmds = sss_cmds;
+ nctx->sss_pipe_name = sss_pipe_name;
+ nctx->confdb_socket_path = confdb_socket_path;
+ nctx->dp_methods = dp_methods;
+
+ ret = sss_init_domains(nctx);
+ if (ret != EOK) {
+ DEBUG(0, ("fatal error setting up domain map\n"));
+ return ret;
+ }
+
+ ret = sss_sbus_init(nctx);
+ if (ret != EOK) {
+ DEBUG(0, ("fatal error setting up message bus\n"));
+ return ret;
+ }
+
+ ret = sss_dp_init(nctx, nctx->dp_methods);
+ if (ret != EOK) {
+ DEBUG(0, ("fatal error setting up backend connector\n"));
+ return ret;
+ }
+
+ ret = sysdb_init(nctx, ev, cdb, NULL, &nctx->sysdb);
+ if (ret != EOK) {
+ DEBUG(0, ("fatal error initializing nss_ctx\n"));
+ return ret;
+ }
+
+ /* after all initializations we are ready to listen on our socket */
+ ret = set_unix_socket(nctx);
+ if (ret != EOK) {
+ DEBUG(0, ("fatal error initializing socket\n"));
+ return ret;
+ }
+
+ nctx->cache_timeout = 600; /* FIXME: read from conf */
+
+ DEBUG(1, ("NSS Initialization complete\n"));
+
+ return EOK;
+}
+
+int sss_parse_name(TALLOC_CTX *memctx,
+ const char *fullname,
+ struct btreemap *domain_map,
+ const char **domain, const char **name) {
+ char *delim;
+ struct btreemap *node;
+ int ret;
+
+ if ((delim = strchr(fullname, NSS_DOMAIN_DELIM)) != NULL) {
+
+ /* Check for registered domain */
+ ret = btreemap_search_key(domain_map, (void *)(delim+1), &node);
+ if (ret != BTREEMAP_FOUND) {
+ /* No such domain was registered. Return EINVAL.
+ * TODO: alternative approach?
+ * Alternatively, we could simply fail down to
+ * below, treating the entire construct as the
+ * full name if the domain is unspecified.
+ */
+ return EINVAL;
+ }
+
+ *name = talloc_strndup(memctx, fullname, delim-fullname);
+ *domain = talloc_strdup(memctx, delim+1);
+ }
+ else {
+ *name = talloc_strdup(memctx, fullname);
+ *domain = NULL;
+ }
+
+ return EOK;
+}
diff --git a/server/responder/common/responder_common.h b/server/responder/common/responder_common.h
new file mode 100644
index 00000000..433b242e
--- /dev/null
+++ b/server/responder/common/responder_common.h
@@ -0,0 +1,24 @@
+#include "sbus/sssd_dbus.h"
+#include "responder/common/responder_cmd.h"
+#include "util/btreemap.h"
+
+/* SSS_DOMAIN_DELIM can be specified in config.h */
+#include "config.h"
+#ifndef SSS_DOMAIN_DELIM
+#define SSS_DOMAIN_DELIM '@'
+#endif
+
+
+int sss_process_init(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct confdb_ctx *cdb,
+ struct sbus_method sss_sbus_methods[],
+ struct sss_cmd_table sss_cmds[],
+ const char *sss_pipe_name,
+ const char *confdb_socket_path,
+ struct sbus_method dp_methods[]);
+
+int sss_parse_name(TALLOC_CTX *memctx,
+ const char *fullname,
+ struct btreemap *domain_map,
+ const char **domain, const char **name);
diff --git a/server/responder/common/responder_dp.c b/server/responder/common/responder_dp.c
new file mode 100644
index 00000000..a024674b
--- /dev/null
+++ b/server/responder/common/responder_dp.c
@@ -0,0 +1,123 @@
+
+#include <sys/time.h>
+#include <time.h>
+#include "responder/nss/nsssrv.h"
+#include "util/util.h"
+#include "responder/common/responder_packet.h"
+#include "responder/common/responder_common.h"
+#include "providers/data_provider.h"
+#include "sbus/sbus_client.h"
+#include "providers/dp_sbus.h"
+
+struct sss_dp_pvt_ctx {
+ struct nss_ctx *nctx;
+ struct sbus_method *methods;
+ time_t last_retry;
+ int retries;
+};
+
+static int sss_dp_conn_destructor(void *data);
+static void sss_dp_reconnect(struct event_context *ev,
+ struct timed_event *te,
+ struct timeval tv, void *data);
+
+static void sss_dp_conn_reconnect(struct sss_dp_pvt_ctx *pvt)
+{
+ struct nss_ctx *nctx;
+ struct timed_event *te;
+ struct timeval tv;
+ struct sbus_method_ctx *sm_ctx;
+ char *sbus_address;
+ time_t now;
+ int ret;
+
+ now = time(NULL);
+
+ /* reset retry if last reconnect was > 60 sec. ago */
+ if (pvt->last_retry + 60 < now) pvt->retries = 0;
+ if (pvt->retries >= 3) {
+ DEBUG(4, ("Too many reconnect retries! Giving up\n"));
+ return;
+ }
+
+ pvt->last_retry = now;
+ pvt->retries++;
+
+ nctx = pvt->nctx;
+
+ ret = dp_get_sbus_address(nctx, nctx->cdb, &sbus_address);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not locate data provider address.\n"));
+ return;
+ }
+
+ ret = dp_init_sbus_methods(nctx, pvt->methods, &sm_ctx);
+ if (ret != EOK) {
+ DEBUG(0, ("Could not initialize SBUS methods.\n"));
+ return;
+ }
+
+ ret = sbus_client_init(nctx, nctx->ev,
+ sbus_address, sm_ctx,
+ pvt, sss_dp_conn_destructor,
+ &nctx->dp_ctx);
+ if (ret != EOK) {
+ DEBUG(4, ("Failed to reconnect [%d(%s)]!\n", ret, strerror(ret)));
+
+ tv.tv_sec = now +5;
+ tv.tv_usec = 0;
+ te = event_add_timed(nctx->ev, nctx, tv, sss_dp_reconnect, pvt);
+ if (te == NULL) {
+ DEBUG(4, ("Failed to add timed event! Giving up\n"));
+ } else {
+ DEBUG(4, ("Retrying in 5 seconds\n"));
+ }
+ }
+}
+
+static void sss_dp_reconnect(struct event_context *ev,
+ struct timed_event *te,
+ struct timeval tv, void *data)
+{
+ struct sss_dp_pvt_ctx *pvt;
+
+ pvt = talloc_get_type(data, struct sss_dp_pvt_ctx);
+
+ sss_dp_conn_reconnect(pvt);
+}
+
+int sss_dp_conn_destructor(void *data)
+{
+ struct sss_dp_pvt_ctx *pvt;
+ struct sbus_conn_ctx *scon;
+
+ scon = talloc_get_type(data, struct sbus_conn_ctx);
+ if (!scon) return 0;
+
+ /* if this is a regular disconnect just quit */
+ if (sbus_conn_disconnecting(scon)) return 0;
+
+ pvt = talloc_get_type(sbus_conn_get_private_data(scon),
+ struct sss_dp_pvt_ctx);
+ if (pvt) return 0;
+
+ sss_dp_conn_reconnect(pvt);
+
+ return 0;
+}
+
+int sss_dp_init(struct nss_ctx *nctx, struct sbus_method *dp_methods)
+{
+ struct sss_dp_pvt_ctx *pvt;
+
+ pvt = talloc_zero(nctx, struct sss_dp_pvt_ctx);
+ if (!pvt) return ENOMEM;
+
+ pvt->nctx = nctx;
+ pvt->methods = dp_methods;
+
+ sss_dp_conn_reconnect(pvt);
+
+ return EOK;
+}
+
diff --git a/server/responder/common/responder_dp.h b/server/responder/common/responder_dp.h
new file mode 100644
index 00000000..2eeddf5b
--- /dev/null
+++ b/server/responder/common/responder_dp.h
@@ -0,0 +1,4 @@
+#include "responder/nss/nsssrv.h"
+#include "sbus/sssd_dbus.h"
+
+int sss_dp_init(struct nss_ctx *nctx, struct sbus_method dp_methods[]);
diff --git a/server/nss/nsssrv_packet.c b/server/responder/common/responder_packet.c
index f79087d4..24762934 100644
--- a/server/nss/nsssrv_packet.c
+++ b/server/responder/common/responder_packet.c
@@ -1,7 +1,7 @@
/*
SSSD
- NSS Responder, command parser
+ SSS Client Responder, command parser
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
@@ -25,11 +25,11 @@
#include <errno.h>
#include "talloc.h"
#include "util/util.h"
-#include "nss/nsssrv.h"
+#include "responder/common/responder_packet.h"
-#define NSSSRV_PACKET_MEM_SIZE 512
+#define SSSSRV_PACKET_MEM_SIZE 512
-struct nss_packet {
+struct sss_packet {
size_t memsize;
uint8_t *buffer;
@@ -49,22 +49,22 @@ struct nss_packet {
* Allocate a new packet structure
*
* - if size is defined use it otherwise the default packet will be
- * NSSSRV_PACKET_MEM_SIZE bytes.
+ * SSSSRV_PACKET_MEM_SIZE bytes.
*/
-int nss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
- enum sss_nss_command cmd,
- struct nss_packet **rpacket)
+int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
+ enum sss_cli_command cmd,
+ struct sss_packet **rpacket)
{
- struct nss_packet *packet;
+ struct sss_packet *packet;
- packet = talloc(mem_ctx, struct nss_packet);
+ packet = talloc(mem_ctx, struct sss_packet);
if (!packet) return ENOMEM;
if (size) {
- int n = (size + SSS_NSS_HEADER_SIZE) % NSSSRV_PACKET_MEM_SIZE;
- packet->memsize = (n + 1) * NSSSRV_PACKET_MEM_SIZE;
+ int n = (size + SSS_NSS_HEADER_SIZE) % SSSSRV_PACKET_MEM_SIZE;
+ packet->memsize = (n + 1) * SSSSRV_PACKET_MEM_SIZE;
} else {
- packet->memsize = NSSSRV_PACKET_MEM_SIZE;
+ packet->memsize = SSSSRV_PACKET_MEM_SIZE;
}
packet->buffer = talloc_size(packet, packet->memsize);
@@ -90,8 +90,8 @@ int nss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
return EOK;
}
-/* grows a packet size only in NSSSRV_PACKET_MEM_SIZE chunks */
-int nss_packet_grow(struct nss_packet *packet, size_t size)
+/* grows a packet size only in SSSSRV_PACKET_MEM_SIZE chunks */
+int sss_packet_grow(struct sss_packet *packet, size_t size)
{
size_t totlen, len;
uint8_t *newmem;
@@ -105,8 +105,8 @@ int nss_packet_grow(struct nss_packet *packet, size_t size)
/* make sure we do not overflow */
if (totlen < len) {
- int n = len % NSSSRV_PACKET_MEM_SIZE + 1;
- totlen += n * NSSSRV_PACKET_MEM_SIZE;
+ int n = len % SSSSRV_PACKET_MEM_SIZE + 1;
+ totlen += n * SSSSRV_PACKET_MEM_SIZE;
if (totlen < len) {
return EINVAL;
}
@@ -132,7 +132,7 @@ int nss_packet_grow(struct nss_packet *packet, size_t size)
return 0;
}
-int nss_packet_recv(struct nss_packet *packet, int fd)
+int sss_packet_recv(struct sss_packet *packet, int fd)
{
size_t rb;
size_t len;
@@ -174,7 +174,7 @@ int nss_packet_recv(struct nss_packet *packet, int fd)
return EOK;
}
-int nss_packet_send(struct nss_packet *packet, int fd)
+int sss_packet_send(struct sss_packet *packet, int fd)
{
size_t rb;
size_t len;
@@ -203,18 +203,18 @@ int nss_packet_send(struct nss_packet *packet, int fd)
return EOK;
}
-enum sss_nss_command nss_packet_get_cmd(struct nss_packet *packet)
+enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet)
{
- return (enum sss_nss_command)(*packet->cmd);
+ return (enum sss_cli_command)(*packet->cmd);
}
-void nss_packet_get_body(struct nss_packet *packet, uint8_t **body, size_t *blen)
+void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen)
{
*body = packet->body;
*blen = *packet->len - SSS_NSS_HEADER_SIZE;
}
-void nss_packet_set_error(struct nss_packet *packet, int error)
+void sss_packet_set_error(struct sss_packet *packet, int error)
{
*(packet->status) = error;
}
diff --git a/server/responder/common/responder_packet.h b/server/responder/common/responder_packet.h
new file mode 100644
index 00000000..1a852946
--- /dev/null
+++ b/server/responder/common/responder_packet.h
@@ -0,0 +1,39 @@
+/*
+ SSSD
+
+ SSS Client Responder, header file
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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 __SSSSRV_PACKET_H__
+#define __SSSSRV_PACKET_H__
+
+#include "../sss_client/sss_cli.h"
+
+struct sss_packet;
+
+int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
+ enum sss_cli_command cmd,
+ struct sss_packet **rpacket);
+int sss_packet_grow(struct sss_packet *packet, size_t size);
+int sss_packet_recv(struct sss_packet *packet, int fd);
+int sss_packet_send(struct sss_packet *packet, int fd);
+enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet);
+void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen);
+void sss_packet_set_error(struct sss_packet *packet, int error);
+
+#endif /* __SSSSRV_PACKET_H__ */
diff --git a/server/nss/nsssrv.c b/server/responder/nss/nsssrv.c
index c48aed4a..93490c46 100644
--- a/server/nss/nsssrv.c
+++ b/server/responder/nss/nsssrv.c
@@ -31,12 +31,13 @@
#include <errno.h>
#include "popt.h"
#include "util/util.h"
-#include "nss/nsssrv.h"
+#include "responder/nss/nsssrv.h"
#include "db/sysdb.h"
#include "confdb/confdb.h"
#include "dbus/dbus.h"
#include "sbus/sssd_dbus.h"
#include "util/btreemap.h"
+#include "responder/common/responder_packet.h"
#include "providers/data_provider.h"
#include "monitor/monitor_sbus.h"
#include "monitor/monitor_interfaces.h"
@@ -81,7 +82,7 @@ static void client_send(struct event_context *ev, struct cli_ctx *cctx)
{
int ret;
- ret = nss_packet_send(cctx->creq->out, cctx->cfd);
+ ret = sss_packet_send(cctx->creq->out, cctx->cfd);
if (ret == EAGAIN) {
/* not all data was sent, loop again */
return;
@@ -114,7 +115,7 @@ static void client_recv(struct event_context *ev, struct cli_ctx *cctx)
}
if (!cctx->creq->in) {
- ret = nss_packet_new(cctx->creq, NSS_PACKET_MAX_RECV_SIZE,
+ ret = sss_packet_new(cctx->creq, NSS_PACKET_MAX_RECV_SIZE,
0, &cctx->creq->in);
if (ret != EOK) {
DEBUG(0, ("Failed to alloc request, aborting client!\n"));
@@ -123,7 +124,7 @@ static void client_recv(struct event_context *ev, struct cli_ctx *cctx)
}
}
- ret = nss_packet_recv(cctx->creq->in, cctx->cfd);
+ ret = sss_packet_recv(cctx->creq->in, cctx->cfd);
switch (ret) {
case EOK:
/* do not read anymore */
diff --git a/server/nss/nsssrv.h b/server/responder/nss/nsssrv.h
index 2352a505..03dc35af 100644
--- a/server/nss/nsssrv.h
+++ b/server/responder/nss/nsssrv.h
@@ -27,8 +27,10 @@
#include "talloc.h"
#include "tevent.h"
#include "ldb.h"
-#include "../nss_client/sss_nss.h"
+#include "../sss_client/sss_cli.h"
#include "dbus/dbus.h"
+#include "sbus/sssd_dbus.h"
+#include "responder/common/responder_cmd.h"
#define NSS_SBUS_SERVICE_VERSION 0x0001
#define NSS_SBUS_SERVICE_NAME "nss"
@@ -61,6 +63,12 @@ struct nss_ctx {
char *default_domain;
int cache_timeout;
+
+ struct sbus_method *sss_sbus_methods;
+ struct sss_cmd_table *sss_cmds;
+ const char *sss_pipe_name;
+ const char *confdb_socket_path;
+ struct sbus_method *dp_methods;
};
struct cli_ctx {
@@ -85,24 +93,12 @@ struct nss_packet;
struct cli_request {
/* original request from the wire */
- struct nss_packet *in;
+ struct sss_packet *in;
/* reply data */
- struct nss_packet *out;
+ struct sss_packet *out;
};
-/* from nsssrv_packet.c */
-int nss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
- enum sss_nss_command cmd,
- struct nss_packet **rpacket);
-int nss_packet_grow(struct nss_packet *packet, size_t size);
-int nss_packet_recv(struct nss_packet *packet, int fd);
-int nss_packet_send(struct nss_packet *packet, int fd);
-enum sss_nss_command nss_packet_get_cmd(struct nss_packet *packet);
-void nss_packet_get_body(struct nss_packet *packet, uint8_t **body, size_t *blen);
-void nss_packet_set_error(struct nss_packet *packet, int error);
-
-/* from nsssrv_cmd.c */
int nss_cmd_execute(struct cli_ctx *cctx);
/* from nsssrv_dp.c */
diff --git a/server/nss/nsssrv_cmd.c b/server/responder/nss/nsssrv_cmd.c
index b16d27c2..338de0ea 100644
--- a/server/nss/nsssrv_cmd.c
+++ b/server/responder/nss/nsssrv_cmd.c
@@ -21,7 +21,8 @@
#include "util/util.h"
#include "util/btreemap.h"
-#include "nss/nsssrv.h"
+#include "responder/common/responder_packet.h"
+#include "responder/nss/nsssrv.h"
#include "db/sysdb.h"
#include <time.h>
@@ -50,7 +51,7 @@ struct nss_dom_ctx {
};
struct nss_cmd_table {
- enum sss_nss_command cmd;
+ enum sss_cli_command cmd;
int (*fn)(struct cli_ctx *cctx);
};
@@ -70,14 +71,14 @@ static int nss_cmd_send_error(struct nss_cmd_ctx *cmdctx, int err)
int ret;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
- nss_packet_set_error(cctx->creq->out, err);
+ sss_packet_set_error(cctx->creq->out, err);
return EOK;
}
@@ -146,14 +147,14 @@ static int nss_cmd_get_version(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* create response packet */
- ret = nss_packet_new(cctx->creq, sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
- ((uint32_t *)body)[0] = SSS_NSS_VERSION;
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
+ ((uint32_t *)body)[0] = SSS_PROTOCOL_VERSION;
nss_cmd_done(cmdctx);
return EOK;
@@ -163,7 +164,7 @@ static int nss_cmd_get_version(struct cli_ctx *cctx)
* PASSWD db related functions
***************************************************************************/
-static int fill_pwent(struct nss_packet *packet,
+static int fill_pwent(struct sss_packet *packet,
struct ldb_message **msgs,
int count)
{
@@ -180,7 +181,7 @@ static int fill_pwent(struct nss_packet *packet,
int i, ret, num;
/* first 2 fields (len and reserved), filled up later */
- ret = nss_packet_grow(packet, 2*sizeof(uint32_t));
+ ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
rp = 2*sizeof(uint32_t);
num = 0;
@@ -206,12 +207,12 @@ static int fill_pwent(struct nss_packet *packet,
s4 = strlen(shell) + 1;
rsize = 2*sizeof(uint64_t) +s1 + 2 + s2 + s3 +s4;
- ret = nss_packet_grow(packet, rsize);
+ ret = sss_packet_grow(packet, rsize);
if (ret != EOK) {
num = 0;
goto done;
}
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint64_t *)(&body[rp]))[0] = uid;
((uint64_t *)(&body[rp]))[1] = gid;
@@ -231,7 +232,7 @@ static int fill_pwent(struct nss_packet *packet,
}
done:
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint32_t *)body)[0] = num; /* num results */
((uint32_t *)body)[1] = 0; /* reserved */
@@ -292,7 +293,7 @@ static void nss_cmd_getpwnam_callback(void *ptr, int status,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getpwnam_dp_callback, dctx,
@@ -315,28 +316,27 @@ static void nss_cmd_getpwnam_callback(void *ptr, int status,
DEBUG(2, ("No results for getpwnam call\n"));
- ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
((uint32_t *)body)[0] = 0; /* 0 results */
((uint32_t *)body)[1] = 0; /* reserved */
break;
case 1:
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
-
ret = fill_pwent(cctx->creq->out, res->msgs, res->count);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
break;
@@ -401,7 +401,7 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx)
dctx->cmdctx = cmdctx;
/* get user name to query */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
/* if not terminated fail */
if (body[blen -1] != '\0') {
talloc_free(cmdctx);
@@ -503,7 +503,7 @@ static void nss_cmd_getpwuid_callback(void *ptr, int status,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getpwuid_dp_callback, dctx,
@@ -530,28 +530,28 @@ static void nss_cmd_getpwuid_callback(void *ptr, int status,
DEBUG(2, ("No results for getpwuid call\n"));
- ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
((uint32_t *)body)[0] = 0; /* 0 results */
((uint32_t *)body)[1] = 0; /* reserved */
break;
case 1:
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
ret = fill_pwent(cctx->creq->out, res->msgs, res->count);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
break;
@@ -622,7 +622,7 @@ static int nss_cmd_getpwuid(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* get uid to query */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint64_t)) {
return EINVAL;
@@ -708,13 +708,13 @@ static void nss_cmd_setpwent_callback(void *ptr, int status,
if (status != LDB_SUCCESS) {
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_set_error(cctx->creq->out, status);
+ sss_packet_set_error(cctx->creq->out, status);
cmdctx->done = true;
return;
}
@@ -747,8 +747,8 @@ static void nss_cmd_setpwent_callback(void *ptr, int status,
}
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
@@ -848,7 +848,7 @@ static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate)
dctx->legacy = info->legacy;
if (dctx->check_provider) {
- timeout = SSS_NSS_SOCKET_TIMEOUT/(i+2);
+ timeout = SSS_CLI_SOCKET_TIMEOUT/(i+2);
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_setpw_dp_callback, dctx,
timeout, domains[i], NSS_DP_USER,
@@ -871,14 +871,14 @@ static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate)
if (cmdctx->nr == 0) {
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
nss_cmd_done(cmdctx);
return EOK;
}
@@ -921,29 +921,29 @@ static void nss_cmd_getpwent_callback(void *ptr, int status,
int ret;
/* get max num of entries to return in one call */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint32_t)) {
NSS_CMD_FATAL_ERROR(cctx);
}
num = *((uint32_t *)body);
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
if (status != LDB_SUCCESS) {
- nss_packet_set_error(cctx->creq->out, status);
+ sss_packet_set_error(cctx->creq->out, status);
goto done;
}
gctx->pwds = talloc_steal(gctx, res);
ret = nss_cmd_retpwent(cctx, num);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
done:
nss_cmd_done(cmdctx);
@@ -961,7 +961,7 @@ static int nss_cmd_getpwent(struct cli_ctx *cctx)
DEBUG(4, ("Requesting info for all accounts\n"));
/* get max num of entries to return in one call */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint32_t)) {
return EINVAL;
}
@@ -989,15 +989,15 @@ static int nss_cmd_getpwent(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
ret = nss_cmd_retpwent(cctx, num);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
nss_cmd_done(cmdctx);
return EOK;
}
@@ -1016,8 +1016,8 @@ static int nss_cmd_endpwent(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (cctx->gctx == NULL) goto done;
@@ -1037,7 +1037,7 @@ done:
* GROUP db related functions
***************************************************************************/
-static int fill_grent(struct nss_packet *packet,
+static int fill_grent(struct sss_packet *packet,
struct ldb_message **msgs,
int count)
{
@@ -1052,7 +1052,7 @@ static int fill_grent(struct nss_packet *packet,
bool memnum_set = false;
/* first 2 fields (len and reserved), filled up later */
- ret = nss_packet_grow(packet, 2*sizeof(uint32_t));
+ ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
rp = 2*sizeof(uint32_t);
num = 0;
@@ -1073,8 +1073,8 @@ static int fill_grent(struct nss_packet *packet,
/* fill in gid and name and set pointer for number of members */
rsize = sizeof(uint64_t) + sizeof(uint32_t) + strlen(name)+1 +2;
- ret = nss_packet_grow(packet, rsize);
- nss_packet_get_body(packet, &body, &blen);
+ ret = sss_packet_grow(packet, rsize);
+ sss_packet_get_body(packet, &body, &blen);
rp = blen - rsize;
((uint64_t *)(&body[rp]))[0] = gid;
rp += sizeof(uint64_t);
@@ -1097,19 +1097,19 @@ static int fill_grent(struct nss_packet *packet,
for (j = 0; j < memnum; j++) {
rsize = el->values[j].length + 1;
- ret = nss_packet_grow(packet, rsize);
+ ret = sss_packet_grow(packet, rsize);
if (ret != EOK) {
num = 0;
goto done;
}
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
rp = blen - rsize;
memcpy(&body[rp], el->values[j].data, el->values[j].length);
body[blen-1] = '\0';
}
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */
memnum_set = true;
@@ -1128,7 +1128,7 @@ static int fill_grent(struct nss_packet *packet,
* fail there if here start bogus entries */
get_group = true;
i--;
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */
memnum_set = true;
continue;
@@ -1136,12 +1136,12 @@ static int fill_grent(struct nss_packet *packet,
rsize = strlen(name) + 1;
- ret = nss_packet_grow(packet, rsize);
+ ret = sss_packet_grow(packet, rsize);
if (ret != EOK) {
num = 0;
goto done;
}
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
rp = blen - rsize;
memcpy(&body[rp], name, rsize);
@@ -1151,13 +1151,13 @@ static int fill_grent(struct nss_packet *packet,
if (!memnum_set) {
/* fill in the last group member count */
if (mnump != 0) {
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */
}
}
done:
- nss_packet_get_body(packet, &body, &blen);
+ sss_packet_get_body(packet, &body, &blen);
((uint32_t *)body)[0] = num; /* num results */
((uint32_t *)body)[1] = 0; /* reserved */
@@ -1210,7 +1210,7 @@ static void nss_cmd_getgrnam_callback(void *ptr, int status,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getgrnam_dp_callback, dctx,
@@ -1234,13 +1234,13 @@ static void nss_cmd_getgrnam_callback(void *ptr, int status,
DEBUG(2, ("No results for getgrnam call\n"));
- ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
((uint32_t *)body)[0] = 0; /* 0 results */
((uint32_t *)body)[1] = 0; /* reserved */
break;
@@ -1250,15 +1250,15 @@ static void nss_cmd_getgrnam_callback(void *ptr, int status,
DEBUG(6, ("Returning info for group [%s]\n", cmdctx->name));
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
ret = fill_grent(cctx->creq->out, res->msgs, res->count);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
}
done:
@@ -1314,7 +1314,7 @@ static int nss_cmd_getgrnam(struct cli_ctx *cctx)
dctx->cmdctx = cmdctx;
/* get user name to query */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
/* if not terminated fail */
if (body[blen -1] != '\0') {
talloc_free(cmdctx);
@@ -1407,7 +1407,7 @@ static void nss_cmd_getgrgid_callback(void *ptr, int status,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getgrgid_dp_callback, dctx,
@@ -1434,13 +1434,13 @@ static void nss_cmd_getgrgid_callback(void *ptr, int status,
DEBUG(2, ("No results for getgrgid call\n"));
- ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
((uint32_t *)body)[0] = 0; /* 0 results */
((uint32_t *)body)[1] = 0; /* reserved */
break;
@@ -1450,15 +1450,15 @@ static void nss_cmd_getgrgid_callback(void *ptr, int status,
DEBUG(6, ("Returning info for group [%u]\n", (unsigned)cmdctx->id));
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
ret = fill_grent(cctx->creq->out, res->msgs, res->count);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
}
done:
@@ -1516,7 +1516,7 @@ static int nss_cmd_getgrgid(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* get uid to query */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint64_t)) {
return EINVAL;
@@ -1601,13 +1601,13 @@ static void nss_cmd_setgrent_callback(void *ptr, int status,
if (status != LDB_SUCCESS) {
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_set_error(cctx->creq->out, status);
+ sss_packet_set_error(cctx->creq->out, status);
cmdctx->done = true;
return;
}
@@ -1639,8 +1639,8 @@ static void nss_cmd_setgrent_callback(void *ptr, int status,
}
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
@@ -1740,7 +1740,7 @@ static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate)
dctx->legacy = info->legacy;
if (dctx->check_provider) {
- timeout = SSS_NSS_SOCKET_TIMEOUT/(i+2);
+ timeout = SSS_CLI_SOCKET_TIMEOUT/(i+2);
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_setgr_dp_callback, dctx,
timeout, domains[i], NSS_DP_GROUP,
@@ -1762,14 +1762,14 @@ static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate)
if (cmdctx->nr == 0) {
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
nss_cmd_done(cmdctx);
return EOK;
}
@@ -1811,7 +1811,7 @@ static void nss_cmd_getgrent_callback(void *ptr, int status,
int ret;
/* get max num of entries to return in one call */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint32_t)) {
ret = nss_cmd_send_error(cmdctx, EIO);
if (ret != EOK) {
@@ -1822,22 +1822,22 @@ static void nss_cmd_getgrent_callback(void *ptr, int status,
num = *((uint32_t *)body);
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
if (status != LDB_SUCCESS) {
- nss_packet_set_error(cctx->creq->out, status);
+ sss_packet_set_error(cctx->creq->out, status);
goto done;
}
gctx->grps = talloc_steal(gctx, res);
ret = nss_cmd_retgrent(cctx, num);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
done:
nss_cmd_done(cmdctx);
@@ -1855,7 +1855,7 @@ static int nss_cmd_getgrent(struct cli_ctx *cctx)
DEBUG(4, ("Requesting info for all groups\n"));
/* get max num of entries to return in one call */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
if (blen != sizeof(uint32_t)) {
return EINVAL;
}
@@ -1883,15 +1883,15 @@ static int nss_cmd_getgrent(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
return ret;
}
ret = nss_cmd_retgrent(cctx, num);
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
nss_cmd_done(cmdctx);
return EOK;
}
@@ -1910,8 +1910,8 @@ static int nss_cmd_endgrent(struct cli_ctx *cctx)
cmdctx->cctx = cctx;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (cctx->gctx == NULL) goto done;
@@ -1939,33 +1939,33 @@ static void nss_cmd_initgr_callback(void *ptr, int status,
int ret, i;
/* create response packet */
- ret = nss_packet_new(cctx->creq, 0,
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 0,
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
if (status != LDB_SUCCESS) {
- nss_packet_set_error(cctx->creq->out, status);
+ sss_packet_set_error(cctx->creq->out, status);
goto done;
}
num = res->count;
/* the first 64 bit uint is really 2 32 units used to hold the number of
* results */
- ret = nss_packet_grow(cctx->creq->out, (1 + num) * sizeof(uint64_t));
+ ret = sss_packet_grow(cctx->creq->out, (1 + num) * sizeof(uint64_t));
if (ret != EOK) {
- nss_packet_set_error(cctx->creq->out, ret);
+ sss_packet_set_error(cctx->creq->out, ret);
goto done;
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
for (i = 0; i < num; i++) {
gid = ldb_msg_find_attr_as_uint64(res->msgs[i], SYSDB_GR_GIDNUM, 0);
if (!gid) {
DEBUG(1, ("Incomplete group object for initgroups! Aborting\n"));
- nss_packet_set_error(cctx->creq->out, EIO);
+ sss_packet_set_error(cctx->creq->out, EIO);
num = 0;
goto done;
}
@@ -2084,7 +2084,7 @@ static void nss_cmd_getinit_callback(void *ptr, int status,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getinitnam_callback, dctx,
@@ -2108,20 +2108,20 @@ static void nss_cmd_getinit_callback(void *ptr, int status,
DEBUG(2, ("No results for initgroups call\n"));
- ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t),
- nss_packet_get_cmd(cctx->creq->in),
+ ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
+ sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
NSS_CMD_FATAL_ERROR(cctx);
}
- nss_packet_get_body(cctx->creq->out, &body, &blen);
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
((uint32_t *)body)[0] = 0; /* 0 results */
((uint32_t *)body)[1] = 0; /* reserved */
break;
case 1:
- timeout = SSS_NSS_SOCKET_TIMEOUT/2;
+ timeout = SSS_CLI_SOCKET_TIMEOUT/2;
ret = nss_dp_send_acct_req(cctx->nctx, cmdctx,
nss_cmd_getinitgr_callback, dctx,
timeout, dctx->domain, NSS_DP_INITGROUPS,
@@ -2170,7 +2170,7 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx)
dctx->cmdctx = cmdctx;
/* get user name to query */
- nss_packet_get_body(cctx->creq->in, &body, &blen);
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
cmdctx->name = (const char *)body;
/* if not terminated fail */
if (cmdctx->name[blen -1] != '\0') {
@@ -2203,8 +2203,9 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx)
return EOK;
}
+struct nss_cmd_table sss_cmds[] = {};
struct nss_cmd_table nss_cmds[] = {
- {SSS_NSS_GET_VERSION, nss_cmd_get_version},
+ {SSS_GET_VERSION, nss_cmd_get_version},
{SSS_NSS_GETPWNAM, nss_cmd_getpwnam},
{SSS_NSS_GETPWUID, nss_cmd_getpwuid},
{SSS_NSS_SETPWENT, nss_cmd_setpwent},
@@ -2216,17 +2217,17 @@ struct nss_cmd_table nss_cmds[] = {
{SSS_NSS_GETGRENT, nss_cmd_getgrent},
{SSS_NSS_ENDGRENT, nss_cmd_endgrent},
{SSS_NSS_INITGR, nss_cmd_initgroups},
- {SSS_NSS_NULL, NULL}
+ {SSS_CLI_NULL, NULL}
};
int nss_cmd_execute(struct cli_ctx *cctx)
{
- enum sss_nss_command cmd;
+ enum sss_cli_command cmd;
int i;
- cmd = nss_packet_get_cmd(cctx->creq->in);
+ cmd = sss_packet_get_cmd(cctx->creq->in);
- for (i = 0; nss_cmds[i].cmd != SSS_NSS_NULL; i++) {
+ for (i = 0; nss_cmds[i].cmd != SSS_CLI_NULL; i++) {
if (cmd == nss_cmds[i].cmd) {
return nss_cmds[i].fn(cctx);
}
diff --git a/server/nss/nsssrv_dp.c b/server/responder/nss/nsssrv_dp.c
index ec8aea8b..46e21801 100644
--- a/server/nss/nsssrv_dp.c
+++ b/server/responder/nss/nsssrv_dp.c
@@ -22,7 +22,8 @@
#include <sys/time.h>
#include <time.h>
#include "util/util.h"
-#include "nss/nsssrv.h"
+#include "responder/common/responder_packet.h"
+#include "responder/nss/nsssrv.h"
#include "providers/data_provider.h"
#include "sbus/sbus_client.h"
#include "providers/dp_sbus.h"
diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c
new file mode 100644
index 00000000..b6593bcf
--- /dev/null
+++ b/server/responder/pam/pamsrv.c
@@ -0,0 +1,171 @@
+/*
+ SSSD
+
+ PAM Responder
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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 "db/sysdb.h"
+#include "confdb/confdb.h"
+#include "dbus/dbus.h"
+#include "sbus/sssd_dbus.h"
+#include "util/btreemap.h"
+#include "responder/common/responder_packet.h"
+#include "responder/common/responder_cmd.h"
+#include "responder/common/responder_common.h"
+#include "providers/data_provider.h"
+#include "monitor/monitor_sbus.h"
+#include "monitor/monitor_interfaces.h"
+#include "sbus/sbus_client.h"
+#include "responder/pam/pamsrv.h"
+
+#define SSS_PAM_PIPE_NAME "pam"
+#define PAM_SBUS_SERVICE_VERSION 0x0001
+#define PAM_SBUS_SERVICE_NAME "pam"
+#define CONFDB_SOCKET_PATH "config/services/pam"
+
+static int service_identity(DBusMessage *message, struct sbus_conn_ctx *sconn);
+static int service_pong(DBusMessage *message, struct sbus_conn_ctx *sconn);
+static int service_reload(DBusMessage *message, struct sbus_conn_ctx *sconn);
+
+struct sbus_method sss_sbus_methods[] = {
+ {SERVICE_METHOD_IDENTITY, service_identity},
+ {SERVICE_METHOD_PING, service_pong},
+ {SERVICE_METHOD_RELOAD, service_reload},
+ {NULL, NULL}
+};
+
+static int service_identity(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+ dbus_uint16_t version = PAM_SBUS_SERVICE_VERSION;
+ const char *name = PAM_SBUS_SERVICE_NAME;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ DEBUG(4,("Sending ID reply: (%s,%d)\n", name, version));
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) return ENOMEM;
+
+ ret = dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT16, &version,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ dbus_message_unref(reply);
+ return EIO;
+ }
+
+ /* send reply back */
+ sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+
+ return EOK;
+}
+
+static int service_pong(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) return ENOMEM;
+
+ ret = dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+ if (!ret) {
+ return EIO;
+ }
+
+ /* send reply back */
+ sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+
+ return EOK;
+}
+
+static int service_reload(DBusMessage *message, struct sbus_conn_ctx *sconn) {
+ /* Monitor calls this function when we need to reload
+ * our configuration information. Perform whatever steps
+ * are needed to update the configuration objects.
+ */
+
+ /* Send an empty reply to acknowledge receipt */
+ return service_pong(message, sconn);
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ struct main_context *main_ctx;
+ int ret;
+ struct sbus_method *pam_dp_methods;
+ struct sss_cmd_table *sss_cmds;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ { NULL }
+ };
+
+ 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... */
+ ret = server_setup("sssd[pam]", 0, &main_ctx);
+ if (ret != EOK) return 2;
+
+ pam_dp_methods = register_pam_dp_methods();
+ sss_cmds = register_sss_cmds();
+ ret = sss_process_init(main_ctx,
+ main_ctx->event_ctx,
+ main_ctx->confdb_ctx,
+ sss_sbus_methods,
+ sss_cmds,
+ SSS_PAM_PIPE_NAME,
+ CONFDB_SOCKET_PATH,
+ pam_dp_methods);
+ if (ret != EOK) return 3;
+
+ /* loop on main */
+ server_loop(main_ctx);
+
+ return 0;
+}
+
diff --git a/server/responder/pam/pamsrv.h b/server/responder/pam/pamsrv.h
new file mode 100644
index 00000000..bb0082ac
--- /dev/null
+++ b/server/responder/pam/pamsrv.h
@@ -0,0 +1,33 @@
+#include "sbus/sssd_dbus.h"
+#include "responder/common/responder_cmd.h"
+
+#define PAM_DP_TIMEOUT 5000
+
+#define DEBUG_PAM_DATA(level, pd) do { \
+ if (level <= debug_level) pam_print_data(level, pd); \
+} while(0);
+
+struct pam_data {
+ int cmd;
+ uint32_t authtok_type;
+ uint32_t authtok_size;
+ uint32_t newauthtok_type;
+ uint32_t newauthtok_size;
+ char *domain;
+ char *user;
+ char *service;
+ char *tty;
+ char *ruser;
+ char *rhost;
+ uint8_t *authtok;
+ uint8_t *newauthtok;
+};
+
+void pam_print_data(int l, struct pam_data *pd);
+
+typedef void (*pam_dp_callback_t)(struct cli_ctx *cctx, int pam_status, char *domain);
+
+struct sbus_method *register_pam_dp_methods(void);
+struct sss_cmd_table *register_sss_cmds(void);
+int pam_dp_send_req(struct cli_ctx *cctx, pam_dp_callback_t callback,
+ int timeout, struct pam_data *pd);
diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c
new file mode 100644
index 00000000..4fdded30
--- /dev/null
+++ b/server/responder/pam/pamsrv_cmd.c
@@ -0,0 +1,196 @@
+#include <errno.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "responder/common/responder_common.h"
+#include "responder/common/responder_cmd.h"
+#include "responder/common/responder_packet.h"
+#include "responder/pam/pamsrv.h"
+
+static int pam_parse_in_data(uint8_t *body, size_t blen, struct pam_data *pd) {
+ int start;
+ int end;
+ int last=blen-1;
+ char *delim;
+
+ start = end = 0;
+ while ( end < last && body[end++]!='\0');
+ pd->user = (char *) &body[start];
+
+ delim = strchr(pd->user, SSS_DOMAIN_DELIM);
+ if (delim != NULL ) {
+ *delim = '\0';
+ pd->domain = delim+1;
+ } else {
+ pd->domain = NULL;
+ }
+
+ start = end;
+ while ( end < last && body[end++]!='\0');
+ pd->service = (char *) &body[start];
+
+ start = end;
+ while ( end < last && body[end++]!='\0');
+ pd->tty = (char *) &body[start];
+
+ start = end;
+ while ( end < last && body[end++]!='\0');
+ pd->ruser = (char *) &body[start];
+
+ start = end;
+ while ( end < last && body[end++]!='\0');
+ pd->rhost = (char *) &body[start];
+
+ start = end;
+ pd->authtok_type = (int) body[start];
+ start += sizeof(uint32_t);
+ pd->authtok_size = (int) body[start];
+ start += sizeof(uint32_t);
+ end = start+pd->authtok_size;
+ if ( pd->authtok_size == 0 ) {
+ pd->authtok = NULL;
+ } else {
+ if ( end <= blen ) {
+ pd->authtok = (uint8_t *) &body[start];
+ } else {
+ DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size));
+ return EINVAL;
+ }
+ }
+
+ start = end;
+ pd->newauthtok_type = (int) body[start];
+ start += sizeof(uint32_t);
+ pd->newauthtok_size = (int) body[start];
+ start += sizeof(uint32_t);
+ end = start+pd->newauthtok_size;
+ if ( pd->newauthtok_size == 0 ) {
+ pd->newauthtok = NULL;
+ } else {
+ if ( end <= blen ) {
+ pd->newauthtok = (uint8_t *) &body[start];
+ } else {
+ DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size));
+ return EINVAL;
+ }
+ }
+
+ DEBUG_PAM_DATA(4, pd);
+
+ return EOK;
+}
+
+static void pam_reply(struct cli_ctx *cctx, int pam_status, char *domain) {
+ struct sss_cmd_ctx *nctx;
+ int32_t ret_status = pam_status;
+ uint8_t *body;
+ size_t blen;
+ int ret;
+ int err = EOK;
+
+ DEBUG(4, ("pam_reply get called.\n"));
+ nctx = talloc_zero(cctx, struct sss_cmd_ctx);
+ if (!nctx) {
+ err = ENOMEM;
+ goto done;
+ }
+ nctx->cctx = cctx;
+ nctx->check_expiration = true;
+
+ ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
+ &cctx->creq->out);
+ if (ret != EOK) {
+ err = ret;
+ goto done;
+ }
+
+ ret = sss_packet_grow(cctx->creq->out, sizeof(int) + strlen(domain)+1 );
+ if (ret != EOK) {
+ err = ret;
+ goto done;
+ }
+
+ sss_packet_get_body(cctx->creq->out, &body, &blen);
+ DEBUG(4, ("blen: %d\n", blen));
+ memcpy(body, &ret_status, sizeof(int32_t));
+ memcpy(body+sizeof(int32_t), domain, strlen(domain)+1);
+
+done:
+ sss_cmd_done(nctx);
+}
+
+static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
+{
+ uint8_t *body;
+ size_t blen;
+ int ret;
+ struct pam_data *pd;
+
+ pd = talloc(cctx, struct pam_data);
+ if (pd == NULL) return ENOMEM;
+
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
+ if (blen >= sizeof(uint32_t) &&
+ ((uint32_t *)(&body[blen - sizeof(uint32_t)]))[0] != END_OF_PAM_REQUEST) {
+ DEBUG(1, ("Received data not terminated.\n"));
+ talloc_free(pd);
+ return EINVAL;
+ }
+
+ pd->cmd = pam_cmd;
+ ret=pam_parse_in_data(body, blen, pd);
+ if( ret != 0 ) {
+ talloc_free(pd);
+ return EINVAL;
+ }
+
+ ret=pam_dp_send_req(cctx, pam_reply, PAM_DP_TIMEOUT, pd);
+ DEBUG(4, ("pam_dp_send_req returned %d\n", ret));
+
+ return ret;
+}
+
+static int pam_cmd_authenticate(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_authenticate\n"));
+ return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
+}
+
+static int pam_cmd_setcred(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_setcred\n"));
+ return pam_forwarder(cctx, SSS_PAM_SETCRED);
+}
+
+static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_acct_mgmt\n"));
+ return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT);
+}
+
+static int pam_cmd_open_session(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_open_session\n"));
+ return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION);
+}
+
+static int pam_cmd_close_session(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_close_session\n"));
+ return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
+}
+
+static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
+ DEBUG(4, ("entering pam_cmd_chauthtok\n"));
+ return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
+}
+
+struct sss_cmd_table *register_sss_cmds(void) {
+ static struct sss_cmd_table sss_cmds[] = {
+ {SSS_GET_VERSION, sss_cmd_get_version},
+ {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate},
+ {SSS_PAM_SETCRED, pam_cmd_setcred},
+ {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt},
+ {SSS_PAM_OPEN_SESSION, pam_cmd_open_session},
+ {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session},
+ {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok},
+ {SSS_CLI_NULL, NULL}
+ };
+
+ return sss_cmds;
+}
diff --git a/server/responder/pam/pamsrv_dp.c b/server/responder/pam/pamsrv_dp.c
new file mode 100644
index 00000000..8a10c6bd
--- /dev/null
+++ b/server/responder/pam/pamsrv_dp.c
@@ -0,0 +1,215 @@
+/*
+ SSSD
+
+ NSS Responder - Data Provider Interfaces
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
+
+ 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 <sys/time.h>
+#include <time.h>
+
+#include <talloc.h>
+#include <security/pam_modules.h>
+
+#include "util/util.h"
+#include "responder/common/responder_packet.h"
+#include "responder/nss/nsssrv.h"
+#include "providers/data_provider.h"
+#include "sbus/sbus_client.h"
+#include "providers/dp_sbus.h"
+#include "responder/pam/pamsrv.h"
+
+struct pam_reply_ctx {
+ struct cli_ctx *cctx;
+ pam_dp_callback_t callback;
+};
+
+static void pam_process_dp_reply(DBusPendingCall *pending, void *ptr) {
+ DBusError dbus_error;
+ DBusMessage* msg;
+ int ret;
+ int type;
+ dbus_uint32_t pam_status;
+ char *domain;
+ struct pam_reply_ctx *rctx;
+
+ rctx = talloc_get_type(ptr, struct pam_reply_ctx);
+
+ dbus_error_init(&dbus_error);
+
+ dbus_pending_call_block(pending);
+ msg = dbus_pending_call_steal_reply(pending);
+ if (msg == NULL) {
+ DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+
+ type = dbus_message_get_type(msg);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ ret = dbus_message_get_args(msg, &dbus_error,
+ DBUS_TYPE_UINT32, &pam_status,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(0, ("Failed to parse reply.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ domain = "";
+ goto done;
+ }
+ DEBUG(4, ("received: [%d][%s]\n", pam_status, domain));
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ DEBUG(0, ("Reply error.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ break;
+ default:
+ DEBUG(0, ("Default... what now?.\n"));
+ pam_status = PAM_SYSTEM_ERR;
+ }
+
+
+done:
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(msg);
+ rctx->callback(rctx->cctx, pam_status, domain);
+}
+
+int pam_dp_send_req(struct cli_ctx *cctx,
+ pam_dp_callback_t callback,
+ int timeout, struct pam_data *pd) {
+ DBusMessage *msg;
+ DBusPendingCall *pending_reply;
+ DBusConnection *conn;
+ DBusError dbus_error;
+ dbus_bool_t ret;
+ struct pam_reply_ctx *rctx;
+
+ rctx = talloc(cctx, struct pam_reply_ctx);
+ if (rctx == NULL) {
+ DEBUG(0,("Out of memory?!\n"));
+ return ENOMEM;
+ }
+ rctx->cctx=cctx;
+ rctx->callback=callback;
+
+ if (pd->domain==NULL ||
+ pd->user==NULL ||
+ pd->service==NULL ||
+ pd->tty==NULL ||
+ pd->ruser==NULL ||
+ pd->rhost==NULL ) {
+ return EINVAL;
+ }
+
+ conn = sbus_get_connection(cctx->nctx->dp_ctx->scon_ctx);
+ dbus_error_init(&dbus_error);
+
+ msg = dbus_message_new_method_call(NULL,
+ DP_CLI_PATH,
+ DP_CLI_INTERFACE,
+ DP_SRV_METHOD_PAMHANDLER);
+ if (msg == NULL) {
+ DEBUG(0,("Out of memory?!\n"));
+ return ENOMEM;
+ }
+
+
+ DEBUG(4, ("Sending request with the following data:\n"));
+ DEBUG_PAM_DATA(4, pd);
+
+ ret = dbus_message_append_args(msg,
+ DBUS_TYPE_INT32, &(pd->cmd),
+ DBUS_TYPE_STRING, &(pd->domain),
+ DBUS_TYPE_STRING, &(pd->user),
+ DBUS_TYPE_STRING, &(pd->service),
+ DBUS_TYPE_STRING, &(pd->tty),
+ DBUS_TYPE_STRING, &(pd->ruser),
+ DBUS_TYPE_STRING, &(pd->rhost),
+ DBUS_TYPE_INT32, &(pd->authtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->authtok), pd->authtok_size,
+ DBUS_TYPE_INT32, &(pd->newauthtok_type),
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &(pd->newauthtok), pd->newauthtok_size,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to build message\n"));
+ return EIO;
+ }
+
+ ret = dbus_connection_send_with_reply(conn, msg, &pending_reply, timeout);
+ if (!ret) {
+ /*
+ * Critical Failure
+ * We can't communicate on this connection
+ * We'll drop it using the default destructor.
+ */
+ DEBUG(0, ("D-BUS send failed.\n"));
+ dbus_message_unref(msg);
+ return EIO;
+ }
+
+ dbus_pending_call_set_notify(pending_reply, pam_process_dp_reply, rctx,
+ NULL);
+ dbus_message_unref(msg);
+
+ return EOK;
+}
+
+static int pam_dp_identity(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+ dbus_uint16_t version = DATA_PROVIDER_VERSION;
+ dbus_uint16_t clitype = DP_CLI_FRONTEND;
+ const char *cliname = "PAM";
+ const char *nullname = "";
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ DEBUG(4,("Sending ID reply: (%d,%d,%s)\n", clitype, version, cliname));
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) return ENOMEM;
+
+ ret = dbus_message_append_args(reply,
+ DBUS_TYPE_UINT16, &clitype,
+ DBUS_TYPE_UINT16, &version,
+ DBUS_TYPE_STRING, &cliname,
+ DBUS_TYPE_STRING, &nullname,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ dbus_message_unref(reply);
+ return EIO;
+ }
+
+ /* send reply back */
+ sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+
+ return EOK;
+}
+
+struct sbus_method *register_pam_dp_methods(void) {
+ static struct sbus_method pam_dp_methods[] = {
+ { DP_CLI_METHOD_IDENTITY, pam_dp_identity },
+ { NULL, NULL }
+ };
+
+ return pam_dp_methods;
+}
diff --git a/server/responder/pam/pamsrv_util.c b/server/responder/pam/pamsrv_util.c
new file mode 100644
index 00000000..5dab9b67
--- /dev/null
+++ b/server/responder/pam/pamsrv_util.c
@@ -0,0 +1,16 @@
+#include "util/util.h"
+#include "responder/pam/pamsrv.h"
+
+void pam_print_data(int l, struct pam_data *pd) {
+ DEBUG(l, ("command: %d\n", pd->cmd));
+ DEBUG(l, ("domain: %s\n", pd->domain));
+ DEBUG(l, ("user: %s\n", pd->user));
+ DEBUG(l, ("service: %s\n", pd->service));
+ DEBUG(l, ("tty: %s\n", pd->tty));
+ DEBUG(l, ("ruser: %s\n", pd->ruser));
+ DEBUG(l, ("rhost: %s\n", pd->rhost));
+ DEBUG(l, ("authtok type: %d\n", pd->authtok_type));
+ DEBUG(l, ("authtok size: %d\n", pd->authtok_size));
+ DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type));
+ DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size));
+}
diff --git a/server/server.mk b/server/server.mk
index 744dc243..386f56f1 100644
--- a/server/server.mk
+++ b/server/server.mk
@@ -15,6 +15,12 @@ UTIL_OBJ = \
db/sysdb.o \
db/sysdb_sync.o
+RESPONDER_UTIL_OBJ = \
+ responder/common/responder_dp.o \
+ responder/common/responder_packet.o \
+ responder/common/responder_common.o \
+ responder/common/responder_cmd.o
+
SERVER_OBJ = \
monitor/monitor.o
@@ -27,11 +33,13 @@ DP_BE_OBJ = \
PROXY_BE_OBJ = \
providers/proxy.o
+LDAP_BE_OBJ = \
+ providers/ldap_be.o
+
NSSSRV_OBJ = \
- nss/nsssrv.o \
- nss/nsssrv_packet.o \
- nss/nsssrv_cmd.o \
- nss/nsssrv_dp.o
+ responder/nss/nsssrv.o \
+ responder/nss/nsssrv_cmd.o \
+ responder/nss/nsssrv_dp.o
INFOPIPE_OBJ = \
infopipe/infopipe.o \
@@ -51,17 +59,29 @@ SYSDB_TEST_OBJ = \
INFP_TEST_OBJ = \
tests/infopipe-tests.o
+PAMSRV_OBJ = \
+ responder/pam/pamsrv.o \
+ responder/pam/pamsrv_cmd.o \
+ responder/pam/pamsrv_dp.o
+
+PAMSRV_UTIL_OBJ = responder/pam/pamsrv_util.o
+
+PAM = -lpam
+
sbin/sssd: $(SERVER_OBJ) $(UTIL_OBJ)
$(CC) -o sbin/sssd $(SERVER_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
-sbin/sssd_nss: $(NSSSRV_OBJ) $(UTIL_OBJ)
- $(CC) -o sbin/sssd_nss $(NSSSRV_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
+sbin/sssd_nss: $(NSSSRV_OBJ) $(UTIL_OBJ) $(RESPONDER_UTIL_OBJ)
+ $(CC) -o sbin/sssd_nss $(NSSSRV_OBJ) $(UTIL_OBJ) $(RESPONDER_UTIL_OBJ) $(LDFLAGS) $(LIBS)
+
+sbin/sssd_pam: $(PAMSRV_OBJ) $(UTIL_OBJ) $(RESPONDER_UTIL_OBJ) $(PAMSRV_UTIL_OBJ)
+ $(CC) -o sbin/sssd_pam $(PAMSRV_OBJ) $(UTIL_OBJ) $(PAMSRV_UTIL_OBJ) $(RESPONDER_UTIL_OBJ) $(LDFLAGS) $(LIBS)
-sbin/sssd_dp: $(DP_OBJ) $(UTIL_OBJ)
- $(CC) -o sbin/sssd_dp $(DP_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
+sbin/sssd_dp: $(DP_OBJ) $(UTIL_OBJ) $(PAMSRV_UTIL_OBJ)
+ $(CC) -o sbin/sssd_dp $(DP_OBJ) $(UTIL_OBJ) $(PAMSRV_UTIL_OBJ) $(LDFLAGS) $(LIBS)
sbin/sssd_be: $(DP_BE_OBJ) $(UTIL_OBJ)
- $(CC) -Wl,-E -o sbin/sssd_be $(DP_BE_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
+ $(CC) -Wl,-E -o sbin/sssd_be $(DP_BE_OBJ) $(UTIL_OBJ) $(PAMSRV_UTIL_OBJ) $(LDFLAGS) $(LIBS) $(PAM)
sbin/sssd_info: $(INFOPIPE_OBJ) $(UTIL_OBJ)
$(CC) -o sbin/sssd_info $(INFOPIPE_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
@@ -70,9 +90,13 @@ sbin/sssd_pk: $(POLKIT_OBJ) $(UTIL_OBJ)
$(CC) -o sbin/sssd_pk $(POLKIT_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
lib/$(PROXY_BE_SOBASE): $(PROXY_BE_OBJ)
- $(SHLD) $(SHLD_FLAGS) $(SONAMEFLAG)$(PROXY_BE_SONAME) -o lib/$(PROXY_BE_SOLIB) $(PROXY_BE_OBJ) $(LDFLAGS) $(LIBS)
+ $(SHLD) $(SHLD_FLAGS) $(SONAMEFLAG)$(PROXY_BE_SONAME) -o lib/$(PROXY_BE_SOLIB) $(PROXY_BE_OBJ) $(LDFLAGS) $(LIBS) $(PAM_LIBS)
ln -fs $(PROXY_BE_SOLIB) $@
+lib/$(LDAP_BE_SOBASE): $(LDAP_BE_OBJ)
+ $(SHLD) $(SHLD_FLAGS) $(SONAMEFLAG)$(LDAP_BE_SONAME) -o lib/$(LDAP_BE_SOLIB) $(LDAP_BE_OBJ) $(LDFLAGS) $(LIBS) $(LDAP_LIBS)
+ ln -fs $(LDAP_BE_SOLIB) $@
+
lib/$(MEMBEROF_SOBASE): $(MEMBEROF_OBJ)
$(SHLD) $(SHLD_FLAGS) $(SONAMEFLAG)$(MEMBEROF_SONAME) -o lib/$(MEMBEROF_SOLIB) $(MEMBEROF_OBJ) $(LDFLAGS) $(LDB_LIBS)
ln -fs $(MEMBEROF_SOLIB) $@