ukui-control-center/ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch
huayadong 161bd1abd1 fix password changes for this user and for other use
(cherry picked from commit 648ac5e06e1c18ae64a3906cdf7449c3960fc622)
2023-06-12 10:58:16 +08:00

1895 lines
61 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From d345bc5b0688c93f1942e38a0bf03eca9dbb0001 Mon Sep 17 00:00:00 2001
From: huayadong <huayadong@kylinos.cn>
Date: Fri, 9 Jun 2023 10:54:52 +0800
Subject: [PATCH] fix-password-changes-for-this-user-and-for-other-use
---
changeOtherUserPwd/run-passwd2.cpp | 5 +
changeUserPwd/run-passwd.cpp | 4 +
checkUserPwdWithPAM/checkUserPwd/auth-pam.cpp | 343 ---------
checkUserPwdWithPAM/checkUserPwd/auth-pam.h | 59 --
checkUserPwdWithPAM/checkUserPwd/auth.h | 62 --
.../checkUserPwd/checkUserPwd.pro | 38 -
checkUserPwdWithPAM/checkUserPwd/main.cpp | 20 -
checkUserPwdWithPAM/checkUserPwd/widget.cpp | 61 --
checkUserPwdWithPAM/checkUserPwd/widget.h | 29 -
checkUserPwdWithPAM/checkUserPwdWithPAM.pro | 41 +-
.../childCheckPwdWithPAM.pro | 39 -
.../childCheckPwdWithPAM/main.cpp | 166 -----
checkUserPwdWithPAM/conf/control-center | 11 -
checkUserPwdWithPAM/main.cpp | 81 ++
checkUserPwdWithPAM/run-passwd.cpp | 704 ++++++++++++++++++
checkUserPwdWithPAM/run-passwd.h | 34 +
plugins/account/userinfo/changeuserpwd.cpp | 3 +-
plugins/account/userinfo/pwdcheckthread.cpp | 2 +-
translate_generation.sh | 2 +-
19 files changed, 867 insertions(+), 837 deletions(-)
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/auth-pam.cpp
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/auth-pam.h
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/auth.h
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/checkUserPwd.pro
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/main.cpp
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/widget.cpp
delete mode 100644 checkUserPwdWithPAM/checkUserPwd/widget.h
delete mode 100644 checkUserPwdWithPAM/childCheckPwdWithPAM/childCheckPwdWithPAM.pro
delete mode 100644 checkUserPwdWithPAM/childCheckPwdWithPAM/main.cpp
delete mode 100644 checkUserPwdWithPAM/conf/control-center
create mode 100644 checkUserPwdWithPAM/main.cpp
create mode 100644 checkUserPwdWithPAM/run-passwd.cpp
create mode 100644 checkUserPwdWithPAM/run-passwd.h
diff --git a/changeOtherUserPwd/run-passwd2.cpp b/changeOtherUserPwd/run-passwd2.cpp
index 29c1901..483cfaa 100644
--- a/changeOtherUserPwd/run-passwd2.cpp
+++ b/changeOtherUserPwd/run-passwd2.cpp
@@ -284,6 +284,11 @@ static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, Pas
/* Pop retyped password from queue and into IO channel */
io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+ if (passwd_handler->chpasswd_cb)
+ passwd_handler->chpasswd_cb (passwd_handler,
+ NULL,
+ passwd_handler->chpasswd_cb_data);
+
reinit = TRUE;
}
break;
diff --git a/changeUserPwd/run-passwd.cpp b/changeUserPwd/run-passwd.cpp
index 3b416ec..2700f78 100644
--- a/changeUserPwd/run-passwd.cpp
+++ b/changeUserPwd/run-passwd.cpp
@@ -286,6 +286,10 @@ static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, Pas
io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
reinit = TRUE;
+ if (passwd_handler->chpasswd_cb)
+ passwd_handler->chpasswd_cb (passwd_handler,
+ NULL,
+ passwd_handler->chpasswd_cb_data);
}
break;
case PASSWD_STATE_RETYPE:
diff --git a/checkUserPwdWithPAM/checkUserPwd/auth-pam.cpp b/checkUserPwdWithPAM/checkUserPwd/auth-pam.cpp
deleted file mode 100644
index 9695b54..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/auth-pam.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
- *
- * 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, 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 "auth-pam.h"
-#include <string.h>
-#include <QDebug>
-#include <sys/prctl.h>
-#include <unistd.h>
-#include <wait.h>
-
-#include <QTimer>
-
-
-#define PAM_SERVICE_NAME "control-center"
-
-//通信管道的文件描述符
-int toParent[2], toChild[2];
-
-static void writeData(int fd, const void *buf, ssize_t count);
-static void writeString(int fd, const char *data);
-static int readData(int fd, void *buf, size_t count);
-static char * readString(int fd);
-static int pam_conversation(int msgLength, const struct pam_message **msg,
- PAM_RESPONSE **resp, void *appData);
-static void sigchld_handler(int signo);
-
-AuthPAM::AuthPAM(QObject *parent)
- : Auth(parent),
- pid(0),
- nPrompts(0),
- _isAuthenticated(false),
- _isAuthenticating(false)
-{
- signal(SIGCHLD, sigchld_handler);
-}
-
-void AuthPAM::authenticate(const QString &userName, const QString &userPwd)
-{
- stopAuth();
-
- if(pipe(toParent) || pipe(toChild))
- qDebug()<< "create pipe failed: " << strerror(errno);
- if((pid = fork()) < 0)
- {
- qDebug() << "fork error: " << strerror(errno);
- }
- else if(pid == 0)
- {
- int arg1_int = toParent[1];
- int arg2_int = toChild[0];
- char arg1[128];
- char arg2[128];
- snprintf(arg1,128,"%d",arg1_int);
- snprintf(arg2,128,"%d",arg2_int);
- //_authenticate(userName.toLocal8Bit().data());
- prctl(PR_SET_PDEATHSIG,SIGHUP);
- execlp ("childCheckpwdwithPAM",
- "childCheckpwdwithPAM",
- arg1, arg2,userName.toLocal8Bit().data(), NULL);
- _exit (EXIT_FAILURE);
- }
- else
- {
- _isAuthenticating = true;
- notifier = new QSocketNotifier(toParent[0], QSocketNotifier::Read);
- connect(notifier, &QSocketNotifier::activated, this, &AuthPAM::onSockRead);
- }
-
- QTimer::singleShot(100, this, [=]{respond(userPwd);});
-
-}
-
-void AuthPAM::stopAuth()
-{
-// qDebug()<<"pppppppppppppppppid = "<<pid;
- if(pid != 0)
- {
- messageList.clear();
- responseList.clear();
- _isAuthenticating = false;
- _isAuthenticated = false;
- nPrompts = 0;
-
- ::kill(pid, SIGKILL);
-
- pid = 0;
- }
-}
-
-void AuthPAM::respond(const QString &response)
-{
- nPrompts--;
- responseList.push_back(response);
-
-// for(auto msg : messageList)
-// qDebug() << msg.msg;
-// qDebug() << responseList;
-// qDebug() << nPrompts;
-
- if(nPrompts == 0)
- {
- //发送响应到子进程
- int j = 0;
- PAM_RESPONSE *resp = (PAM_RESPONSE*)calloc(messageList.size(), sizeof(PAM_RESPONSE));
- //响应的数量和消息的数量一致如果消息类型不是PROMPT则响应是空的
- for(int i = 0; i < messageList.size(); i++)
- {
- struct pam_message message = messageList[i];
- PAM_RESPONSE *r = &resp[i];
- if(message.msg_style == PAM_PROMPT_ECHO_OFF
- || message.msg_style == PAM_PROMPT_ECHO_ON)
- {
- int respLength = responseList[j].length() + 1;
- r->resp = (char *)malloc(sizeof(char) * respLength);
- memcpy(r->resp, responseList[j].toLocal8Bit().data(), respLength);
- j++;
- }
- }
- _respond(resp);
- free(resp);
- resp = NULL;
- messageList.clear();
- responseList.clear();
- }
-}
-
-bool AuthPAM::isAuthenticated()
-{
- return _isAuthenticated;
-}
-
-bool AuthPAM::isAuthenticating()
-{
- return _isAuthenticating;
-}
-
-
-void AuthPAM::onSockRead()
-{
-// qDebug() << "has message";
- int msgLength;
- int authComplete;
- readData(toParent[0], &authComplete, sizeof(authComplete));
-
- if(authComplete)
- {
- int authRet;
- if(readData(toParent[0], (void*)&authRet, sizeof(authRet)) <= 0)
- qDebug() << "get authentication result failed: " << strerror(errno);
-// qDebug() << "result: " << authRet;
- _isAuthenticated = (authRet == PAM_SUCCESS);
- _isAuthenticating = false;
- Q_EMIT authenticateComplete();
-
- }
- else
- {
- readData(toParent[0], &msgLength, sizeof(msgLength));
-// qDebug() << "message length: " << msgLength;
-
- for(int i = 0; i < msgLength; i++)
- {
- //读取message
- struct pam_message message;
- readData(toParent[0], &message.msg_style, sizeof(message.msg_style));
- message.msg = readString(toParent[0]);
-
-// qDebug() << message.msg;
-
- messageList.push_back(message);
-
- switch (message.msg_style)
- {
- case PAM_PROMPT_ECHO_OFF:
- nPrompts++;
- Q_EMIT showPrompt(message.msg, Auth::PromptTypeSecret);
- break;
- case PAM_PROMPT_ECHO_ON:
- nPrompts++;
- Q_EMIT showPrompt(message.msg, Auth::PromptTypeQuestion);
- break;
- case PAM_ERROR_MSG:
- Q_EMIT showMessage(message.msg, Auth::MessageTypeInfo);
- break;
- case PAM_TEXT_INFO:
- Q_EMIT showMessage(message.msg, Auth::MessageTypeError);
- break;
- }
- }
-
- if(nPrompts == 0)
- {
- //不需要响应,发送一个空的
- PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(messageList.size(), sizeof(PAM_RESPONSE));
- _respond(response);
- free(response);
- response = NULL;
- messageList.clear();
- }
- }
-}
-
-static void
-writeData(int fd, const void *buf, ssize_t count)
-{
- if(write(fd, buf, count) != count)
- qDebug() << "write to parent failed: " << strerror(errno);
-}
-
-static void
-writeString(int fd, const char *data)
-{
- int length = data ? strlen(data) : -1;
- writeData(fd, &length, sizeof(length));
- if(data)
- writeData(fd, data, sizeof(char) * length);
-}
-
-static int
-readData(int fd, void *buf, size_t count)
-{
- ssize_t nRead = read(fd, buf, count);
- if(nRead < 0)
- qDebug() << "read data failed: " << strerror(errno);
- return nRead;
-}
-
-static char *
-readString(int fd)
-{
- int length;
-
- if(readData(fd, &length, sizeof(length)) <= 0)
- return NULL;
- if(length <= 0)
- return NULL;
-
- char *value = (char *)malloc(sizeof(char) * (length + 1));
- readData(fd, value, length);
- value[length] = '\0';
-
- return value;
-}
-
-void AuthPAM::_authenticate(const char *userName)
-{
-// qDebug() << "authenticate " << userName;
-
- pam_handle_t *pamh = NULL;
- char *newUser;
- int ret;
- int authRet;
- struct pam_conv conv;
-
- conv.conv = pam_conversation;
- conv.appdata_ptr = NULL;
-
- ret = pam_start(PAM_SERVICE_NAME, userName, &conv, &pamh);
- if(ret != PAM_SUCCESS)
- {
- qDebug() << "failed to start PAM: " << pam_strerror(NULL, ret);
- }
-
- authRet = pam_authenticate(pamh, 0);
-
- ret = pam_get_item(pamh, PAM_USER, (const void **)&newUser);
- if(ret != PAM_SUCCESS)
- {
- pam_end(pamh, 0);
- qDebug() << "failed to get username";
- }
- free(newUser);
- newUser = NULL;
-// fprintf(stderr, "authentication result: %d\n", authRet);
-
- // 发送认证结果
- int authComplete = 1;
- writeData(toParent[1], (const void*)&authComplete, sizeof(authComplete));
- writeData(toParent[1], (const void *)&authRet, sizeof(authRet));
-// qDebug() << "--- 认证完成";
- _exit(EXIT_SUCCESS);
-}
-
-void AuthPAM::_respond(const PAM_RESPONSE *response)
-{
- for(int i = 0; i < messageList.size(); i++)
- {
- const PAM_RESPONSE *resp = &response[i];
- writeData(toChild[1], (const void *)&resp->resp_retcode,
- sizeof(resp->resp_retcode));
- writeString(toChild[1], resp->resp);
- }
-}
-
-
-static int
-pam_conversation(int msgLength, const struct pam_message **msg,
- PAM_RESPONSE **resp, void */*appData*/)
-{
- PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(msgLength,sizeof(PAM_RESPONSE));
-
- int authComplete = 0;
- writeData(toParent[1], (const void*)&authComplete, sizeof(authComplete));
- writeData(toParent[1], (const void*)&msgLength, sizeof(msgLength));
- //发送pam消息
- for(int i = 0; i < msgLength; i++)
- {
- const struct pam_message *m = msg[i];
- writeData(toParent[1], (const void *)&m->msg_style, sizeof(m->msg_style));
- writeString(toParent[1], m->msg);
- }
- //读取响应
- for(int i = 0; i < msgLength; i++)
- {
- PAM_RESPONSE *r = &response[i];
- readData(toChild[0], &r->resp_retcode, sizeof(r->resp_retcode));
- r->resp = readString(toChild[0]);
- }
- *resp = response;
- return PAM_SUCCESS;
-}
-
-void sigchld_handler(int signo)
-{
- if(signo == SIGCHLD)
- {
- ::waitpid(-1, NULL, WNOHANG);
- }
-}
diff --git a/checkUserPwdWithPAM/checkUserPwd/auth-pam.h b/checkUserPwdWithPAM/checkUserPwd/auth-pam.h
deleted file mode 100644
index 9497351..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/auth-pam.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
- *
- * 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, 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/>.
- *
-**/
-#ifndef AUTHPAM_H
-#define AUTHPAM_H
-#include "auth.h"
-#include <QSocketNotifier>
-#include <QList>
-
-#include <security/pam_appl.h>
-
-typedef struct pam_message PAM_MESSAGE;
-typedef struct pam_response PAM_RESPONSE;
-
-class AuthPAM : public Auth
-{
- Q_OBJECT
-public:
- AuthPAM(QObject *parent = nullptr);
-
- void authenticate(const QString &userName, const QString &userPwd);
- void stopAuth();
- void respond(const QString &response);
- bool isAuthenticated();
- bool isAuthenticating();
-
-private:
- void _authenticate(const char *userName);
- void _respond(const struct pam_response *response);
-
-private Q_SLOTS:
- void onSockRead();
-
-private:
- QString userName;
- pid_t pid;
- QSocketNotifier *notifier;
- int nPrompts;
- QStringList responseList;
- QList<PAM_MESSAGE> messageList;
- bool _isAuthenticated; //认证结果
- bool _isAuthenticating;
-};
-
-#endif // AUTHPAM_H
diff --git a/checkUserPwdWithPAM/checkUserPwd/auth.h b/checkUserPwdWithPAM/checkUserPwd/auth.h
deleted file mode 100644
index 22d9f23..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/auth.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
- *
- * 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, 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/>.
- *
-**/
-#ifndef AUTH_H
-#define AUTH_H
-
-#ifndef QT_NO_KEYWORDS
-#define QT_NO_KEYWORDS
-#endif
-
-#include <QObject>
-
-class Auth : public QObject
-{
- Q_OBJECT
-
- Q_ENUMS(PromptType MessageType)
-public:
- explicit Auth(QObject *parent = nullptr)
- : QObject(parent)
- {
-
- }
-
- enum PromptType {
- PromptTypeQuestion,
- PromptTypeSecret
- };
- enum MessageType {
- MessageTypeInfo,
- MessageTypeError
- };
-
-
-Q_SIGNALS:
- void showPrompt(const QString &prompt, Auth::PromptType type);
- void showMessage(const QString &message, Auth::MessageType type);
- void authenticateComplete();
-
-public:
- virtual void authenticate(const QString &userName, const QString &userPwd) = 0;
- virtual void stopAuth() = 0;
- virtual void respond(const QString &response) = 0;
- virtual bool isAuthenticating() = 0;
- virtual bool isAuthenticated() = 0;
-};
-
-#endif // AUTH_H
diff --git a/checkUserPwdWithPAM/checkUserPwd/checkUserPwd.pro b/checkUserPwdWithPAM/checkUserPwd/checkUserPwd.pro
deleted file mode 100644
index 8037587..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/checkUserPwd.pro
+++ /dev/null
@@ -1,38 +0,0 @@
-QT += core
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-TARGET = checkUserPwd
-TEMPLATE = app
-
-CONFIG += c++11
-
-# The following define makes your compiler emit warnings if you use
-# any Qt feature that has been marked deprecated (the exact warnings
-# depend on your compiler). Please consult the documentation of the
-# deprecated API in order to know how to port your code away from it.
-DEFINES += QT_DEPRECATED_WARNINGS
-
-# You can also make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-# You can also select to disable deprecated APIs only up to a certain version of Qt.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-LIBS += -lpam
-
-SOURCES += \
- auth-pam.cpp \
- main.cpp \
- widget.cpp
-
-HEADERS += \
- auth-pam.h \
- auth.h \
- widget.h
-
-target.source += $$TARGET
-target.path = /usr/bin
-
-
-INSTALLS += \
- target \
diff --git a/checkUserPwdWithPAM/checkUserPwd/main.cpp b/checkUserPwdWithPAM/checkUserPwd/main.cpp
deleted file mode 100644
index 8f7dfc7..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/main.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "widget.h"
-
-#include <QCoreApplication>
-
-#include <QDebug>
-
-int main(int argc, char *argv[])
-{
- QCoreApplication a(argc, argv);
-
-
- Widget w;
- if (argc == 3){
- w.pwdCheck(argv[1], argv[2]);
- } else {
- return 1;
- }
-
- return a.exec();
-}
diff --git a/checkUserPwdWithPAM/checkUserPwd/widget.cpp b/checkUserPwdWithPAM/checkUserPwd/widget.cpp
deleted file mode 100644
index 059333e..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/widget.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "widget.h"
-
-#include "auth-pam.h"
-
-#include <QDebug>
-
-
-Widget::Widget()
-{
-
- auth = new AuthPAM(this);
-
- accountlock = false;
-
- connect(auth, &Auth::showMessage, this, &Widget::onShowMessage);
- connect(auth, &Auth::showPrompt, this, &Widget::onShowPrompt);
- connect(auth, &Auth::authenticateComplete, this, &Widget::onAuthComplete);
-
-}
-
-Widget::~Widget()
-{
-
- auth->stopAuth();
-
- delete auth;
-}
-
-void Widget::pwdCheck(QString userName, QString userPwd){
- auth->authenticate(userName, userPwd);
-}
-
-void Widget::onShowMessage(const QString &message, Auth::MessageType type)
-{
-// qDebug() << "showMessage" << message;
- accountlock = true;
- printf("%s\n", message.toUtf8().data());
-}
-
-void Widget::onShowPrompt(const QString &prompt, Auth::PromptType type)
-{
-// qDebug() << "prompt: " << prompt;
-}
-
-void Widget::onAuthComplete()
-{
-
- if (!accountlock){
- if(auth->isAuthenticated()){
-// qDebug() << "Succes!\n";
-// printf("Succes!\n");
- } else {
- printf("Failed!\n");
-// qDebug() << "Failed!";
- }
- }
-
- exit(0);
-
-}
-
diff --git a/checkUserPwdWithPAM/checkUserPwd/widget.h b/checkUserPwdWithPAM/checkUserPwd/widget.h
deleted file mode 100644
index 86f0e8f..0000000
--- a/checkUserPwdWithPAM/checkUserPwd/widget.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef WIDGET_H
-#define WIDGET_H
-
-
-#include "auth-pam.h"
-
-
-class Widget : public QObject
-{
- Q_OBJECT
-
-public:
- Widget();
- ~Widget();
-
-public:
- void pwdCheck(QString userName, QString userPwd);
-
-private:
- Auth * auth;
-
- bool accountlock;
-
-private Q_SLOTS:
- void onShowMessage(const QString &message, Auth::MessageType type);
- void onShowPrompt(const QString &prompt, Auth::PromptType type);
- void onAuthComplete();
-};
-#endif // WIDGET_H
diff --git a/checkUserPwdWithPAM/checkUserPwdWithPAM.pro b/checkUserPwdWithPAM/checkUserPwdWithPAM.pro
index 9d6c015..97f51f0 100644
--- a/checkUserPwdWithPAM/checkUserPwdWithPAM.pro
+++ b/checkUserPwdWithPAM/checkUserPwdWithPAM.pro
@@ -1,7 +1,38 @@
-TEMPLATE = subdirs
+QT -= gui
-CONFIG += ordered
+TARGET = checkUserPwd
+TEMPLATE = app
-SUBDIRS = \
- childCheckPwdWithPAM \
- checkUserPwd \
+CONFIG += c++11
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+
+##加载gio库和gio-unix库
+CONFIG += link_pkgconfig \
+ C++11
+PKGCONFIG += gio-2.0 \
+ gio-unix-2.0 \
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+target.source += $$TARGET
+target.path = /usr/bin
+INSTALLS += \
+ target \
+
+
+SOURCES += \
+ main.cpp \
+ run-passwd.cpp
+
+HEADERS += \
+ run-passwd.h
diff --git a/checkUserPwdWithPAM/childCheckPwdWithPAM/childCheckPwdWithPAM.pro b/checkUserPwdWithPAM/childCheckPwdWithPAM/childCheckPwdWithPAM.pro
deleted file mode 100644
index c2f5532..0000000
--- a/checkUserPwdWithPAM/childCheckPwdWithPAM/childCheckPwdWithPAM.pro
+++ /dev/null
@@ -1,39 +0,0 @@
-QT -= core
-QT -= gui
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-TARGET = childCheckpwdwithPAM
-TEMPLATE = app
-
-CONFIG += c++11
-
-# The following define makes your compiler emit warnings if you use
-# any Qt feature that has been marked deprecated (the exact warnings
-# depend on your compiler). Please consult the documentation of the
-# deprecated API in order to know how to port your code away from it.
-DEFINES += QT_DEPRECATED_WARNINGS
-
-# You can also make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-# You can also select to disable deprecated APIs only up to a certain version of Qt.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-LIBS += -lpam
-
-SOURCES += \
- main.cpp
-
-HEADERS +=
-
-
-cf.files += ../conf/control-center
-cf.path = /etc/pam.d/
-
-target.source += $$TARGET
-target.path = /usr/bin
-
-
-INSTALLS += \
- cf \
- target \
diff --git a/checkUserPwdWithPAM/childCheckPwdWithPAM/main.cpp b/checkUserPwdWithPAM/childCheckPwdWithPAM/main.cpp
deleted file mode 100644
index ed9d883..0000000
--- a/checkUserPwdWithPAM/childCheckPwdWithPAM/main.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
- *
- * 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 2 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <wait.h>
-#include <fcntl.h>
-#include <security/pam_appl.h>
-#include <sys/mman.h>
-static int toParent = 0;
-static int fromChild = 0;
-
-typedef struct pam_message PAM_MESSAGE;
-typedef struct pam_response PAM_RESPONSE;
-
-static void
-writeData(int fd, const void *buf, ssize_t count)
-{
- if(write(fd, buf, count) != count)
- printf("write to parent failed: %s\n",strerror(errno));
-}
-
-static void
-writeString(int fd, const char *data)
-{
- int length = data ? strlen(data) : -1;
- writeData(fd, &length, sizeof(length));
- if(data)
- writeData(fd, data, sizeof(char) * length);
-}
-
-static int
-readData(int fd, void *buf, size_t count)
-{
- ssize_t nRead = read(fd, buf, count);
- if(nRead < 0)
- printf("read data failed: %s\n",strerror(errno));
- return nRead;
-}
-
-static char *
-readString(int fd)
-{
- int length;
-
- if(readData(fd, &length, sizeof(length)) <= 0)
- return NULL;
- if(length <= 0)
- return NULL;
-
- char *value = (char *)malloc(sizeof(char) * (length + 1));
- readData(fd, value, length);
- value[length] = '\0';
-
- return value;
-}
-
-static int
-pam_conversation(int msgLength, const struct pam_message **msg,
- PAM_RESPONSE **resp, void */*appData*/)
-{
- PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(msgLength,sizeof(PAM_RESPONSE));
-
- int authComplete = 0;
- writeData(toParent, (const void*)&authComplete, sizeof(authComplete));
- writeData(toParent, (const void*)&msgLength, sizeof(msgLength));
- //发送pam消息
- for(int i = 0; i < msgLength; i++)
- {
- const struct pam_message *m = msg[i];
- writeData(toParent, (const void *)&m->msg_style, sizeof(m->msg_style));
- writeString(toParent, m->msg);
- }
- //读取响应
- for(int i = 0; i < msgLength; i++)
- {
- PAM_RESPONSE *r = &response[i];
- readData(fromChild, &r->resp_retcode, sizeof(r->resp_retcode));
- r->resp = readString(fromChild);
- }
- *resp = response;
- return PAM_SUCCESS;
-}
-
-static void
-_authenticate(const char *userName)
-{
-// printf("authenticate %s\n",userName);
-
- pam_handle_t *pamh = NULL;
- char *newUser;
- int ret;
- int authRet;
- struct pam_conv conv;
-
- conv.conv = pam_conversation;
- conv.appdata_ptr = NULL;
-
- ret = pam_start("control-center", userName, &conv, &pamh);
- if(ret != PAM_SUCCESS)
- {
- printf("failed to start PAM: = %s\n", pam_strerror(NULL, ret));
- }
-
- authRet = pam_authenticate(pamh, 0);
-
- ret = pam_get_item(pamh, PAM_USER, (const void **)&newUser);
- if(ret != PAM_SUCCESS)
- {
- pam_end(pamh, 0);
- printf("failed to get username\n");
- }
- free(newUser);
- newUser = NULL;
-// fprintf(stderr, "authentication result: %d\n", authRet);
-
- // 发送认证结果
- int authComplete = 1;
- writeData(toParent, (const void*)&authComplete, sizeof(authComplete));
- writeData(toParent, (const void *)&authRet, sizeof(authRet));
-
- /* ---认证完成\n*/
- _exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char **argv)
-{
- if (argc != 4)
- {
- return EXIT_FAILURE;
- }
- toParent = atoi (argv[1]);
- fromChild = atoi (argv[2]);
- if (toParent == 0 || fromChild == 0)
- {
- printf ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
- return EXIT_FAILURE;
- }
- //mlockall (MCL_CURRENT | MCL_FUTURE);
- fcntl (toParent, F_SETFD, FD_CLOEXEC);
- fcntl (fromChild, F_SETFD, FD_CLOEXEC);
-
-
- _authenticate(argv[3]);
-
-}
diff --git a/checkUserPwdWithPAM/conf/control-center b/checkUserPwdWithPAM/conf/control-center
deleted file mode 100644
index 6af045a..0000000
--- a/checkUserPwdWithPAM/conf/control-center
+++ /dev/null
@@ -1,11 +0,0 @@
-@include common-auth
-auth optional pam_gnome_keyring.so
-
-
-#If you are using Arch,comment out the
-#above and use the following.
-
-#auth include system-auth
-#account include system-auth
-#password include system-auth
-#session include system-auth
diff --git a/checkUserPwdWithPAM/main.cpp b/checkUserPwdWithPAM/main.cpp
new file mode 100644
index 0000000..fd5cc94
--- /dev/null
+++ b/checkUserPwdWithPAM/main.cpp
@@ -0,0 +1,81 @@
+#include <QCoreApplication>
+
+#include <glib.h>
+#include "run-passwd.h"
+
+PasswdHandler *passwd_handler = NULL;
+
+static void auth_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);
+static void chpasswd_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);
+
+int main(int argc, char *argv[])
+{
+
+ if (argc != 3)
+ {
+ return -1;
+ }
+
+ QCoreApplication a(argc, argv);
+
+ passwd_handler = passwd_init ();
+
+ passwd_authenticate (passwd_handler, argv[1], auth_cb, argv[2]);
+
+ return a.exec();
+}
+
+static void
+auth_cb (PasswdHandler *passwd_handler,
+ GError *error,
+ gpointer user_data)
+{
+ char *secondary_text;
+ char * pwd = (char*) user_data;
+
+ if (error){
+ secondary_text = error->message;
+ printf("%s\n", secondary_text);
+ qApp->exit(1);
+ } else {
+ qApp->exit(1);
+ }
+
+}
+
+/**
+ * @brief chpasswd_cb
+ * @param passwd_handler
+ * @param error
+ * @param user_data
+ */
+static void
+chpasswd_cb (PasswdHandler *passwd_handler,
+ GError *error,
+ gpointer user_data)
+{
+// char *primary_text;
+ char *secondary_text;
+
+ if (!error) {
+ //finish_password_change (TRUE);
+// primary_text = "Success";
+ secondary_text = "";
+
+ printf("%s\n", secondary_text);
+
+ qApp->exit(0);
+ } else {
+// primary_text = "Failed";
+ secondary_text = error->message;
+
+ char ** lines = g_strsplit(secondary_text, "\n", -1);
+
+ printf("%s\n", lines[0]);
+
+ passwd_destroy (passwd_handler);
+
+ qApp->exit(1);
+ }
+
+}
diff --git a/checkUserPwdWithPAM/run-passwd.cpp b/checkUserPwdWithPAM/run-passwd.cpp
new file mode 100644
index 0000000..3b416ec
--- /dev/null
+++ b/checkUserPwdWithPAM/run-passwd.cpp
@@ -0,0 +1,704 @@
+
+
+/* qt会将glib里的signals成员识别为宏所以取消该宏
+ * 后面如果用到signals时使用Q_SIGNALS代替即可
+ **/
+#ifdef signals
+#undef signals
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#include "run-passwd.h"
+
+
+/* Buffer size for backend output */
+#define BUFSIZE 64
+
+/* Passwd states */
+//后端passwd的状态NONE应该是passwd还没有启动ERROR表示报错但还没退出
+typedef enum {
+ PASSWD_STATE_NONE, /* Passwd is not asking for anything */
+ PASSWD_STATE_AUTH, /* Passwd is asking for our current password */
+ PASSWD_STATE_NEW, /* Passwd is asking for our new password */
+ PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */
+ PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */
+} PasswdState;
+
+struct PasswdHandler {
+// GtkBuilder *ui;
+
+ const char *current_password;
+ const char *new_password;
+ const char *retyped_password;
+
+ /* Communication with the passwd program */
+ GPid backend_pid;
+
+ GIOChannel *backend_stdin;
+ GIOChannel *backend_stdout;
+
+ GQueue *backend_stdin_queue; /* Write queue to backend_stdin */
+
+ /* GMainLoop IDs */
+ guint backend_child_watch_id; /* g_child_watch_add (PID) */
+ guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */
+
+ /* State of the passwd program */
+ PasswdState backend_state;
+ gboolean changing_password;
+
+ PasswdCallback auth_cb;
+ gpointer auth_cb_data;
+
+ PasswdCallback chpasswd_cb;
+ gpointer chpasswd_cb_data;
+};
+
+//GQuark是一个guint32
+static GQuark
+passwd_error_quark (void)
+{
+ static GQuark q = 0;
+
+ //返回错误的标识码
+ if (q == 0) {
+ q = g_quark_from_static_string("passwd_error");
+ }
+
+ return q;
+}
+
+/* Error handling */
+#define PASSWD_ERROR (passwd_error_quark ())
+
+static void stop_passwd (PasswdHandler *passwd_handler);
+
+static void free_passwd_resources (PasswdHandler *passwd_handler);
+
+static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler);
+
+
+static void free_passwd_resources (PasswdHandler *passwd_handler)
+{
+ GError *error = NULL;
+
+ /* Remove the child watcher */
+ if (passwd_handler->backend_child_watch_id != 0) {
+
+ g_source_remove (passwd_handler->backend_child_watch_id);
+
+ passwd_handler->backend_child_watch_id = 0;
+ }
+
+
+ /* Close IO channels (internal file descriptors are automatically closed) */
+ if (passwd_handler->backend_stdin != NULL) {
+
+ if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) {
+ g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_io_channel_unref (passwd_handler->backend_stdin);
+ passwd_handler->backend_stdin = NULL;
+ }
+
+ if (passwd_handler->backend_stdout != NULL) {
+
+ if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) {
+ g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_io_channel_unref (passwd_handler->backend_stdout);
+
+ passwd_handler->backend_stdout = NULL;
+ }
+
+ /* Remove IO watcher */
+ if (passwd_handler->backend_stdout_watch_id != 0) {
+
+ g_source_remove (passwd_handler->backend_stdout_watch_id);
+
+ passwd_handler->backend_stdout_watch_id = 0;
+ }
+
+ /* Close PID */
+ //因为flag为G_SPAWN_DO_NOT_REAP_CHILD,所以child不会自动的被reap掉需要在子进程上free
+ if (passwd_handler->backend_pid != -1) {
+
+ g_spawn_close_pid (passwd_handler->backend_pid);
+
+ passwd_handler->backend_pid = -1;
+ }
+
+ /* Clear backend state */
+ passwd_handler->backend_state = PASSWD_STATE_NONE;
+}
+
+static void authenticate (PasswdHandler *passwd_handler)
+{
+ gchar *s;
+
+ s = g_strdup_printf ("%s\n", passwd_handler->current_password);
+ g_queue_push_tail (passwd_handler->backend_stdin_queue, s);
+}
+
+static void io_queue_pop (GQueue *queue, GIOChannel *channel)
+{
+ gchar *buf;
+ gsize bytes_written;
+ GError *error = NULL;
+
+ buf = (gchar *)g_queue_pop_head (queue);
+
+ if (buf != NULL) {
+ //将队列中的首元素写入到channel中
+ if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) {
+ g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message);
+ g_error_free (error);
+ }
+
+ /* Ensure passwords are cleared from memory */
+ //清除内存中的passwords
+ memset (buf, 0, strlen (buf));
+ g_free (buf);
+ }
+
+}
+
+static gboolean is_string_complete (gchar *str, ...)
+{
+ va_list ap;
+ gchar *arg;
+
+ if (strlen (str) == 0) {
+ return FALSE;
+ }
+
+ va_start (ap, str);
+
+ while ((arg = va_arg (ap, char *)) != NULL) {
+ if (g_strrstr (str, arg) != NULL) {
+ va_end (ap);
+ return TRUE;
+ }
+ }
+
+ va_end (ap);
+
+ return FALSE;
+}
+
+static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler)
+{
+ static GString *str = NULL; /* Persistent buffer */
+
+ gchar buf[BUFSIZE]; /* Temporary buffer */
+ gsize bytes_read;
+ GError *gio_error = NULL; /* Error returned by functions */
+ GError *error = NULL; /* Error sent to callbacks */
+
+ //GtkBuilder *dialog;
+
+ gboolean reinit = FALSE;
+
+ /* Initialize buffer */
+ if (str == NULL) {
+ str = g_string_new ("");
+ }
+
+ //dialog = passwd_handler->ui;
+ //buf将保存从channel中读取到的数据,bytes_read表示从buf中读取的数据长度
+ if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error)
+ != G_IO_STATUS_NORMAL) {
+ g_warning ("IO Channel read error: %s", gio_error->message);
+ g_error_free (gio_error);
+
+ return TRUE;
+ }
+
+ // g_warning("----------bytes_read=%d",bytes_read);
+ // g_warning("----------io_watch_buf=%s-------",buf);
+
+ str = g_string_append_len (str, buf, bytes_read);
+
+ /* In which state is the backend? */
+ switch (passwd_handler->backend_state) {
+ case PASSWD_STATE_AUTH:
+ /* Passwd is asking for our current password */
+
+ if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) {
+
+ if (g_strrstr (str->str, "New password: ") != NULL) {
+ /* Authentication successful */
+
+ passwd_handler->backend_state = PASSWD_STATE_NEW;
+
+ /* Trigger callback to update authentication status */
+ if (passwd_handler->auth_cb)
+ passwd_handler->auth_cb (passwd_handler,
+ NULL,
+ passwd_handler->auth_cb_data);
+
+ } else {
+ /* Authentication failed */
+
+ error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
+ "Authentication token manipulation error!");
+
+ passwd_handler->changing_password = FALSE;
+
+ /* This error can happen both while authenticating or while changing password:
+ * if chpasswd_cb is set, this means we're already changing password */
+ if (passwd_handler->chpasswd_cb)
+ passwd_handler->chpasswd_cb (passwd_handler,
+ error,
+ passwd_handler->auth_cb_data);
+ else if (passwd_handler->auth_cb)
+ passwd_handler->auth_cb (passwd_handler,
+ error,
+ passwd_handler->auth_cb_data);
+
+ g_error_free (error);
+ }
+
+ reinit = TRUE;
+ }
+ break;
+ case PASSWD_STATE_NEW:
+ /* Passwd is asking for our new password */
+
+ if (is_string_complete (str->str, "assword: ", NULL)) {
+ /* Advance to next state */
+ passwd_handler->backend_state = PASSWD_STATE_RETYPE;
+
+ /* Pop retyped password from queue and into IO channel */
+ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+
+ reinit = TRUE;
+ }
+ break;
+ case PASSWD_STATE_RETYPE:
+ /* Passwd is asking for our retyped new password */
+
+ // if (is_string_complete (str->str,
+ // "successfully",
+ // "short",
+ // "longer",
+ // "palindrome",
+ // "dictionary",
+ // "simple",
+ // "simplistic",
+ // "similar",
+ // "different",
+ // "case",
+ // "wrapped",
+ // "recovered",
+ // "recent",
+ // "unchanged",
+ // "match",
+ // "1 numeric or special",
+ // "failure",
+ // "length",
+ // NULL)) {
+ if (TRUE){
+
+ if (g_strrstr (str->str, "successfully") != NULL) {
+ /* Hooray! */
+
+ /* Trigger callback to update status */
+ if (passwd_handler->chpasswd_cb)
+ passwd_handler->chpasswd_cb (passwd_handler,
+ NULL,
+ passwd_handler->chpasswd_cb_data);
+ }
+ else {
+ /* Ohnoes! */
+
+ if (g_strrstr (str->str, "recovered") != NULL) {
+ /* What does this indicate?
+ * "Authentication information cannot be recovered?" from libpam? */
+ error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
+ str->str);
+ }/* else if (g_strrstr (str->str, "short") != NULL ||
+ g_strrstr (str->str, "longer") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "New password length is too short!");
+ } else if (g_strrstr (str->str, "palindrome") != NULL ||
+ g_strrstr (str->str, "simple") != NULL ||
+ g_strrstr (str->str, "simplistic") != NULL ||
+ g_strrstr (str->str, "dictionary") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "The new password is too simple!");
+ } else if (g_strrstr (str->str, "similar") != NULL ||
+ g_strrstr (str->str, "different") != NULL ||
+ g_strrstr (str->str, "case") != NULL ||
+ g_strrstr (str->str, "wrapped") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "The new password is too similar to the old one!");
+ } else if (g_strrstr (str->str, "1 numeric or special") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "The new password must contain numbers or special characters!");
+ } else if (g_strrstr (str->str, "unchanged") != NULL ||
+ g_strrstr (str->str, "match") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "The new password is the same as the old one!");
+ } else if (g_strrstr (str->str, "recent") != NULL) {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+ "The new password has been used recently!");
+ } else if (g_strrstr (str->str, "failure") != NULL) {
+ //Authentication failure
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
+ "Your password has been changed after you verify!");
+ } */else {
+ error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
+ "Unknown error");
+ }
+
+ /* At this point, passwd might have exited, in which case
+ * child_watch_cb should clean up for us and remove this watcher.
+ * On some error conditions though, passwd just re-prompts us
+ * for our new password. */
+ passwd_handler->backend_state = PASSWD_STATE_ERR;
+
+ passwd_handler->changing_password = FALSE;
+
+ /* Trigger callback to update status */
+ if (passwd_handler->chpasswd_cb)
+ passwd_handler->chpasswd_cb (passwd_handler,
+ error,
+ passwd_handler->chpasswd_cb_data);
+
+ g_error_free (error);
+
+ }
+
+ reinit = TRUE;
+
+ /* child_watch_cb should clean up for us now */
+ }
+ break;
+ case PASSWD_STATE_NONE:
+ /* Passwd is not asking for anything yet */
+ if (is_string_complete (str->str, "assword: ", NULL)) {
+
+ /* If the user does not have a password set,
+ * passwd will immediately ask for the new password,
+ * so skip the AUTH phase */
+ if (is_string_complete (str->str, "new", "New", NULL)) {
+ gchar *pw;
+
+ passwd_handler->backend_state = PASSWD_STATE_NEW;
+
+ /* since passwd didn't ask for our old password
+ * in this case, simply remove it from the queue */
+ pw = (gchar *)g_queue_pop_head (passwd_handler->backend_stdin_queue);
+ g_free (pw);
+
+ /* Pop the IO queue, i.e. send new password */
+ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+ } else {
+
+ passwd_handler->backend_state = PASSWD_STATE_AUTH;
+
+ /* Pop the IO queue, i.e. send current password */
+ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+ }
+
+ reinit = TRUE;
+ }
+ break;
+ default:
+ /* Passwd has returned an error */
+ reinit = TRUE;
+ break;
+ }
+
+ if (reinit) {
+ g_string_free (str, TRUE);
+ str = NULL;
+ }
+
+ /* Continue calling us */
+ return TRUE;
+}
+
+/* Child watcher */
+static void child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler)
+{
+ //子进程正常结束为非0
+ if (WIFEXITED (status)) {
+ //取得子进程正常退出时返回的结束代码
+ if (WEXITSTATUS (status) >= 255) {
+ g_warning ("Child exited unexpectedly");
+ }
+ }
+
+ free_passwd_resources (passwd_handler);
+}
+
+static void stop_passwd (PasswdHandler *passwd_handler)
+{
+ /* This is the standard way of returning from the dialog with passwd.
+ * If we return this way we can safely kill passwd as it has completed
+ * its task.
+ */
+
+ if (passwd_handler->backend_pid != -1) {
+ kill (passwd_handler->backend_pid, 9);
+ }
+
+ /* We must run free_passwd_resources here and not let our child
+ * watcher do it, since it will access invalid memory after the
+ * dialog has been closed and cleaned up.
+ *
+ * If we had more than a single thread we'd need to remove
+ * the child watch before trying to kill the child.
+ */
+ free_passwd_resources (passwd_handler);
+}
+
+static gboolean spawn_passwd (PasswdHandler *passwd_handler, GError **error)
+{
+ gchar *argv[2];
+ gchar *envp[1];
+ gint my_stdin, my_stdout, my_stderr;
+
+ argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */
+ argv[1] = NULL;
+
+ envp[0] = NULL; /* If we pass an empty array as the environment,
+ * will the childs environment be empty, and the
+ * locales set to the C default? From the manual:
+ * "If envp is NULL, the child inherits its
+ * parent'senvironment."
+ * If I'm wrong here, we somehow have to set
+ * the locales here.
+ */
+
+ //创建一个管道,进行通信,子进程执行passwd命令
+ if (!g_spawn_async_with_pipes (NULL, /* Working directory */
+ argv, /* Argument vector */
+ envp, /* Environment */
+ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */
+ NULL, /* Child setup 在子进程调用exec()之前,该函数会被调用)*/
+ NULL, /* Data to child setup */
+ &passwd_handler->backend_pid, /* PID */
+ &my_stdin, /* Stdin */
+ &my_stdout, /* Stdout */
+ &my_stderr, /* Stderr */
+ error)) { /* GError */
+
+ /* An error occured */
+ free_passwd_resources (passwd_handler);
+
+ return FALSE;
+ }
+
+ /* 2>&1 */
+ //复制文件描述符也就是将stderr重定向到stdout
+ if (dup2 (my_stderr, my_stdout) == -1) {
+ /* Failed! */
+ g_set_error_literal (error,
+ PASSWD_ERROR,
+ PASSWD_ERROR_BACKEND,
+ strerror (errno));
+
+ /* Clean up */
+ stop_passwd (passwd_handler);
+
+ return FALSE;
+ }
+
+ /* Open IO Channels */
+ //指定一个文件描述符创建一个IO Channel默认使用UTF-8编码格式
+ passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin);
+ passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout);
+
+ /* Set raw encoding */
+ /* Set nonblocking mode */
+ //设置通道的编码方式为NULL,设置为非阻塞的方式
+ if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
+
+ /* Clean up */
+ stop_passwd (passwd_handler);
+ return FALSE;
+ }
+
+ /* Turn off buffering */
+ //只有通道的编码方式为NULL才能设置缓冲状态为FASLE其他任何编码通道必须被缓冲这里是为了清掉上次的密码
+ g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE);
+ g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE);
+
+ /* Add IO Channel watcher */
+ //当IO通道的状态为G_IO_IN(从IO通道读数据时)或者G_IO_PRI(读紧急数据时)时调用io_watch_stdout
+ passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout,
+ G_IO_IN /*| G_IO_PRI*/,
+ (GIOFunc) io_watch_stdout, passwd_handler);
+
+ /* Add child watcher */
+ //在指定pid的进程退出时调用child_watch_cb(),进行错误检查,以及资源回收
+ passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler);
+
+ /* Success! */
+
+ return TRUE;
+}
+
+static void update_password (PasswdHandler *passwd_handler)
+{
+ gchar *s;
+
+ s = g_strdup_printf ("%s\n", passwd_handler->new_password);
+
+ g_queue_push_tail (passwd_handler->backend_stdin_queue, s);
+ /* We need to allocate new space because io_queue_pop() g_free()s
+ * every element of the queue after it's done */
+ g_queue_push_tail (passwd_handler->backend_stdin_queue, g_strdup (s));
+}
+
+gboolean passwd_change_password (PasswdHandler *passwd_handler,
+ const char *new_password,
+ PasswdCallback cb,
+ const gpointer user_data)
+{
+ GError *error = NULL;
+
+ passwd_handler->changing_password = TRUE;
+
+ passwd_handler->new_password = new_password;
+ passwd_handler->chpasswd_cb = cb;
+ passwd_handler->chpasswd_cb_data = user_data;
+
+ /* Stop passwd if an error occured and it is still running */
+ if (passwd_handler->backend_state == PASSWD_STATE_ERR) {
+
+ /* Stop passwd, free resources */
+ stop_passwd (passwd_handler);
+ }
+
+ /* Check that the backend is still running, or that an error
+ * has occured but it has not yet exited */
+ if (passwd_handler->backend_pid == -1) {
+ /* If it is not, re-run authentication */
+
+ /* Spawn backend */
+ stop_passwd (passwd_handler);
+
+ if (!spawn_passwd (passwd_handler, &error)) {
+ g_error_free (error);
+
+ return FALSE;
+ }
+
+ /* Add current and new passwords to queue */
+ //将当前的密码和新密码入队,新密码会入队两次
+ authenticate (passwd_handler);
+ update_password (passwd_handler);
+ } else {
+ /* Only add new passwords to queue */
+ update_password (passwd_handler);
+ }
+
+ /* Pop new password through the backend. If user has no password, popping the queue
+ would output current password, while 'passwd' is waiting for the new one. So wait
+ for io_watch_stdout() to remove current password from the queue, and output
+ the new one for us.*/
+ //如果密码为空将新进队列的密码作为current_passwd弹出
+ if (passwd_handler->current_password)
+ {
+ io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+ }
+
+ /* Our IO watcher should now handle the rest */
+
+ return TRUE;
+}
+
+void passwd_authenticate (PasswdHandler *passwd_handler,
+ const char *current_password,
+ PasswdCallback cb,
+ const gpointer user_data)
+{
+ GError *error = NULL;
+
+ /* Don't stop if we've already started chaging password */
+ if (passwd_handler->changing_password)
+ return;
+
+ /* Clear data from possible previous attempts to change password */
+ passwd_handler->new_password = NULL;
+ passwd_handler->chpasswd_cb = NULL;
+ passwd_handler->chpasswd_cb_data = NULL;
+ g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL);
+ g_queue_clear (passwd_handler->backend_stdin_queue);
+
+ passwd_handler->current_password = current_password;
+ passwd_handler->auth_cb = cb;
+ passwd_handler->auth_cb_data = user_data;
+
+ /* Spawn backend */
+ //重新启动后台passwd
+ stop_passwd (passwd_handler);
+
+ if (!spawn_passwd (passwd_handler, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ //将current passwd从尾部插入队列
+ authenticate (passwd_handler);
+
+ /* Our IO watcher should now handle the rest */
+}
+
+
+PasswdHandler * passwd_init ()
+{
+ PasswdHandler *passwd_handler;
+
+ passwd_handler = g_new0 (PasswdHandler, 1);
+
+ /* Initialize backend_pid. -1 means the backend is not running */
+ //-1代表后台还没启动
+ passwd_handler->backend_pid = -1;
+
+ /* Initialize IO Channels */
+ passwd_handler->backend_stdin = NULL;
+ passwd_handler->backend_stdout = NULL;
+
+ /* Initialize write queue */
+ passwd_handler->backend_stdin_queue = g_queue_new ();
+
+ /* Initialize watchers */
+ passwd_handler->backend_child_watch_id = 0;
+ passwd_handler->backend_stdout_watch_id = 0;
+
+ /* Initialize backend state */
+ passwd_handler->backend_state = PASSWD_STATE_NONE;
+ passwd_handler->changing_password = FALSE;
+
+ return passwd_handler;
+}
+
+
+void passwd_destroy (PasswdHandler *passwd_handler)
+{
+ g_queue_free (passwd_handler->backend_stdin_queue);
+ stop_passwd (passwd_handler);
+ g_free (passwd_handler);
+}
diff --git a/checkUserPwdWithPAM/run-passwd.h b/checkUserPwdWithPAM/run-passwd.h
new file mode 100644
index 0000000..513d05b
--- /dev/null
+++ b/checkUserPwdWithPAM/run-passwd.h
@@ -0,0 +1,34 @@
+#ifndef RUNPASSWD_H
+#define RUNPASSWD_H
+
+
+struct PasswdHandler;
+
+typedef struct PasswdHandler PasswdHandler;
+
+typedef void (*PasswdCallback) (PasswdHandler * passwd_handler, GError * error, const gpointer user_data);
+
+/* Error codes */
+typedef enum {
+ PASSWD_ERROR_REJECTED, /* New password is not secure enough */
+ PASSWD_ERROR_AUTH_FAILED, /* Wrong old password, or PAM failure */
+ PASSWD_ERROR_REAUTH_FAILED, /* Password has changed since first authentication */
+ PASSWD_ERROR_BACKEND, /* Backend error */
+ PASSWD_ERROR_UNKNOWN /* General error */
+} PasswdError;
+
+PasswdHandler *passwd_init ();
+
+void passwd_destroy (PasswdHandler *passwd_handler);
+
+void passwd_authenticate (PasswdHandler *passwd_handler,
+ const char *current_password,
+ PasswdCallback cb,
+ gpointer user_data);
+
+gboolean passwd_change_password (PasswdHandler *passwd_handler,
+ const char *new_password,
+ PasswdCallback cb,
+ const gpointer user_data);
+
+#endif // RUNPASSWD_H
diff --git a/plugins/account/userinfo/changeuserpwd.cpp b/plugins/account/userinfo/changeuserpwd.cpp
index 95f27c9..14acc58 100644
--- a/plugins/account/userinfo/changeuserpwd.cpp
+++ b/plugins/account/userinfo/changeuserpwd.cpp
@@ -402,7 +402,6 @@ void ChangeUserPwd::setupConnect(){
}
char * cmd = g_strdup_printf("/usr/bin/changeuserpwd %s %s", currentPwd.toLatin1().data(), newPwd.toLatin1().data());
-
FILE *stream = NULL;
char buf[256] = {0};
@@ -427,7 +426,7 @@ void ChangeUserPwd::setupConnect(){
}
} else {
- if (re.contains("Failed")){
+ if (re.contains("Authentication token manipulation error!")){
curPwdTip = tr("Authentication failed, input authtok again!");
}
diff --git a/plugins/account/userinfo/pwdcheckthread.cpp b/plugins/account/userinfo/pwdcheckthread.cpp
index 37e9af6..2fbb0e9 100644
--- a/plugins/account/userinfo/pwdcheckthread.cpp
+++ b/plugins/account/userinfo/pwdcheckthread.cpp
@@ -37,7 +37,7 @@ void PwdCheckThread::run(){
}
}
- snprintf(command, 128, "/usr/bin/checkUserPwd %s %s", ba1.data(), currentPwd.toLatin1().data());
+ snprintf(command, 128, "/usr/bin/checkUserPwd %s %s", currentPwd.toLatin1().data(), ba1.data());
if ((stream = popen(command, "r")) != NULL){
diff --git a/translate_generation.sh b/translate_generation.sh
index c971497..bfb9c88 100755
--- a/translate_generation.sh
+++ b/translate_generation.sh
@@ -7,7 +7,7 @@ version=(`echo $ID`)
for ts in "${ts_list[@]}"
do
printf "\nprocess ${ts}\n"
- if [ "$version" == "fedora" ] || [ "$version" == "opensuse-leap" ] || [ "$version" == "opensuse-tumbleweed" ] || [ "$version" == "openEuler" ];then
+ if [ "$version" == "fedora" ] || [ "$version" == "opensuse-leap" ] || [ "$version" == "opensuse-tumbleweed" ] || [ "$version" == "openEuler" ] || [ "$version" == "kylin" ];then
lrelease-qt5 "${ts}"
else
lrelease "${ts}"
--
2.36.1