From 161bd1abd19dfa9d0c0ea51dca224b3f5c540615 Mon Sep 17 00:00:00 2001 From: huayadong Date: Fri, 9 Jun 2023 16:38:22 +0800 Subject: [PATCH] fix password changes for this user and for other use (cherry picked from commit 648ac5e06e1c18ae64a3906cdf7449c3960fc622) --- ...nges-for-this-user-and-for-other-use.patch | 1894 +++++++++++++++++ ukui-control-center.spec | 11 +- 2 files changed, 1901 insertions(+), 4 deletions(-) create mode 100644 ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch diff --git a/ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch b/ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch new file mode 100644 index 0000000..17ae292 --- /dev/null +++ b/ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch @@ -0,0 +1,1894 @@ +From d345bc5b0688c93f1942e38a0bf03eca9dbb0001 Mon Sep 17 00:00:00 2001 +From: huayadong +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 . +- * +-**/ +-#include "auth-pam.h" +-#include +-#include +-#include +-#include +-#include +- +-#include +- +- +-#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 = "<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 . +- * +-**/ +-#ifndef AUTHPAM_H +-#define AUTHPAM_H +-#include "auth.h" +-#include +-#include +- +-#include +- +-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 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 . +- * +-**/ +-#ifndef AUTH_H +-#define AUTH_H +- +-#ifndef QT_NO_KEYWORDS +-#define QT_NO_KEYWORDS +-#endif +- +-#include +- +-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 +- +-#include +- +-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 +- +- +-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 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-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 ++ ++#include ++#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 ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 + diff --git a/ukui-control-center.spec b/ukui-control-center.spec index c44258f..50a4ce7 100644 --- a/ukui-control-center.spec +++ b/ukui-control-center.spec @@ -1,6 +1,6 @@ Name: ukui-control-center Version: 3.1.2 -Release: 17 +Release: 18 Summary: utilities to configure the UKUI desktop License: GPL-2+ URL: http://www.ukui.org @@ -18,6 +18,7 @@ Patch13: 0013-Fix-terminal-garbled-characters-when-not-root-user-change-l Patch14: 0014-fix-memorysize-of-aboutinfo.patch Patch15: fix-changeOtherUserPasswd-critical-vulnerabilities.patch Patch16: fix-createuser-critical-vulnerabilities.patch +Patch17: ukui-control-center-3.1.2-fix-password-changes-for-this-user-and-for-other-use.patch BuildRequires: qt5-qtsvg-devel BuildRequires: gsettings-qt-devel @@ -102,8 +103,8 @@ glib-compile-schemas /usr/share/glib-2.0/schemas/ &> /dev/null ||: systemctl enable ukui-group-manager.service systemctl start ukui-group-manager.service -chown root:root /usr/bin/checkUserPwd -chmod u+s /usr/bin/checkUserPwd +#chown root:root /usr/bin/checkUserPwd +#chmod u+s /usr/bin/checkUserPwd sed -i "1iauth sufficient pam_succeed_if.so user ingroup nopasswdlogin" /etc/pam.d/lightdm groupadd nopasswdlogin &> /dev/null ||: @@ -121,7 +122,6 @@ rm -rf $RPM_BUILD_ROOT %files %{_sysconfdir}/dbus-1/system.d/* -%{_sysconfdir}/pam.d/* /lib/systemd/system/* %{_bindir}/* %{_datadir}/applications/* @@ -143,6 +143,9 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Fri Jun 09 2023 huayadong - 3.1.2-18 +- fix password changes for this user and for other use + * Fri May 26 2023 peijiankang - 3.1.2-17 - sync from upstream 3.1.2+2023-0403