Better error reporting

svn path=/trunk/kdeutils/kdepasswd/; revision=55529
This commit is contained in:
Geert Jansen 2000-07-05 17:28:14 +00:00
parent c6719462a9
commit 6c9726aeb7
4 changed files with 152 additions and 86 deletions

View file

@ -1,11 +1,12 @@
/* vi: ts=8 sts=4 sw=4
*
* $Id: $
* $Id$
*
* This file is part of the KDE project, module kdesu.
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
*/
#include <config.h>
#include <stdlib.h>
#include <qcstring.h>
@ -15,16 +16,13 @@
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>
#include <kstddirs.h>
#include <kdebug.h>
#include "passwd.h"
#include "passwddlg.h"
const char *Version = "1.0";
static KCmdLineOptions options[] = {
static KCmdLineOptions options[] =
{
{ "user", I18N_NOOP("Change password of this user."), 0 },
{ 0, 0, 0 }
};
@ -33,9 +31,8 @@ static KCmdLineOptions options[] = {
int main(int argc, char **argv)
{
KAboutData aboutData("kdepasswd", I18N_NOOP("KDE passwd"),
Version, I18N_NOOP("Changes a Unix password."),
KAboutData::License_Artistic,
"Copyright (c) 2000 Geert Jansen");
VERSION, I18N_NOOP("Changes a Unix password."),
KAboutData::License_Artistic, "Copyright (c) 2000 Geert Jansen");
aboutData.addAuthor("Geert Jansen", I18N_NOOP("Maintainer"),
"jansen@kde.org", "http://www.stack.nl/~geertj/");
@ -43,17 +40,12 @@ int main(int argc, char **argv)
KCmdLineArgs::addCmdLineOptions(options);
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
KApplication app;
QCString user;
if (args->count())
user = args->arg(0);
KApplication app;
if (KStandardDirs::findExe("passwd").isEmpty()) {
kDebugFatal("passwd not found");
exit(1);
}
QCString oldpass;
int result = KDEpasswd1Dialog::getPassword(oldpass, user);
if (result != KDEpasswd1Dialog::Accepted)

View file

@ -9,6 +9,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
@ -29,28 +30,25 @@
#include "passwd.h"
#ifdef __GNUC__
#define ID __PRETTY_FUNCTION__
#else
#define ID "PasswdProcess"
#endif
PasswdProcess::PasswdProcess(QCString user)
{
struct passwd *pw;
if (user.isEmpty()) {
if (user.isEmpty())
{
pw = getpwuid(getuid());
if (pw == 0L) {
kdDebug() << "You don't exist!";
if (pw == 0L)
{
kdDebug(1512) << "You don't exist!\n";
return;
}
m_User = pw->pw_name;
} else {
} else
{
pw = getpwnam(user);
if (pw == 0L) {
kdDebug() << ID << ": User " << user.data() << "does not exist.";
if (pw == 0L)
{
kdDebug(1512) << k_lineinfo << "User " << user << "does not exist.\n";
return;
}
m_User = user;
@ -65,7 +63,7 @@ PasswdProcess::~PasswdProcess()
int PasswdProcess::checkCurrent(const char *oldpass)
{
return exec(oldpass, 0L, 1) != 1;
return exec(oldpass, 0L, 1);
}
@ -77,26 +75,24 @@ int PasswdProcess::exec(const char *oldpass, const char *newpass,
if (check)
setTerminal(true);
QString path = KStandardDirs::findExe("passwd");
if (path.isEmpty()) {
kdDebug() << "passwd not found!";
return -1;
}
QCString cpath = path.latin1();
// Try to set the default locale to make the parsing of the output
// of `passwd' easier.
putenv("LANG=C");
QCStringList args;
args += m_User;
if (PtyProcess::exec(cpath, args) < 0)
return -1;
int ret = ConversePasswd(oldpass, newpass, check);
if (ret < 0) {
kdDebug() << ID << ": Conversation with passwd failed";
return -1;
}
if (ret == 1) {
kill(m_Pid, SIGKILL);
waitForChild();
int ret = PtyProcess::exec("passwd", args);
if (ret < 0)
{
kdDebug(1512) << k_lineinfo << "Passwd not found!\n";
return PasswdNotFound;
}
ret = ConversePasswd(oldpass, newpass, check);
if (ret < 0)
kdDebug(1512) << k_lineinfo << "Conversation with passwd failed.\n";
waitForChild();
return ret;
}
@ -104,6 +100,7 @@ int PasswdProcess::exec(const char *oldpass, const char *newpass,
/*
* The tricky thing is to make this work with a lot of different passwd
* implementations. We _don't_ want implementation specific routines.
* Return values: -1 = unknown error, 0 = ok, >0 = error code.
*/
int PasswdProcess::ConversePasswd(const char *oldpass, const char *newpass,
@ -112,30 +109,34 @@ int PasswdProcess::ConversePasswd(const char *oldpass, const char *newpass,
QCString line;
int state = 0;
while (state < 7) {
while (state != 7)
{
line = readLine();
if (line.isNull()) {
if (state == 6)
break;
else
return -1;
if (line.isNull())
{
return -1;
}
switch (state) {
switch (state)
{
case 0:
// Eat garbage, wait for prompt
if (isPrompt(line, "password")) {
if (isPrompt(line, "password"))
{
WaitSlave();
write(m_Fd, oldpass, strlen(oldpass));
write(m_Fd, "\n", 1);
state++; break;
state++;
break;
}
if (m_bTerminal) fputs(line, stdout);
if (m_bTerminal)
fputs(line, stdout);
break;
case 1: case 3: case 5:
case 1: case 3: case 6:
// Wait for \n
if (line.isEmpty()) {
if (line.isEmpty())
{
state++;
break;
}
@ -144,41 +145,67 @@ int PasswdProcess::ConversePasswd(const char *oldpass, const char *newpass,
case 2:
// Wait for second prompt.
if (isPrompt(line, "new")) {
if (isPrompt(line, "new"))
{
if (check)
return 1;
{
kill(m_Pid, SIGKILL);
waitForChild();
return 0;
}
WaitSlave();
write(m_Fd, newpass, strlen(newpass));
write(m_Fd, "\n", 1);
state++; break;
state++;
break;
}
// Assume error message.
if (m_bTerminal) fputs(line, stdout);
// Assume incorrect password.
if (m_bTerminal)
fputs(line, stdout);
m_Error = line;
return -1;
return PasswordIncorrect;
case 4:
// Wait for third prompt
if (isPrompt(line, "password")) {
if (isPrompt(line, "re"))
{
WaitSlave();
write(m_Fd, newpass, strlen(newpass));
write(m_Fd, "\n", 1);
state++; break;
state += 2;
break;
}
// Assume error message.
if (m_bTerminal) fputs(line, stdout);
// Warning or error about the new password
if (m_bTerminal)
fputs(line, stdout);
m_Error = line;
return -1;
state++;
break;
case 6:
// Wait for EOF, but no prompt.
if (isPrompt(line, "password"))
return 1;
if (m_bTerminal) fputs(line, stdout);
case 5:
// Wait for either a "Reenter password" or a "Enter password" prompt
if (isPrompt(line, "re"))
{
WaitSlave();
write(m_Fd, newpass, strlen(newpass));
write(m_Fd, "\n", 1);
state++;
break;
}
else if (isPrompt(line, "password"))
{
kill(m_Pid, SIGKILL);
waitForChild();
return PasswordNotGood;
}
if (m_bTerminal)
fputs(line, stdout);
m_Error += line;
break;
}
}
kdDebug() << ID << ": Conversation ended";
kdDebug(1512) << k_lineinfo << "Conversation ended successfully.\n";
return 0;
}
@ -187,8 +214,10 @@ bool PasswdProcess::isPrompt(QCString line, const char *word)
{
unsigned i, j, colon;
for (i=0,j=0,colon=0; i<line.length(); i++) {
if (line[i] == ':') {
for (i=0,j=0,colon=0; i<line.length(); i++)
{
if (line[i] == ':')
{
j = i; colon++;
continue;
}
@ -200,7 +229,6 @@ bool PasswdProcess::isPrompt(QCString line, const char *word)
return false;
if (word == 0L)
return true;
return line.contains(word, false);
}

View file

@ -1,6 +1,6 @@
/* vi: ts=8 sts=4 sw=4
*
* $Id: $
* $Id$
*
* This file is part of the KDE project, module kdesu.
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
@ -23,6 +23,8 @@ public:
PasswdProcess(QCString user=0);
~PasswdProcess();
enum Errors { PasswdNotFound=1, PasswordIncorrect, PasswordNotGood };
int checkCurrent(const char *oldpass);
int exec(const char *oldpass, const char *newpass, int check=0);

View file

@ -33,12 +33,31 @@ KDEpasswd1Dialog::~KDEpasswd1Dialog()
bool KDEpasswd1Dialog::checkPassword(const char *password)
{
PasswdProcess proc(m_User);
int ret = proc.checkCurrent(password);
if (ret != 0) {
switch (ret)
{
case -1:
KMessageBox::error(this, i18n("Conversation with `passwd' failed."));
done(Rejected);
return true;
case 0:
return true;
case PasswdProcess::PasswdNotFound:
KMessageBox::error(this, i18n("Could not find the program `passwd'."));
return true;
case PasswdProcess::PasswordIncorrect:
KMessageBox::sorry(this, i18n("Incorrect password! Please try again."));
return false;
default:
KMessageBox::error(this, i18n("Internal error: illegal return value "
"from PasswdProcess::checkCurrent."));
return true;
}
return true;
}
@ -74,11 +93,36 @@ KDEpasswd2Dialog::~KDEpasswd2Dialog()
bool KDEpasswd2Dialog::checkPassword(const char *password)
{
PasswdProcess proc(m_User);
int ret = proc.exec(m_Pass, password);
if (ret != 0) {
KMessageBox::error(this, proc.error());
return false;
if (strlen(password) > 8)
{
KMessageBox::information(this,
i18n("Your password will be truncated to 8 characters."));
const_cast<char *>(password)[8] = '\000';
}
int ret = proc.exec(m_Pass, password);
switch (ret)
{
case 0:
if (!proc.error().isEmpty())
{
// The pw change succeeded but there is a warning.
KMessageBox::information(this, proc.error());
}
return true;
case PasswdProcess::PasswordNotGood:
// The pw change did not succeed. Print the error.
KMessageBox::sorry(this, proc.error());
return false;
default:
KMessageBox::sorry(this, i18n("Conversation with `passwd' failed."));
done(Rejected);
return true;
}
return true;
}