~ubuntu-filemanager-dev/ubuntu-filemanager-app/trunk

« back to all changes in this revision

Viewing changes to src/plugin/pamauthentication/pamauthentication.cpp

  • Committer: Tarmac
  • Author(s): Arto Jalkanen, David Planella, Nicholas Skaggs, nskaggs
  • Date: 2014-08-15 05:57:51 UTC
  • mfrom: (240.2.26 require-screenlock-password)
  • Revision ID: tarmac-20140815055751-h1z9kb2espzc3r8u
Only show files and allow operating in non-MTP folders unless password explicitly given. Fixes: https://bugs.launchpad.net/bugs/1347010.

Approved by Ubuntu Phone Apps Jenkins Bot, Arto Jalkanen, Seth Arnold.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2014 Canonical Ltd
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Author : Arto Jalkanen <ajalkane@gmail.com>
 
17
 */
 
18
 
 
19
#include "pamauthentication.h"
 
20
 
 
21
#include <QDebug>
 
22
#include <QtDBus/QtDBus>
 
23
 
 
24
#include <security/pam_appl.h>
 
25
 
 
26
#define UNITYGREETER_SERVICE "com.canonical.UnityGreeter"
 
27
#define UNITYGREETER_PATH "/list"
 
28
#define UNITYGREETER_INTERFACE "com.canonical.UnityGreeter.List"
 
29
#define UNITYGREETER_PROPERTY_ENTRY_IS_LOCKED "EntryIsLocked"
 
30
 
 
31
 
 
32
PamAuthentication::PamAuthentication(QObject *parent) :
 
33
    QObject(parent)
 
34
{
 
35
    m_userLogin = qgetenv("USER");
 
36
}
 
37
 
 
38
PamAuthentication::~PamAuthentication() {
 
39
 
 
40
}
 
41
 
 
42
void
 
43
PamAuthentication::setServiceName(const QString &serviceName) {
 
44
    if (serviceName != m_serviceName) {
 
45
        m_serviceName = serviceName;
 
46
        emit serviceNameChanged();
 
47
    }
 
48
}
 
49
 
 
50
bool
 
51
PamAuthentication::requireAuthentication() {
 
52
    // Desktop doesn't have yet Unity8 and so no unity greeter either. Consequently it doesn't
 
53
    // also have any "PIN code" or "Password" extra authentication. Don't require any extra
 
54
    // authentication there.
 
55
    if (qgetenv("QT_QPA_PLATFORM") != "ubuntumirclient") {
 
56
        qDebug() << Q_FUNC_INFO << "Running on non-MIR desktop, not requiring authentication";
 
57
        return false;
 
58
    }
 
59
 
 
60
    QDBusInterface dbus_iface(UNITYGREETER_SERVICE, UNITYGREETER_PATH, UNITYGREETER_INTERFACE);
 
61
 
 
62
    qDebug() << Q_FUNC_INFO << "Querying if authentication required";
 
63
 
 
64
    if (!dbus_iface.isValid()) {
 
65
        qDebug() << Q_FUNC_INFO << "Not a valid dbus interface";
 
66
        qDebug() << Q_FUNC_INFO << "Last error: " + dbus_iface.lastError().message();
 
67
        // By default be cautious and require authentication
 
68
        return true;
 
69
    }
 
70
    QVariant isLockedVariant = dbus_iface.property(UNITYGREETER_PROPERTY_ENTRY_IS_LOCKED);
 
71
    if (isLockedVariant.isValid()) {
 
72
        bool replyValue = isLockedVariant.toBool();
 
73
        qDebug() << Q_FUNC_INFO << "Return value" << replyValue;
 
74
        return replyValue;
 
75
    } else {
 
76
        qDebug() << Q_FUNC_INFO << "Failed getting value for EntryIsLocked property";
 
77
    }
 
78
    // By default be cautious and require authentication
 
79
    return true;
 
80
}
 
81
 
 
82
bool
 
83
PamAuthentication::validatePasswordToken(const QString &token) {
 
84
    pam_handle *pamHandle = 0;
 
85
    if (!initPam(&pamHandle)) {
 
86
        qDebug() << Q_FUNC_INFO << "Pam init failed";
 
87
        return false;
 
88
    }
 
89
 
 
90
    m_passwordToken = token;
 
91
 
 
92
    int status = pam_authenticate(pamHandle, 0);
 
93
    qDebug() << Q_FUNC_INFO << "Pam authenticate status" << status << pam_strerror(pamHandle, status);
 
94
    if (status == PAM_SUCCESS) {
 
95
        status = validateAccount(pamHandle);
 
96
    }
 
97
    pam_end(pamHandle, status);
 
98
 
 
99
    m_passwordToken.clear();
 
100
 
 
101
    return status == PAM_SUCCESS;
 
102
}
 
103
 
 
104
int
 
105
PamAuthentication::validateAccount(pam_handle *pamHandle) {
 
106
    // This makes sure account and password are still valid
 
107
    int status = pam_acct_mgmt(pamHandle, 0);
 
108
    qDebug() << Q_FUNC_INFO << "pam_acct_mgmt: " << status << pam_strerror(pamHandle, status);
 
109
    // Placeholders for some common errors
 
110
    // IMPROVE: it'd be good to let user know reason for failure
 
111
    switch (status) {
 
112
    case PAM_SUCCESS:
 
113
        break;
 
114
    case PAM_USER_UNKNOWN:
 
115
        break;
 
116
    case PAM_ACCT_EXPIRED:
 
117
        break;
 
118
    case PAM_NEW_AUTHTOK_REQD:
 
119
        break;
 
120
    }
 
121
    return status;
 
122
}
 
123
 
 
124
bool
 
125
PamAuthentication::initPam(pam_handle **pamHandle)
 
126
{
 
127
    pam_conv conversation;
 
128
    conversation.conv = ConversationFunction;
 
129
    conversation.appdata_ptr = static_cast<void *>(this);
 
130
 
 
131
    return pam_start(m_serviceName.toLocal8Bit().data(), m_userLogin.toLocal8Bit().data(),
 
132
                     &conversation, pamHandle) == PAM_SUCCESS;
 
133
}
 
134
 
 
135
int PamAuthentication::ConversationFunction(int num_msg,
 
136
                                            const pam_message **msg,
 
137
                                            pam_response **resp,
 
138
                                            void* appdata_ptr)
 
139
{
 
140
    if (num_msg <= 0) {
 
141
        return PAM_CONV_ERR;
 
142
    }
 
143
 
 
144
    *resp = static_cast<pam_response*>(calloc(num_msg, sizeof(pam_response)));
 
145
 
 
146
    PamAuthentication *self = static_cast<PamAuthentication*>(appdata_ptr);
 
147
 
 
148
    for (int count = 0; count < num_msg; ++count) {
 
149
        switch (msg[count]->msg_style) {
 
150
        case PAM_PROMPT_ECHO_ON:
 
151
        {
 
152
            qDebug() << Q_FUNC_INFO << "PAM_PROMPT_ECHO_ON received";
 
153
            resp[count]->resp = strdup(self->m_passwordToken.toLocal8Bit().data());
 
154
            resp[count]->resp_retcode = 0;
 
155
            break;
 
156
        }
 
157
        case PAM_PROMPT_ECHO_OFF:
 
158
        {
 
159
            qDebug() << Q_FUNC_INFO << "PAM_PROMPT_ECHO_OFF received";
 
160
            resp[count]->resp = strdup(self->m_passwordToken.toLocal8Bit().data());
 
161
            resp[count]->resp_retcode = 0;
 
162
            break;
 
163
        }
 
164
        case PAM_TEXT_INFO:
 
165
        {
 
166
            QString message(msg[count]->msg);
 
167
            qDebug() << Q_FUNC_INFO << "PAM_TEXT_INFO received" << message;
 
168
            break;
 
169
        }
 
170
        case PAM_AUTHTOK:
 
171
        {
 
172
            qDebug() << Q_FUNC_INFO << "PAM_AUTHTOK received";
 
173
            break;
 
174
        }
 
175
        default:
 
176
        {
 
177
            qDebug() << Q_FUNC_INFO << "Other PAM msg received: " << msg[count]->msg_style;
 
178
        }
 
179
        }
 
180
    }
 
181
 
 
182
    return PAM_SUCCESS;
 
183
}