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

