summaryrefslogtreecommitdiff
path: root/server/providers
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/providers
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/providers')
-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
6 files changed, 1232 insertions, 2 deletions
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)