1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
//===========================================
// Lumina-DE source code
// Copyright (c) 2015, Ken Moore
// Available under the 3-clause BSD license
// See the LICENSE file for full details
//===========================================
#include "LLockScreen.h"
#include "ui_LLockScreen.h"
//Standard C libary for username/system fetch
#include <unistd.h>
//#include <sys/param.h>
//PAM libraries
#include <sys/types.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
//#include <sys/wait.h>
//#include <pwd.h>
//#include <login_cap.h>
#define DEBUG 1
LLockScreen::LLockScreen(QWidget *parent) : QWidget(parent), ui(new Ui::LLockScreen()){
ui->setupUi(this);
waittime = new QTimer(this);
waittime->setInterval(300000); //5 minutes (too many attempts in short time)
waittime->setSingleShot(true);
connect(ui->tool_unlock, SIGNAL(clicked()), this, SLOT(TryUnlock()) );
connect(ui->line_password, SIGNAL(returnPressed()), this, SLOT(TryUnlock()) );
connect(ui->line_password, SIGNAL(textEdited(QString)), this, SIGNAL(InputDetected()) );
connect(ui->line_password, SIGNAL(cursorPositionChanged(int,int)), this, SIGNAL(InputDetected()) );
connect(waittime, SIGNAL(timeout()), this, SLOT(aboutToShow()) );
}
LLockScreen::~LLockScreen(){
}
void LLockScreen::LoadSystemDetails(){
//Run every time the screen is initially locked
QString user = QString(getlogin());
ui->label_username->setText( QString(tr("Locked by: %1")).arg(user) );
ui->label_hostname->setText( QHostInfo::localHostName() );
ui->tool_unlock->setIcon( LXDG::findIcon("document-decrypt","") );
attempts = 0;
bool ok = PAM_lockSession(user);
qDebug() << "Closed PAM session:" << ok;
}
void LLockScreen::aboutToHide(){
//auto-hide timeout - clear display
ui->line_password->clear();
ui->line_password->clearFocus();
if(!waittime->isActive()){ ui->label_info->clear(); } //could be obsolete the next time the lock screen is shown
}
void LLockScreen::aboutToShow(){
if(!waittime->isActive()){
ui->label_info->setText( PAM_checkLockInfo( QString(getlogin()) ) );
this->setEnabled(true);
triesleft = 4; //back to initial number of tries
}
ui->line_password->clear();
ui->line_password->setFocus();
}
// =================
// PRIVATE
// =================
// PAM structures for the functions below
static struct pam_conv pamc = { openpam_nullconv, NULL };
pam_handle_t *pamh;
bool LLockScreen::PAM_checkpass(QString user, QString pass, QString &info){
//Convert the inputs to C character arrays for use in PAM
if(DEBUG){qDebug() << "Check Password w/PAM:" << user << pass;}
QByteArray tmp2 = pass.toUtf8();
char* cPassword = tmp2.data();
//initialize variables
bool result = false;
//Place the user-supplied password into the structure
int ret = pam_set_item(pamh, PAM_AUTHTOK, cPassword);
//Set the TTY
//Authenticate with PAM
ret = pam_authenticate(pamh,0);
if( ret == PAM_SUCCESS ){
//Check for valid, unexpired account and verify access restrictions
ret = pam_acct_mgmt(pamh,0);
if( ret == PAM_SUCCESS ){
result = true;
ret = pam_setcred(pamh,PAM_REINITIALIZE_CRED);
ret = pam_end(pamh,ret);
}else{ info = PAM_getError(ret); }
}else{
info = PAM_getError(ret);
}
if(DEBUG){ qDebug() << " - Result:" << result << ret; }
//return verification result
return result;
}
QString LLockScreen::PAM_checkLockInfo(QString user){
//Return info string with any account lock/reset info
return ""; //not implemented yet
}
QString LLockScreen::PAM_getError(int ret){
QString err;
//Interpret a PAM error message and log it
//qWarning() << "PAM Error: " << ret;
switch( ret ){
case PAM_MAXTRIES:
err = tr("Too Many Failures: Try again later.");
break;
case PAM_NEW_AUTHTOK_REQD:
err = tr("Password Expired: Contact System Admin");
break;
default:
triesleft--;
if(triesleft>0){ err = QString(tr("Failure: %1 Attempts Remaining")).arg( QString::number(triesleft) ); }
else{err = tr("Too Many Failures: Try again in 5 minutes"); }
if(DEBUG){ err.append("\n"+QString(pam_strerror(pamh, ret)) ); }
}
return err;
}
bool LLockScreen::PAM_lockSession(QString user){
QByteArray tmp = user.toUtf8();
char* cUser = tmp.data();
int ret = pam_start( user=="root" ? "system": "login", cUser, &pamc, &pamh);
//if(ret == PAM_SUCCESS){ ret = pam_setcred(pamh,PAM_DELETE_CRED); }
return (ret== PAM_SUCCESS);
}
// =================
// PRIVATE SLOTS
// =================
void LLockScreen::TryUnlock(){
attempts++;
this->setEnabled(false);
QString pass = ui->line_password->text();
ui->line_password->clear();
QString user = QString(getlogin());
QString info;
bool ok = PAM_checkpass(user, pass, info);
if(ok){
emit ScreenUnlocked();
this->setEnabled(true);
}else if(triesleft>1){
this->setEnabled(true);
ui->label_info->setText(info);
}else{
ui->label_info->setText(info);
waittime->start();
}
}
|