1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3
* Copyright (C) 2013 Canonical Ltd
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 3 as
7
* published by the Free Software Foundation.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
20
// Kindly inspired by user_authenticator_linux.cc of chromium project
21
// TODO (andy) Would be nice to make it more thread-safe and to imporve
22
// the API and the cody style
23
#include "UserAuthenticatorPam.h"
25
#include <security/pam_appl.h>
26
#include <UnityCore/GLibWrapper.h>
33
bool UserAuthenticatorPam::AuthenticateStart(std::string const& username,
34
std::string const& password,
35
AuthenticateEndCallback authenticate_cb)
39
authenticate_cb_ = authenticate_cb;
41
// FIXME: would be nice to support a fallback in case PAM
46
glib::Object<GTask> task(g_task_new(nullptr, nullptr, [] (GObject*, GAsyncResult*, gpointer data) {
47
auto self = static_cast<UserAuthenticatorPam*>(data);
48
pam_end(self->pam_handle_, self->status_);
49
self->authenticate_cb_(self->status_ == PAM_SUCCESS);
52
g_task_set_task_data(task, this, nullptr);
54
g_task_run_in_thread(task, [] (GTask* task, gpointer, gpointer data, GCancellable*) {
55
auto self = static_cast<UserAuthenticatorPam*>(data);
56
self->status_ = pam_authenticate(self->pam_handle_, 0);
62
bool UserAuthenticatorPam::InitPam()
64
pam_conv conversation;
65
conversation.conv = ConverationFunction;
66
conversation.appdata_ptr = static_cast<void*>(this);
68
return pam_start(/*FIXME*/ "gnome_screensaver", username_.c_str(),
69
&conversation, &pam_handle_) == PAM_SUCCESS;
72
int UserAuthenticatorPam::ConverationFunction(int num_msg,
73
const pam_message** msg,
80
auto* tmp_response = static_cast<pam_response*>(malloc(num_msg * sizeof(pam_response)));
84
UserAuthenticatorPam* user_auth = static_cast<UserAuthenticatorPam*>(appdata_ptr);
86
bool raise_error = false;
88
for (count = 0; count < num_msg && !raise_error; ++count)
90
pam_response* resp_item = &tmp_response[count];
91
resp_item->resp_retcode = 0;
92
resp_item->resp = nullptr;
94
switch (msg[count]->msg_style)
96
case PAM_PROMPT_ECHO_ON:
97
resp_item->resp = strdup(user_auth->username_.c_str());
101
case PAM_PROMPT_ECHO_OFF:
102
resp_item->resp = strdup(user_auth->password_.c_str());
103
if (!resp_item->resp)
115
for (int i = 0; i < count; ++i)
116
if (tmp_response[i].resp)
117
free(tmp_response[i].resp);
124
*resp = tmp_response;