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