/*
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 "providers/data_provider.h"
#include "sbus/sbus_client.h"
#include "responder/pam/pamsrv.h"
static void pam_dp_process_reply(DBusPendingCall *pending, void *ptr)
{
DBusError dbus_error;
DBusMessage* msg;
int ret;
int type;
struct pam_auth_req *preq = NULL;
struct pam_auth_dp_req *pdp_req;
pdp_req = talloc_get_type(ptr, struct pam_auth_dp_req);
preq = pdp_req->preq;
talloc_free(pdp_req);
dbus_error_init(&dbus_error);
msg = dbus_pending_call_steal_reply(pending);
/* Check if the client still exists. If not, simply free all the resources
* and quit */
if (preq == NULL) {
DEBUG(SSSDBG_MINOR_FAILURE, "Client already disconnected\n");
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
return;
}
/* Sanity-check of message validity */
if (msg == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Severe error. A reply callback was called but no reply was"
"received and no timeout occurred\n");
preq->pd->pam_status = PAM_SYSTEM_ERR;
goto done;
}
type = dbus_message_get_type(msg);
switch (type) {
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
ret = dp_unpack_pam_response(msg, preq->pd, &dbus_error);
if (!ret) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse reply.\n");
preq->pd->pam_status = PAM_SYSTEM_ERR;
goto done;
}
DEBUG(SSSDBG_FUNC_DATA,
"received: [%d (%s)][%s]\n", preq->pd->pam_status,
pam_strerror(NULL, preq->pd->pam_status),
preq->pd->domain);
break;
case DBUS_MESSAGE_TYPE_ERROR:
DEBUG(SSSDBG_FATAL_FAILURE, "Reply error.\n");
preq->pd->pam_status = PAM_SYSTEM_ERR;
break;
default:
DEBUG(SSSDBG_FATAL_FAILURE, "Default... what now?.\n");
preq->pd->pam_status = PAM_SYSTEM_ERR;
}
done:
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
preq->callback(preq);
}
static int pdp_req_destructor(struct pam_auth_dp_req *pdp_req)
{
if (pdp_req && pdp_req->preq) {
/* If there is still a client waiting, reset the
* spy */
pdp_req->preq->dpreq_spy = NULL;
}
return 0;
}
int pam_dp_send_req(struct pam_auth_req *preq, int timeout)
{
struct pam_data *pd = preq->pd;
struct be_conn *be_conn;
DBusMessage *msg;
dbus_bool_t ret;
int res;
struct pam_auth_dp_req *pdp_req;
/* double check dp_ctx has actually been initialized.
* in some pathological cases it may happen that nss starts up before
* dp connection code is actually able to establish a connection.
*/
res = sss_dp_get_domain_conn(preq->cctx->rctx,
preq->domain->conn_name, &be_conn);
if (res != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"The Data Provider connection for %s is not available!"
" This maybe a bug, it shouldn't happen!\n",
preq->domain->conn_name);
return EIO;
}
msg = dbus_message_new_method_call(NULL,
DP_PATH,
IFACE_DP,
IFACE_DP_PAMHANDLER);
if (msg == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
return ENOMEM;
}
DEBUG(SSSDBG_CONF_SETTINGS, "Sending request with the following data:\n");
DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
ret = dp_pack_pam_request(msg, pd);
if (!ret) {
DEBUG(SSSDBG_CRIT_FAILURE,"Failed to build message\n");
return EIO;
}
pdp_req = talloc(preq->cctx->rctx, struct pam_auth_dp_req);
if (pdp_req == NULL) {
return ENOMEM;
}
pdp_req->preq = preq;
preq->dpreq_spy = pdp_req;
talloc_set_destructor(pdp_req, pdp_req_destructor);
res = sbus_conn_send(be_conn->conn, msg,
timeout, pam_dp_process_reply,
pdp_req, NULL);
dbus_message_unref(msg);
return res;
}