Import Upstream version 3.20.0.2022.0601

This commit is contained in:
谢炜 2022-06-02 16:28:06 +08:00
commit e5e1816df7
1232 changed files with 187425 additions and 0 deletions

142
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,142 @@
name: Check build
on:
push:
branches:
- dev-3.1
pull_request:
branches:
- dev-3.1
jobs:
# archlinux-latest:
# name: on Archlinux Latest
# runs-on: ubuntu-20.04
# container: docker.io/library/archlinux:latest
# steps:
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Refresh pacman repository and force upgrade
# run: pacman -Syyu --noconfirm
# - name: Install build dependencies
# run: pacman -S --noconfirm base-devel qt5-base gsettings-qt kwindowsystem poppler-qt5 qt5-x11extras glib2 qt5-tools pkg-config kwidgetsaddons kconfig kconfigwidgets kscreen qt5-svg libmatekbd qt5-x11extras libxklavier qt5-declarative libmatemixer libqtxdg qt5-multimedia libxml2 libcanberra mate-desktop libxkbcommon libxkbfile ki18n kguiaddons kcoreaddons boost glibc bluez-qt
# - name: QMake configure & Make
# run: |
# mkdir build;
# cd build;
# qmake-qt5 ..;
# make -j$(nproc);
# debian-sid:
# name: on Debian Sid
# runs-on: ubuntu-20.04
# container: docker.io/library/debian:sid
# env:
# DEBIAN_FRONTEND: noninteractive
# steps:
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Update apt repository
# run: apt-get update -y
# - name: Install build dependencies
# run: apt-get install -y build-essential qt5-qmake qttools5-dev-tools pkg-kde-tools pkg-config libkf5widgetsaddons-dev libkf5config-dev libkf5configwidgets-dev libkf5screen-dev debhelper-compat libqt5svg5-dev libgsettings-qt-dev libglib2.0-dev libmatekbd-dev libqt5x11extras5-dev libxklavier-dev qtdeclarative5-dev libdconf-dev libmatemixer-dev libqt5xdg-dev qtmultimedia5-dev libxml2-dev libcanberra-dev libmate-desktop-dev libxkbcommon-dev libxkbfile-dev libkf5i18n-dev libkf5windowsystem-dev libkf5guiaddons-dev libkf5coreaddons-dev libboost-dev libxcb-xkb-dev libpolkit-qt5-1-dev libpulse-dev libkf5bluezqt-dev
# - name: QMake configure & Make
# run: |
# mkdir build;
# cd build;
# qmake ..;
# make -j$(nproc);
# fedora-latest:
# name: on Fedora Latest
# runs-on: ubuntu-20.04
# container: docker.io/library/fedora:latest
# steps:
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Install build dependencies
# run: dnf install --refresh -y which gcc gcc-c++ make cmake cmake-rpm-macros autoconf automake intltool rpm-build qt5-rpm-macros qt5-qtbase-devel qt5-qtsvg-devel gsettings-qt-devel glib2-devel qt5-qtx11extras-devel libmatekbd-devel libxklavier-devel kf5-kconfigwidgets-devel kf5-kconfig-devel qt5-qtdeclarative-devel dconf-devel redshift edid-decode libmatemixer-devel libqtxdg-devel qt5-qtmultimedia-devel libxml2-devel libkscreen-qt5-devel kf5-ki18n-devel libcanberra-devel libXi-devel mate-desktop-devel libxkbcommon-devel libxkbfile-devel qt5-linguist kf5-kwindowsystem-devel kf5-kguiaddons-devel kf5-kcoreaddons-devel boost-devel libxcb-devel xcb-util-devel polkit-qt5-1-devel kf5-bluez-qt-devel
# - name: QMake configure & Make
# run: |
# ln -s /usr/bin/lrelease-qt5 /usr/bin/lrelease;
# mkdir build;
# cd build;
# qmake-qt5 ..;
# make -j$(nproc);
# fedora-rawhide:
# name: on Fedora Rawhide
# runs-on: ubuntu-20.04
# container: docker.io/library/fedora:rawhide
# steps:
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Install build dependencies
# run: dnf install --refresh --nogpg -y which gcc gcc-c++ make cmake cmake-rpm-macros autoconf automake intltool rpm-build qt5-rpm-macros qt5-qtbase-devel qt5-qtsvg-devel gsettings-qt-devel glib2-devel qt5-qtx11extras-devel libmatekbd-devel libxklavier-devel kf5-kconfigwidgets-devel kf5-kconfig-devel qt5-qtdeclarative-devel dconf-devel redshift edid-decode libmatemixer-devel libqtxdg-devel qt5-qtmultimedia-devel libxml2-devel libkscreen-qt5-devel kf5-ki18n-devel libcanberra-devel libXi-devel mate-desktop-devel libxkbcommon-devel libxkbfile-devel qt5-linguist kf5-kwindowsystem-devel kf5-kguiaddons-devel kf5-kcoreaddons-devel boost-devel libxcb-devel xcb-util-devel polkit-qt5-1-devel kf5-bluez-qt-devel
# - name: QMake configure & Make
# run: |
# ln -s /usr/bin/lrelease-qt5 /usr/bin/lrelease;
# mkdir build;
# cd build;
# qmake-qt5 ..;
# make -j$(nproc);
# opensuse-tumbleweed:
# name: on openSUSE Tumbleweed
# runs-on: ubuntu-20.04
# container: opensuse/tumbleweed:latest
# steps:
# - name: Install source checkout utils
# run: zypper -n install tar git
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Install build dependencies
# run: zypper -n install atk-devel at-spi2-atk-devel at-spi2-core-devel cairo-devel cmake cmake-full cmake-man dbus-1-devel dconf-devel extra-cmake-modules extra-cmake-modules-doc fontconfig-devel freetype2-devel fribidi-devel gcc10-c++ gcc-c++ gdk-pixbuf-devel gettext-its-gtk4 glib2-devel graphite2-devel gsettings-qt-devel gtk3-devel harfbuzz-devel kauth-devel kcodecs-devel kconfig-devel kconfigwidgets-devel kcoreaddons-devel kf5-filesystem ki18n-devel kwidgetsaddons-devel kwindowsystem-devel libblkid-devel libbrotli-devel libbz2-devel libcairo-script-interpreter2 libcanberra-devel libdatrie-devel libdrm-devel libepoxy-devel libexpat-devel libffi-devel libglvnd-devel libharfbuzz-gobject0 libharfbuzz-subset0 libicu-devel libjsoncpp24 libkscreen2-devel libmatekbd-devel libmatemixer-devel libmount-devel libpcre16-0 libpcrecpp0 libpcreposix0 libpixman-1-0-devel libpng16-compat-devel libpng16-devel libpulse-devel libQt5Concurrent-devel libQt5Core-devel libQt5DBus-devel libQt5Gui-devel libqt5-linguist libQt5Network-devel libQt5PrintSupport-devel libqt5-qtbase-common-devel libqt5-qtdeclarative-devel libqt5-qtdeclarative-tools libqt5-qtmultimedia-devel libqt5-qtsvg-devel libqt5-qtx11extras-devel libQt5Sql-devel libQt5Test-devel libQt5Widgets-devel libQt5Xml-devel librhash0 libselinux-devel libsepol-devel libstdc++6-devel-gcc10 libstdc++-devel libthai-devel libuuid-devel libX11-devel libXau-devel libxcb-devel libxcb-screensaver0 libxcb-xf86dri0 libxcb-xtest0 libxcb-xvmc0 libXcomposite-devel libXcursor-devel libXdamage-devel libXext-devel libXfixes-devel libXft-devel libXi-devel libXinerama-devel libxkbcommon-devel libxklavier-devel libxml2-devel libXrandr-devel libXrender-devel libXtst-devel mate-desktop-devel Mesa-KHR-devel Mesa-libEGL-devel Mesa-libGL-devel ncurses-devel pango-devel pcre-devel readline-devel startup-notification-devel tack typelib-1_0-Atk-1_0 typelib-1_0-Atspi-2_0 typelib-1_0-GdkPixbuf-2_0 typelib-1_0-GdkPixdata-2_0 typelib-1_0-Gtk-3_0 typelib-1_0-HarfBuzz-0_0 typelib-1_0-Pango-1_0 typelib-1_0-Xkl-1_0 vulkan-devel vulkan-headers wayland-devel wayland-protocols-devel xorgproto-devel xz-devel zlib-devel libKF5Screen7 libkscreen2-plugin libpulse0 libpulse-mainloop-glib0 pulseaudio pulseaudio-bash-completion pulseaudio-module-bluetooth pulseaudio-module-gsettings pulseaudio-module-x11 pulseaudio-module-zeroconf pulseaudio-utils extra-cmake-modules-doc libpng16-compat-devel kguiaddons-devel libpwquality1 libxkbcommon-devel libxkbfile-devel libpolkit-qt5-1-devel 'libboost*-devel' bluez-qt-devel
# - name: QMake configure & Make
# run: |
# ln -s /usr/bin/lrelease-qt5 /usr/bin/lrelease;
# mkdir build;
# cd build;
# qmake-qt5 ..;
# make -j$(nproc);
ubuntu-latest:
name: on Ubuntu Latest
runs-on: ubuntu-20.04
container: docker.io/library/ubuntu:latest
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Checkout ukui-control-center source code
uses: actions/checkout@v2
- name: Update apt repository
run: apt-get update -y
- name: Install build dependencies
run: apt-get install -y build-essential qt5-default qttools5-dev-tools pkg-kde-tools pkg-config libkf5widgetsaddons-dev libkf5config-dev libkf5configwidgets-dev libkf5screen-dev debhelper-compat libqt5svg5-dev libgsettings-qt-dev libglib2.0-dev libmatekbd-dev libqt5x11extras5-dev libxklavier-dev qtdeclarative5-dev libdconf-dev libmatemixer-dev libqt5xdg-dev qtmultimedia5-dev libxml2-dev libcanberra-dev libmate-desktop-dev libxkbcommon-dev libxkbfile-dev libkf5i18n-dev libkf5windowsystem-dev libkf5guiaddons-dev libkf5coreaddons-dev libboost-dev libxcb-xkb-dev libpolkit-qt5-1-dev libkf5bluezqt-dev libudev-dev xserver-xorg-dev libupower-glib-dev libpam0g-dev libkf5xmlgui-dev libkf5globalaccel-dev
- name: QMake configure & Make
run: |
mkdir build;
cd build;
qmake ..;
make -j$(nproc);
# ubuntu-rolling:
# name: on Ubuntu Rolling
# runs-on: ubuntu-20.04
# container: docker.io/library/ubuntu:rolling
# env:
# DEBIAN_FRONTEND: noninteractive
# steps:
# - name: Checkout ukui-control-center source code
# uses: actions/checkout@v2
# - name: Update apt repository
# run: apt-get update -y
# - name: Install build dependencies
# run: apt-get install -y build-essential qttools5-dev-tools pkg-kde-tools pkg-config libkf5widgetsaddons-dev libkf5config-dev libkf5configwidgets-dev libkf5screen-dev debhelper-compat libqt5svg5-dev libgsettings-qt-dev libglib2.0-dev libmatekbd-dev libqt5x11extras5-dev libxklavier-dev qtdeclarative5-dev libdconf-dev libmatemixer-dev libqt5xdg-dev qtmultimedia5-dev libxml2-dev libcanberra-dev libmate-desktop-dev libxkbcommon-dev libxkbfile-dev libkf5i18n-dev libkf5windowsystem-dev libkf5guiaddons-dev libkf5coreaddons-dev libboost-dev libxcb-xkb-dev libpolkit-qt5-1-dev libpulse-dev libkf5bluezqt-dev libudev-dev xserver-xorg-dev libupower-glib-dev libpam0g-dev libkf5xmlgui-dev libkf5globalaccel-dev
# - name: QMake configure & Make
# run: |
# mkdir build;
# cd build;
# qmake ..;
# make -j$(nproc);

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

8
NEWS Normal file
View File

@ -0,0 +1,8 @@
2.0.0
* Migrate from gtk to qt.
1.1.0
* update gtk3 API
0.0.1
* init.

385
README.md Normal file
View File

@ -0,0 +1,385 @@
## ukui-control-center
![build](https://github.com/ukui/ukui-control-center/workflows/build/badge.svg?branch=master)
UKCC(ukui-control-center)是UKUI桌面环境的控制面板
### 依赖
------
### 编译依赖
- KF5
- libkf5widgetsaddons-dev
- libkf5config-dev
- libkf5configwidgets-dev
- libkf5screen-dev
- debhelper-compat
- libqt5svg5-dev
- libgsettings-qt-dev
- libglib2.0-dev
- libmatekbd-dev
- libqt5x11extras5-dev
- libxklavier-dev
- qtdeclarative5-dev
- libdconf-dev
- libmatemixer-dev
- libqt5xdg-dev
- qtmultimedia5-dev
- libxml2-dev
### 运行依赖
- ukui-power-manager
- ukui-session-manager
- ukui-screensaver
- ukui-settings-daemon
- qml-module-qtgraphicaleffects
- redshift
- edid-decode
### 编译
------
```shell
$ cd ukui-control-center
$ mkdir build
$ cd build
$ qmake ..
$ make
```
### 安装
------
```shell
$ sudo make install
```
### 主体框架
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [x] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 搜索
- 动画效果
### 功能插件
#### 系统
##### 显示器
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [x] 界面美化
- **TODO**
- 部分环境重启不生效BUG[DBus后台服务编写]
##### 默认应用程序
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 添加界面未设计
##### 电源
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 开机启动
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 添加程序从desktop改为易于理解的程序名称
#### 设备
##### 打印机
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 鼠标
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 光标粗细暂无接口
- **TODO**
- 文本区域光标闪烁功能
##### 触摸板
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 键盘
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 键盘布局的实现
##### 快捷键
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 快捷键功能不生效问题
##### 声音
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
#### 个性化
##### 背景
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 纯色
- 幻灯片
- 背景图片放置方式
##### 主题
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 主题切换速度优化
##### 锁屏
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 预览效果
##### 字体
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 字体预览效果
- 字体高级设置
##### 屏幕保护
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 预览
##### 桌面
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 桌面图标开启/关闭功能
#### 网络
##### 网络连接
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 实时刷新功能
##### VPN
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 代理
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
#### 帐户
##### 帐户信息
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 密码加密后才能设置
- 添加新用户控件换行问题
- 仅剩一个管理员时的处理
- 密码过期功能
##### 登录选项
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 功能暂时不支持
- **TODO**
- 无
##### 云帐户
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [x] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
#### 时间和语言
##### 时间和日期
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [x] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 语言和地区
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [x] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 中英文以外其他区域格式切换
- 中英文以外其他语言切换
- 语言添加功能
#### 更新和安全
##### 更新
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 备份
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
#### 通知和操作
##### 通知
- **InProgress**
- [x] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无
##### 多任务
- **InProgress**
- [ ] 界面绘制
- [ ] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 功能待实现
##### 关于
- **InProgress**
- [x] 界面绘制
- [x] 功能实现
- [ ] 界面美化
- **TROUBLE**
- 无
- **TODO**
- 无

View File

@ -0,0 +1,38 @@
QT -= gui
TARGET = changeotheruserpwd
TEMPLATE = app
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-passwd2.cpp
HEADERS += \
run-passwd2.h

View File

@ -0,0 +1,57 @@
#include <QCoreApplication>
#include <glib.h>
#include "run-passwd2.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_change_password(passwd_handler, argv[1], argv[2], chpasswd_cb, NULL);
return a.exec();
}
static void
auth_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data)
{
}
/**
* @brief chpasswd_cb
* @param passwd_handler
* @param error
* @param user_data
*/
static void
chpasswd_cb (PasswdHandler *passwd_handler,
GError *error,
gpointer user_data)
{
if (!error) {
qApp->exit(0);
} else {
passwd_destroy (passwd_handler);
qApp->exit(1);
}
}

View File

@ -0,0 +1,712 @@
/* qt会将glib里的signals成员识别为宏所以取消该宏
* signals时使Q_SIGNALS代替即可
**/
#ifdef signals
#undef signals
#endif
#include <glib.h>
#include <gio/gio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include "run-passwd2.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, "assword: ") != 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 failure!");
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, const char * user_name, GError **error)
{
gchar *argv[3];
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] = g_strdup_printf ("%s", user_name);
argv[2] = NULL;
// g_warning("spawn_passwd: %s %s", argv[0], argv[1]);
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 *user_name,
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 */
g_warning("passwd pid is: %d", passwd_handler->backend_pid);
if (passwd_handler->backend_pid == -1) {
/* If it is not, re-run authentication */
/* Spawn backend */
stop_passwd (passwd_handler);
if (!spawn_passwd (passwd_handler, user_name, &error)) {
g_error_free (error);
return FALSE;
}
g_warning("------------1----------------------");
/* Add current and new passwords to queue */
//将当前的密码和新密码入队,新密码会入队两次
authenticate (passwd_handler);
update_password (passwd_handler);
} else {
g_warning("-----2-----------");
/* 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);
}

View File

@ -0,0 +1,35 @@
#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 *user_name,
const char *new_password,
PasswdCallback cb,
const gpointer user_data);
#endif // RUNPASSWD_H

View File

@ -0,0 +1,38 @@
QT -= gui
TARGET = changeuserpwd
TEMPLATE = app
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

81
changeUserPwd/main.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <QCoreApplication>
#include <glib.h>
#include "run-passwd.h"
PasswdHandler *passwd_handler = NULL;
static void auth_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);
static void chpasswd_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);
int main(int argc, char *argv[])
{
if (argc != 3)
{
return -1;
}
QCoreApplication a(argc, argv);
passwd_handler = passwd_init ();
passwd_authenticate (passwd_handler, argv[1], auth_cb, argv[2]);
return a.exec();
}
static void
auth_cb (PasswdHandler *passwd_handler,
GError *error,
gpointer user_data)
{
char *secondary_text;
char * pwd = (char*) user_data;
if (error){
secondary_text = error->message;
printf("%s\n", secondary_text);
qApp->exit(1);
} else {
passwd_change_password (passwd_handler, pwd, chpasswd_cb, NULL);
}
}
/**
* @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);
}
}

View File

@ -0,0 +1,704 @@
/* qt会将glib里的signals成员识别为宏所以取消该宏
* signals时使Q_SIGNALS代替即可
**/
#ifdef signals
#undef signals
#endif
#include <glib.h>
#include <gio/gio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include "run-passwd.h"
/* Buffer size for backend output */
#define BUFSIZE 64
/* Passwd states */
//后端passwd的状态NONE应该是passwd还没有启动ERROR表示报错但还没退出
typedef enum {
PASSWD_STATE_NONE, /* Passwd is not asking for anything */
PASSWD_STATE_AUTH, /* Passwd is asking for our current password */
PASSWD_STATE_NEW, /* Passwd is asking for our new password */
PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */
PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */
} PasswdState;
struct PasswdHandler {
// GtkBuilder *ui;
const char *current_password;
const char *new_password;
const char *retyped_password;
/* Communication with the passwd program */
GPid backend_pid;
GIOChannel *backend_stdin;
GIOChannel *backend_stdout;
GQueue *backend_stdin_queue; /* Write queue to backend_stdin */
/* GMainLoop IDs */
guint backend_child_watch_id; /* g_child_watch_add (PID) */
guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */
/* State of the passwd program */
PasswdState backend_state;
gboolean changing_password;
PasswdCallback auth_cb;
gpointer auth_cb_data;
PasswdCallback chpasswd_cb;
gpointer chpasswd_cb_data;
};
//GQuark是一个guint32
static GQuark
passwd_error_quark (void)
{
static GQuark q = 0;
//返回错误的标识码
if (q == 0) {
q = g_quark_from_static_string("passwd_error");
}
return q;
}
/* Error handling */
#define PASSWD_ERROR (passwd_error_quark ())
static void stop_passwd (PasswdHandler *passwd_handler);
static void free_passwd_resources (PasswdHandler *passwd_handler);
static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler);
static void free_passwd_resources (PasswdHandler *passwd_handler)
{
GError *error = NULL;
/* Remove the child watcher */
if (passwd_handler->backend_child_watch_id != 0) {
g_source_remove (passwd_handler->backend_child_watch_id);
passwd_handler->backend_child_watch_id = 0;
}
/* Close IO channels (internal file descriptors are automatically closed) */
if (passwd_handler->backend_stdin != NULL) {
if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) {
g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message);
g_error_free (error);
error = NULL;
}
g_io_channel_unref (passwd_handler->backend_stdin);
passwd_handler->backend_stdin = NULL;
}
if (passwd_handler->backend_stdout != NULL) {
if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) {
g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message);
g_error_free (error);
error = NULL;
}
g_io_channel_unref (passwd_handler->backend_stdout);
passwd_handler->backend_stdout = NULL;
}
/* Remove IO watcher */
if (passwd_handler->backend_stdout_watch_id != 0) {
g_source_remove (passwd_handler->backend_stdout_watch_id);
passwd_handler->backend_stdout_watch_id = 0;
}
/* Close PID */
//因为flag为G_SPAWN_DO_NOT_REAP_CHILD,所以child不会自动的被reap掉需要在子进程上free
if (passwd_handler->backend_pid != -1) {
g_spawn_close_pid (passwd_handler->backend_pid);
passwd_handler->backend_pid = -1;
}
/* Clear backend state */
passwd_handler->backend_state = PASSWD_STATE_NONE;
}
static void authenticate (PasswdHandler *passwd_handler)
{
gchar *s;
s = g_strdup_printf ("%s\n", passwd_handler->current_password);
g_queue_push_tail (passwd_handler->backend_stdin_queue, s);
}
static void io_queue_pop (GQueue *queue, GIOChannel *channel)
{
gchar *buf;
gsize bytes_written;
GError *error = NULL;
buf = (gchar *)g_queue_pop_head (queue);
if (buf != NULL) {
//将队列中的首元素写入到channel中
if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) {
g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message);
g_error_free (error);
}
/* Ensure passwords are cleared from memory */
//清除内存中的passwords
memset (buf, 0, strlen (buf));
g_free (buf);
}
}
static gboolean is_string_complete (gchar *str, ...)
{
va_list ap;
gchar *arg;
if (strlen (str) == 0) {
return FALSE;
}
va_start (ap, str);
while ((arg = va_arg (ap, char *)) != NULL) {
if (g_strrstr (str, arg) != NULL) {
va_end (ap);
return TRUE;
}
}
va_end (ap);
return FALSE;
}
static gboolean io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler)
{
static GString *str = NULL; /* Persistent buffer */
gchar buf[BUFSIZE]; /* Temporary buffer */
gsize bytes_read;
GError *gio_error = NULL; /* Error returned by functions */
GError *error = NULL; /* Error sent to callbacks */
//GtkBuilder *dialog;
gboolean reinit = FALSE;
/* Initialize buffer */
if (str == NULL) {
str = g_string_new ("");
}
//dialog = passwd_handler->ui;
//buf将保存从channel中读取到的数据,bytes_read表示从buf中读取的数据长度
if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error)
!= G_IO_STATUS_NORMAL) {
g_warning ("IO Channel read error: %s", gio_error->message);
g_error_free (gio_error);
return TRUE;
}
// g_warning("----------bytes_read=%d",bytes_read);
// g_warning("----------io_watch_buf=%s-------",buf);
str = g_string_append_len (str, buf, bytes_read);
/* In which state is the backend? */
switch (passwd_handler->backend_state) {
case PASSWD_STATE_AUTH:
/* Passwd is asking for our current password */
if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) {
if (g_strrstr (str->str, "New password: ") != NULL) {
/* Authentication successful */
passwd_handler->backend_state = PASSWD_STATE_NEW;
/* Trigger callback to update authentication status */
if (passwd_handler->auth_cb)
passwd_handler->auth_cb (passwd_handler,
NULL,
passwd_handler->auth_cb_data);
} else {
/* Authentication failed */
error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
"Authentication token manipulation error!");
passwd_handler->changing_password = FALSE;
/* This error can happen both while authenticating or while changing password:
* if chpasswd_cb is set, this means we're already changing password */
if (passwd_handler->chpasswd_cb)
passwd_handler->chpasswd_cb (passwd_handler,
error,
passwd_handler->auth_cb_data);
else if (passwd_handler->auth_cb)
passwd_handler->auth_cb (passwd_handler,
error,
passwd_handler->auth_cb_data);
g_error_free (error);
}
reinit = TRUE;
}
break;
case PASSWD_STATE_NEW:
/* Passwd is asking for our new password */
if (is_string_complete (str->str, "assword: ", NULL)) {
/* Advance to next state */
passwd_handler->backend_state = PASSWD_STATE_RETYPE;
/* Pop retyped password from queue and into IO channel */
io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
reinit = TRUE;
}
break;
case PASSWD_STATE_RETYPE:
/* Passwd is asking for our retyped new password */
// if (is_string_complete (str->str,
// "successfully",
// "short",
// "longer",
// "palindrome",
// "dictionary",
// "simple",
// "simplistic",
// "similar",
// "different",
// "case",
// "wrapped",
// "recovered",
// "recent",
// "unchanged",
// "match",
// "1 numeric or special",
// "failure",
// "length",
// NULL)) {
if (TRUE){
if (g_strrstr (str->str, "successfully") != NULL) {
/* Hooray! */
/* Trigger callback to update status */
if (passwd_handler->chpasswd_cb)
passwd_handler->chpasswd_cb (passwd_handler,
NULL,
passwd_handler->chpasswd_cb_data);
}
else {
/* Ohnoes! */
if (g_strrstr (str->str, "recovered") != NULL) {
/* What does this indicate?
* "Authentication information cannot be recovered?" from libpam? */
error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
str->str);
}/* else if (g_strrstr (str->str, "short") != NULL ||
g_strrstr (str->str, "longer") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"New password length is too short!");
} else if (g_strrstr (str->str, "palindrome") != NULL ||
g_strrstr (str->str, "simple") != NULL ||
g_strrstr (str->str, "simplistic") != NULL ||
g_strrstr (str->str, "dictionary") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"The new password is too simple!");
} else if (g_strrstr (str->str, "similar") != NULL ||
g_strrstr (str->str, "different") != NULL ||
g_strrstr (str->str, "case") != NULL ||
g_strrstr (str->str, "wrapped") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"The new password is too similar to the old one!");
} else if (g_strrstr (str->str, "1 numeric or special") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"The new password must contain numbers or special characters!");
} else if (g_strrstr (str->str, "unchanged") != NULL ||
g_strrstr (str->str, "match") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"The new password is the same as the old one!");
} else if (g_strrstr (str->str, "recent") != NULL) {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
"The new password has been used recently!");
} else if (g_strrstr (str->str, "failure") != NULL) {
//Authentication failure
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
"Your password has been changed after you verify!");
} */else {
error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
str->str);
}
/* 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);
}

View File

@ -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

View File

@ -0,0 +1,343 @@
/*
* Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
**/
#include "auth-pam.h"
#include <string.h>
#include <QDebug>
#include <sys/prctl.h>
#include <unistd.h>
#include <wait.h>
#include <QTimer>
#define PAM_SERVICE_NAME "control-center"
//通信管道的文件描述符
int toParent[2], toChild[2];
static void writeData(int fd, const void *buf, ssize_t count);
static void writeString(int fd, const char *data);
static int readData(int fd, void *buf, size_t count);
static char * readString(int fd);
static int pam_conversation(int msgLength, const struct pam_message **msg,
PAM_RESPONSE **resp, void *appData);
static void sigchld_handler(int signo);
AuthPAM::AuthPAM(QObject *parent)
: Auth(parent),
pid(0),
nPrompts(0),
_isAuthenticated(false),
_isAuthenticating(false)
{
signal(SIGCHLD, sigchld_handler);
}
void AuthPAM::authenticate(const QString &userName, const QString &userPwd)
{
stopAuth();
if(pipe(toParent) || pipe(toChild))
qDebug()<< "create pipe failed: " << strerror(errno);
if((pid = fork()) < 0)
{
qDebug() << "fork error: " << strerror(errno);
}
else if(pid == 0)
{
int arg1_int = toParent[1];
int arg2_int = toChild[0];
char arg1[128];
char arg2[128];
snprintf(arg1,128,"%d",arg1_int);
snprintf(arg2,128,"%d",arg2_int);
//_authenticate(userName.toLocal8Bit().data());
prctl(PR_SET_PDEATHSIG,SIGHUP);
execlp ("childCheckpwdwithPAM",
"childCheckpwdwithPAM",
arg1, arg2,userName.toLocal8Bit().data(), NULL);
_exit (EXIT_FAILURE);
}
else
{
_isAuthenticating = true;
notifier = new QSocketNotifier(toParent[0], QSocketNotifier::Read);
connect(notifier, &QSocketNotifier::activated, this, &AuthPAM::onSockRead);
}
QTimer::singleShot(100, this, [=]{respond(userPwd);});
}
void AuthPAM::stopAuth()
{
// qDebug()<<"pppppppppppppppppid = "<<pid;
if(pid != 0)
{
messageList.clear();
responseList.clear();
_isAuthenticating = false;
_isAuthenticated = false;
nPrompts = 0;
::kill(pid, SIGKILL);
pid = 0;
}
}
void AuthPAM::respond(const QString &response)
{
nPrompts--;
responseList.push_back(response);
// for(auto msg : messageList)
// qDebug() << msg.msg;
// qDebug() << responseList;
// qDebug() << nPrompts;
if(nPrompts == 0)
{
//发送响应到子进程
int j = 0;
PAM_RESPONSE *resp = (PAM_RESPONSE*)calloc(messageList.size(), sizeof(PAM_RESPONSE));
//响应的数量和消息的数量一致如果消息类型不是PROMPT则响应是空的
for(int i = 0; i < messageList.size(); i++)
{
struct pam_message message = messageList[i];
PAM_RESPONSE *r = &resp[i];
if(message.msg_style == PAM_PROMPT_ECHO_OFF
|| message.msg_style == PAM_PROMPT_ECHO_ON)
{
int respLength = responseList[j].length() + 1;
r->resp = (char *)malloc(sizeof(char) * respLength);
memcpy(r->resp, responseList[j].toLocal8Bit().data(), respLength);
j++;
}
}
_respond(resp);
free(resp);
resp = NULL;
messageList.clear();
responseList.clear();
}
}
bool AuthPAM::isAuthenticated()
{
return _isAuthenticated;
}
bool AuthPAM::isAuthenticating()
{
return _isAuthenticating;
}
void AuthPAM::onSockRead()
{
// qDebug() << "has message";
int msgLength;
int authComplete;
readData(toParent[0], &authComplete, sizeof(authComplete));
if(authComplete)
{
int authRet;
if(readData(toParent[0], (void*)&authRet, sizeof(authRet)) <= 0)
qDebug() << "get authentication result failed: " << strerror(errno);
// qDebug() << "result: " << authRet;
_isAuthenticated = (authRet == PAM_SUCCESS);
_isAuthenticating = false;
Q_EMIT authenticateComplete();
}
else
{
readData(toParent[0], &msgLength, sizeof(msgLength));
// qDebug() << "message length: " << msgLength;
for(int i = 0; i < msgLength; i++)
{
//读取message
struct pam_message message;
readData(toParent[0], &message.msg_style, sizeof(message.msg_style));
message.msg = readString(toParent[0]);
// qDebug() << message.msg;
messageList.push_back(message);
switch (message.msg_style)
{
case PAM_PROMPT_ECHO_OFF:
nPrompts++;
Q_EMIT showPrompt(message.msg, Auth::PromptTypeSecret);
break;
case PAM_PROMPT_ECHO_ON:
nPrompts++;
Q_EMIT showPrompt(message.msg, Auth::PromptTypeQuestion);
break;
case PAM_ERROR_MSG:
Q_EMIT showMessage(message.msg, Auth::MessageTypeInfo);
break;
case PAM_TEXT_INFO:
Q_EMIT showMessage(message.msg, Auth::MessageTypeError);
break;
}
}
if(nPrompts == 0)
{
//不需要响应,发送一个空的
PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(messageList.size(), sizeof(PAM_RESPONSE));
_respond(response);
free(response);
response = NULL;
messageList.clear();
}
}
}
static void
writeData(int fd, const void *buf, ssize_t count)
{
if(write(fd, buf, count) != count)
qDebug() << "write to parent failed: " << strerror(errno);
}
static void
writeString(int fd, const char *data)
{
int length = data ? strlen(data) : -1;
writeData(fd, &length, sizeof(length));
if(data)
writeData(fd, data, sizeof(char) * length);
}
static int
readData(int fd, void *buf, size_t count)
{
ssize_t nRead = read(fd, buf, count);
if(nRead < 0)
qDebug() << "read data failed: " << strerror(errno);
return nRead;
}
static char *
readString(int fd)
{
int length;
if(readData(fd, &length, sizeof(length)) <= 0)
return NULL;
if(length <= 0)
return NULL;
char *value = (char *)malloc(sizeof(char) * (length + 1));
readData(fd, value, length);
value[length] = '\0';
return value;
}
void AuthPAM::_authenticate(const char *userName)
{
// qDebug() << "authenticate " << userName;
pam_handle_t *pamh = NULL;
char *newUser;
int ret;
int authRet;
struct pam_conv conv;
conv.conv = pam_conversation;
conv.appdata_ptr = NULL;
ret = pam_start(PAM_SERVICE_NAME, userName, &conv, &pamh);
if(ret != PAM_SUCCESS)
{
qDebug() << "failed to start PAM: " << pam_strerror(NULL, ret);
}
authRet = pam_authenticate(pamh, 0);
ret = pam_get_item(pamh, PAM_USER, (const void **)&newUser);
if(ret != PAM_SUCCESS)
{
pam_end(pamh, 0);
qDebug() << "failed to get username";
}
free(newUser);
newUser = NULL;
// fprintf(stderr, "authentication result: %d\n", authRet);
// 发送认证结果
int authComplete = 1;
writeData(toParent[1], (const void*)&authComplete, sizeof(authComplete));
writeData(toParent[1], (const void *)&authRet, sizeof(authRet));
// qDebug() << "--- 认证完成";
_exit(EXIT_SUCCESS);
}
void AuthPAM::_respond(const PAM_RESPONSE *response)
{
for(int i = 0; i < messageList.size(); i++)
{
const PAM_RESPONSE *resp = &response[i];
writeData(toChild[1], (const void *)&resp->resp_retcode,
sizeof(resp->resp_retcode));
writeString(toChild[1], resp->resp);
}
}
static int
pam_conversation(int msgLength, const struct pam_message **msg,
PAM_RESPONSE **resp, void */*appData*/)
{
PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(msgLength,sizeof(PAM_RESPONSE));
int authComplete = 0;
writeData(toParent[1], (const void*)&authComplete, sizeof(authComplete));
writeData(toParent[1], (const void*)&msgLength, sizeof(msgLength));
//发送pam消息
for(int i = 0; i < msgLength; i++)
{
const struct pam_message *m = msg[i];
writeData(toParent[1], (const void *)&m->msg_style, sizeof(m->msg_style));
writeString(toParent[1], m->msg);
}
//读取响应
for(int i = 0; i < msgLength; i++)
{
PAM_RESPONSE *r = &response[i];
readData(toChild[0], &r->resp_retcode, sizeof(r->resp_retcode));
r->resp = readString(toChild[0]);
}
*resp = response;
return PAM_SUCCESS;
}
void sigchld_handler(int signo)
{
if(signo == SIGCHLD)
{
::waitpid(-1, NULL, WNOHANG);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
**/
#ifndef AUTHPAM_H
#define AUTHPAM_H
#include "auth.h"
#include <QSocketNotifier>
#include <QList>
#include <security/pam_appl.h>
typedef struct pam_message PAM_MESSAGE;
typedef struct pam_response PAM_RESPONSE;
class AuthPAM : public Auth
{
Q_OBJECT
public:
AuthPAM(QObject *parent = nullptr);
void authenticate(const QString &userName, const QString &userPwd);
void stopAuth();
void respond(const QString &response);
bool isAuthenticated();
bool isAuthenticating();
private:
void _authenticate(const char *userName);
void _respond(const struct pam_response *response);
private Q_SLOTS:
void onSockRead();
private:
QString userName;
pid_t pid;
QSocketNotifier *notifier;
int nPrompts;
QStringList responseList;
QList<PAM_MESSAGE> messageList;
bool _isAuthenticated; //认证结果
bool _isAuthenticating;
};
#endif // AUTHPAM_H

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
**/
#ifndef AUTH_H
#define AUTH_H
#ifndef QT_NO_KEYWORDS
#define QT_NO_KEYWORDS
#endif
#include <QObject>
class Auth : public QObject
{
Q_OBJECT
Q_ENUMS(PromptType MessageType)
public:
explicit Auth(QObject *parent = nullptr)
: QObject(parent)
{
}
enum PromptType {
PromptTypeQuestion,
PromptTypeSecret
};
enum MessageType {
MessageTypeInfo,
MessageTypeError
};
Q_SIGNALS:
void showPrompt(const QString &prompt, Auth::PromptType type);
void showMessage(const QString &message, Auth::MessageType type);
void authenticateComplete();
public:
virtual void authenticate(const QString &userName, const QString &userPwd) = 0;
virtual void stopAuth() = 0;
virtual void respond(const QString &response) = 0;
virtual bool isAuthenticating() = 0;
virtual bool isAuthenticated() = 0;
};
#endif // AUTH_H

View File

@ -0,0 +1,38 @@
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 \

View File

@ -0,0 +1,20 @@
#include "widget.h"
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Widget w;
if (argc == 3){
w.pwdCheck(argv[1], argv[2]);
} else {
return 1;
}
return a.exec();
}

View File

@ -0,0 +1,61 @@
#include "widget.h"
#include "auth-pam.h"
#include <QDebug>
Widget::Widget()
{
auth = new AuthPAM(this);
accountlock = false;
connect(auth, &Auth::showMessage, this, &Widget::onShowMessage);
connect(auth, &Auth::showPrompt, this, &Widget::onShowPrompt);
connect(auth, &Auth::authenticateComplete, this, &Widget::onAuthComplete);
}
Widget::~Widget()
{
auth->stopAuth();
delete auth;
}
void Widget::pwdCheck(QString userName, QString userPwd){
auth->authenticate(userName, userPwd);
}
void Widget::onShowMessage(const QString &message, Auth::MessageType type)
{
// qDebug() << "showMessage" << message;
accountlock = true;
printf("%s\n", message.toUtf8().data());
}
void Widget::onShowPrompt(const QString &prompt, Auth::PromptType type)
{
// qDebug() << "prompt: " << prompt;
}
void Widget::onAuthComplete()
{
if (!accountlock){
if(auth->isAuthenticated()){
// qDebug() << "Succes!\n";
// printf("Succes!\n");
} else {
printf("Failed!\n");
// qDebug() << "Failed!";
}
}
exit(0);
}

View File

@ -0,0 +1,29 @@
#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

View File

@ -0,0 +1,7 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = \
childCheckPwdWithPAM \
checkUserPwd \

View File

@ -0,0 +1,39 @@
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 \

View File

@ -0,0 +1,166 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <fcntl.h>
#include <security/pam_appl.h>
#include <sys/mman.h>
static int toParent = 0;
static int fromChild = 0;
typedef struct pam_message PAM_MESSAGE;
typedef struct pam_response PAM_RESPONSE;
static void
writeData(int fd, const void *buf, ssize_t count)
{
if(write(fd, buf, count) != count)
printf("write to parent failed: %s\n",strerror(errno));
}
static void
writeString(int fd, const char *data)
{
int length = data ? strlen(data) : -1;
writeData(fd, &length, sizeof(length));
if(data)
writeData(fd, data, sizeof(char) * length);
}
static int
readData(int fd, void *buf, size_t count)
{
ssize_t nRead = read(fd, buf, count);
if(nRead < 0)
printf("read data failed: %s\n",strerror(errno));
return nRead;
}
static char *
readString(int fd)
{
int length;
if(readData(fd, &length, sizeof(length)) <= 0)
return NULL;
if(length <= 0)
return NULL;
char *value = (char *)malloc(sizeof(char) * (length + 1));
readData(fd, value, length);
value[length] = '\0';
return value;
}
static int
pam_conversation(int msgLength, const struct pam_message **msg,
PAM_RESPONSE **resp, void */*appData*/)
{
PAM_RESPONSE *response = (PAM_RESPONSE*)calloc(msgLength,sizeof(PAM_RESPONSE));
int authComplete = 0;
writeData(toParent, (const void*)&authComplete, sizeof(authComplete));
writeData(toParent, (const void*)&msgLength, sizeof(msgLength));
//发送pam消息
for(int i = 0; i < msgLength; i++)
{
const struct pam_message *m = msg[i];
writeData(toParent, (const void *)&m->msg_style, sizeof(m->msg_style));
writeString(toParent, m->msg);
}
//读取响应
for(int i = 0; i < msgLength; i++)
{
PAM_RESPONSE *r = &response[i];
readData(fromChild, &r->resp_retcode, sizeof(r->resp_retcode));
r->resp = readString(fromChild);
}
*resp = response;
return PAM_SUCCESS;
}
static void
_authenticate(const char *userName)
{
// printf("authenticate %s\n",userName);
pam_handle_t *pamh = NULL;
char *newUser;
int ret;
int authRet;
struct pam_conv conv;
conv.conv = pam_conversation;
conv.appdata_ptr = NULL;
ret = pam_start("control-center", userName, &conv, &pamh);
if(ret != PAM_SUCCESS)
{
printf("failed to start PAM: = %s\n", pam_strerror(NULL, ret));
}
authRet = pam_authenticate(pamh, 0);
ret = pam_get_item(pamh, PAM_USER, (const void **)&newUser);
if(ret != PAM_SUCCESS)
{
pam_end(pamh, 0);
printf("failed to get username\n");
}
free(newUser);
newUser = NULL;
// fprintf(stderr, "authentication result: %d\n", authRet);
// 发送认证结果
int authComplete = 1;
writeData(toParent, (const void*)&authComplete, sizeof(authComplete));
writeData(toParent, (const void *)&authRet, sizeof(authRet));
/* ---认证完成\n*/
_exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
if (argc != 4)
{
return EXIT_FAILURE;
}
toParent = atoi (argv[1]);
fromChild = atoi (argv[2]);
if (toParent == 0 || fromChild == 0)
{
printf ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
return EXIT_FAILURE;
}
//mlockall (MCL_CURRENT | MCL_FUTURE);
fcntl (toParent, F_SETFD, FD_CLOEXEC);
fcntl (fromChild, F_SETFD, FD_CLOEXEC);
_authenticate(argv[3]);
}

View File

@ -0,0 +1,11 @@
@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

BIN
data/en_US/image/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
data/en_US/image/13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
data/en_US/image/14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
data/en_US/image/15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
data/en_US/image/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

BIN
data/en_US/image/17.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
data/en_US/image/18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
data/en_US/image/19.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

BIN
data/en_US/image/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
data/en_US/image/20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
data/en_US/image/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
data/en_US/image/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
data/en_US/image/23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
data/en_US/image/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
data/en_US/image/25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
data/en_US/image/26.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
data/en_US/image/27.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
data/en_US/image/28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
data/en_US/image/29.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
data/en_US/image/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
data/en_US/image/30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
data/en_US/image/31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
data/en_US/image/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
data/en_US/image/33.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
data/en_US/image/34.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
data/en_US/image/35.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
data/en_US/image/36.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
data/en_US/image/37.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
data/en_US/image/38.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
data/en_US/image/39.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
data/en_US/image/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
data/en_US/image/40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
data/en_US/image/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
data/en_US/image/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
data/en_US/image/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
data/en_US/image/8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
data/en_US/image/9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

BIN
data/en_US/image/mouse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

362
data/en_US/index.md Normal file
View File

@ -0,0 +1,362 @@
# Ukui Control Center
## Overview
Ukui Control Center provides a friendly graphic interface to set the system. As shown in Fig 1.
![Fig 1 Ukui Control Center-big](image/1.png)
<br>
## System
### Display
As shown in Fig 2.
![Fig 2 Display-big](image/2.png)
- monitorSelect current monitor.
- resolution, orientation, refresh rate, screen zoom are all for the current active monitor.
- screen zoom to global zoom.
- night mode has the functions of adjusting color temperature and customizing the night mode time period.
### Audio
As shown in Fig 3.
![Fig 3 Audio-big](image/3.png)
### Power
As shown in Fig 4.
![Fig 4 Audio-big](image/4.png)
### Notice
As shown in Fig 5.
![Fig 5 Notice-big](image/5.png)
### Vino
As shown in Fig 6.
![Fig 6 Vino](image/6.png)
### About
As shown in Fig 4.
![Fig 7 About-big](image/7.png)
<br>
## Devices
### Bluetooth
Provide the functions like those: open the bluetooth, rename the device, show/hide the icon of the bluetooth, find the nearby devices, etc.. As shown in Fig 8.
![Fig 8 Bluetooth-big](image/8.png)
### Printer
Provide an entry to add printers or scanners.
![Fig 9 Printer-big](image/9.png)
### Mouse
As shown in Fig mouse.
![Fig mouse Mouse-big](image/mouse.png)
### Touchpad
As shown in Fig touchpad.
![Fig touchpad Touchpad-big](image/touchpad.png)
### Keyboard
As shown in Fig keyboard.
![Fig keyboard Keyboard-big](image/keyboard.png)
### Shortcut
As shown in Fig 13.
![Fig 13 Shortcut-big](image/13.png)
### Projection
Projection is a software that is allowed to be projected by mobile phones and other Kylin-OS and can be projected to other Kylin OS in Kylin OS desktop environment. It is divided into two parts: receiving terminal and sending terminal. The main interface is shown in Figure.
![Fig 14-1 Projection main interface-big](image/mainInterface.png)
The function buttons at the receiving terminal are in the upper part of the main interface, from top to bottom:
1) Receiving terminal on / off button: after the button is turned on, the current Kylin-OS device can be searched by mobile phone device or other Kylin-OS devices.
2) PIN code function on / off button: after the button is turned on, the PIN code needs to be entered during connection.
![Fig 14-2 Enter PIN code interface-big](image/PINCodeinterface.png)
![Fig 14-3 Without PIN code interface-big](image/withoutPINCodeinterface.png)
3) Historical device show / hide button: when the button arrow points down, you can see the relevant devices connected to the current Kylin-OS device.
![Fig 14-4 Historical device interface-big](image/deviceInterface.png)
The function buttons at the sending terminal are in the lower part of the main interface, including:
Receiving terminal on / off button: this button is mutually exclusive with the sending terminal on / off button. When the receiving terminal on / off button is turned on, the receiving terminal on / off button needs to be turned off before the sending terminal on / off button can be turned on (the same is true for the receiving terminal turn on / off button). After opening this button, click Find device to pop up the search window, in which the searchable Kylin-OS device at the receiving terminal will be displayed.
Connection process between mobile phone and Kylin-OS:
1) Open the receiving terminal on / off button (close the sending terminal on / off button first).
2) The mobile phone drop-down menu opens the projection (or mobile phone projection / multi screen collaboration).
![Fig 14-5 Phone open projection interface-big](image/phoneOpenProjectionInterface.png)
3) Select the Kylin-OS device to be projected in the mobile search device list.
![Fig 14-6 Phone search device interface-big](image/phoneSearchInterface.png)
4) Connect (there are two types: PIN code required and PIN code not required).
![Fig 14-7 Phone enter pin code interface-big](image/phonePINcodeInterface.png)
5) Select the mobile phone model (currently divided into Huawei, Xiaomi and others).
![Fig 14-8 Select phone model interface-big](image/chooseTypeInterface.png)
6) Projection interface: the mobile phone screen is displayed in the center of the interface. There are 5 buttons on the right side of the interface, from top to bottom: soft / hard decoding switching button; Full screen / window switching button; Return to parent directory button; Return to the main interface button; Display the application process button;
![Fig 14-9 Receiving terminal projection interface-big](image/receiverConnectInterface.png)
Kylin-OS and Kylin-OS connection process:
1) Open the on / off button at the sending terminal (close the on / off button at the receiving terminal in advance).
2) Click the search device on the left side of the switch button;
![Fig 14-10 Find device interface-big](image/searchDeviceInterface.png)
3) In the pop-up search window, select the Kylin-OS device to project to.
![Fig 14-11 Choose device interface-big](image/chooseDevice.png)
4) Projection interface.
![Fig 14-12 Sending terminal projection interface-big](image/senderConnectInterface.png)
**FAQ**
1. If the projection is unsuccessful, you can try to connect again, and the device connected once will be automatically recorded in the history device.
2. Kylin OS and some phones support the control return function (that is, the receiving terminal can indirectly affect the sending terminal by operating the mouse or keyboard).
3. At present only some Huawei phones and Xiaomi phones support Android three button function (the last three buttons on the interface on the right side of the screen). For other models, clicking these buttons may cause unknown problems.
4. The system will use soft decoding by default. At this time, you can manually switch to hard decoding (use hardware to decode video, reduce CPU occupation, and need hardware support).
5. The name of the receiving device can be changed in the screen projection interface. Click the "pen" icon on the right side of the projection screen to enter the modification interface.
![Fig 14-9 Sending terminal name modification interface-big](image/nameChangeInterface.png)
6. When the wireless network card is not inserted, or the wireless network card does not support the connection required for projection, it is necessary to insert the network card or replace the inserted network card.
![Fig 14-10 Projection function unavailable interface(1)-big](image/unUseInterface.png)
7. When the package with wireless projection is not installed or the package version is too low, the projection function will not be displayed in the control panel.
![Fig 14-11 Projection function unavailable interface(2)-big](image/unUseInterface2.png)
8.When used as the sending terminal, it does not support projecting to the receiving terminal of SP1 version.
<br>
## Network
### WiredConnect
As shown in Fig 15.
![Fig 15 WiredConnect-big](image/37.png)
### WlanConnect
As shown in Fig 16.
![Fig 16 WlanConnect-big](image/38.png)
### Proxy
As shown in Fig 17.
![Fig 17 Proxy-big](image/14.png)
### Vpn
As shown in Fig 18.
![Fig 18 Vpn-big](image/15.png)
### MobileHotspot
As shown in Fig 19.
![Fig 19 MobileHotspot-big](image/39.png)
<br>
## Personalized
### Background
As shown in Fig 20.
![Fig 20 Background-big](image/16.png)
### Theme
- Theme Mode:
![Fig 21-1 Theme mode](image/17.png)
- Icon theme and cursor theme:
![Fig 21-2 Icon&cursor theme](image/18.png)
- Effect settings (some machines do not support this function):
![Fig 21-3 Effect settings](image/19.png)
### Screenlock
As shown in Fig 22.
![Fig 22 Screenlock-big](image/20.png)
### Screensaver
As shown in Fig 23.
![Fig 23 Screensaver-big](image/21.png)
### Fonts
As shown in Fig 24.
![Fig 24 Fonts-big](image/22.png)
<br>
## Account
### User Info
![Fig 25-1 Account-big](image/23.png)
#### Current User
- Change User Face: Click user's face can change it.
![Fig 25-2 Change face](image/24.png)
- Change Password: Click "Password" to modify the current user's password.
![Fig 25-3 Change password](image/25.png)
- Change Account Type: administrator -- can elevated permission temporarily; standard user -- can't elevated permission.
![Fig 25-4 Change password](image/26.png)
#### Other Users
Administrator can modify other user's information, add new user, etc..
- Add new user
-Password complexity requirements(Password strength can be customized through security neutrality):
1. The user password cannot contain illegal characters ("'" and non-standard characters);
2. The minimum password length is 8;
3. The password shall contain at least two types of characters;
4. The password must not contain the user name;
5. It is forbidden to use palindrome in password;
6. Enable password similarity check (detect when modifying password);
7. Enable password dictionary;
8. The validity period of the password is unlimited;
![Fig 25-5 Add new user](image/27.png)
### Biometrics
As shown in Fig 26.
![Fig 26 Biometrics-big](image/40.png)
### Cloud Account
Synchronize personalized settings and data, and this function needs to sign in.
![Fig 27 Cloud account-big](image/28.png)
#### Sign In
Login through Kylin ID login Center.
#### Synchronizable Items
- Desktop wallpaper
- Screensaver: wallpaper and idle time
- Fonts
- User's face
- The settings in control center, such as start menu, taskbar, theme, etc.
- The settings of pluma, kylin weather, peony, terminal, kylin video.
#### Tips
1) When opening the cloud account first time, it will synchronize once by default. If the cloud exists configuration files, it will download them and sync to local; Otherwise, the local configuration files will be uploaded to the cloud.
2) After login, if the automatic synchronization is opened, the cloud will synchronize the local configurations every 5 minutes. And they can be used by different machines, different users.
3) If the automatic synchronization is closed, all the cloud configurations will keep the last upload status.
4) The automatic synchronization for the single item is the similar effects.
<br>
## Datetime
### Date
As shown in Fig 28:
![Fig 28 Datetime-big](image/29.png)
### Area
As shown in Fig 29:
![Fig 29 Area-big](image/30.png)
<br>
## Update Operation
In update configuration, you can configure backup and update.
-Click start backup to automatically open our Kirin backup and restore tool for system content backup.
-Click Detect update to automatically open our Kirin update manager to obtain the updated content.
![Fig 30 Backup-big](image/31.png)
![Fig 31 Upgrade-big](image/32.png)
<br>
## Security
### Security Center
As shown in Fig 32.
![Fig 32 SecurityCenter-big](image/33.png)
<br>
## Application
### Auto Boot
As shown in Fig 33:
![Fig 33 Autoboot-big](image/34.png)
### Default App
As shown in Fig 34:
![Fig 34 Defaultapp-big](image/35.png)
## Investigation
### Search
As shown in Fig 35:
![Fig 35 Search-big](image/36.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
data/faces/02-student.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
data/faces/03-teacher.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
data/faces/04-tiger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
data/faces/05-panda.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
data/faces/09-rocket.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
data/faces/10-warship.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
data/faces/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
data/installer-timezones.mo Normal file

Binary file not shown.

View File

@ -0,0 +1,27 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.apt.proxy" path="/org/ukui/control-center/apt/proxy/">
<key name="enabled" type="b">
<default>false</default>
<summary>Whether open</summary>
<description>
This key is used to control whether to open apt-proxy.
</description>
</key>
<key name="host" type="s">
<default>''</default>
<summary>APT proxy host name</summary>
<description>
The machine name to proxy APT through.
</description>
</key>
<key name="port" type="i">
<range min="0" max="65535"/>
<default>8080</default>
<summary>APT proxy port</summary>
<description>
The port on the machine defined by “/apt/proxy/host” that you
proxy through.
</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,54 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.desktop" path="/org/ukui/control-center/desktop/">
<key name="computer-icon-visible" type="b">
<default>true</default>
<summary>Show computer icon on desktop</summary>
<description>Whether show computer icon on desktop or not.</description>
</key>
<key name="home-icon-visible" type="b">
<default>true</default>
<summary>Show home icon on desktop</summary>
<description>Whether show home icon on desktop or not.</description>
</key>
<key name="network-icon-visible" type="b">
<default>true</default>
<summary>Show network icon on desktop</summary>
<description>Whether show network icon on desktop or not.</description>
</key>
<key name="trash-icon-visible" type="b">
<default>true</default>
<summary>Show trash icon on desktop</summary>
<description>Whether show trash icon on desktop or not.</description>
</key>
<key name="volumes-visible" type="b">
<default>true</default>
<summary>Show volumes icon on desktop</summary>
<description>Whether show volumes icon on desktop or not.</description>
</key>
<key name="menufull-screen" type="b">
<default>false</default>
<summary>menufull-screen switch button</summary>
<description>Whether to always use the start menu in full screen.</description>
</key>
<key name="computer-icon-locking" type="b">
<default>true</default>
<summary>Lock computer icon on start menu</summary>
<description>Whether lock computer icon on start menu or not.</description>
</key>
<key name="personal-icon-locking" type="b">
<default>false</default>
<summary>Lock personal icon on start menu</summary>
<description>Whether personal icon on start menu or not.</description>
</key>
<key name="settings-icon-locking" type="b">
<default>true</default>
<summary>Lock settings icon on start menu</summary>
<description>Whether lock settings icon on start menu or not.</description>
</key>
<key name="trash-icon-locking" type="b">
<default>false</default>
<summary>Lock trash icon on start menu</summary>
<description>Whether lock trash icon on start menu or not.</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,9 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.experienceplan" path="/org/ukui/control-center/experienceplan/">
<key name="join" type="b">
<default>true</default>
<summary>join user experience plan</summary>
<description>Whether this plugin would be activated by ukui-settings-daemon or not</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,19 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.keybinding">
<key name="binding" type="s">
<default>''</default>
<summary>Keybinding</summary>
<description>Keybinding associated with a custom shortcut.</description>
</key>
<key name="action" type="s">
<default>''</default>
<summary>Command</summary>
<description>Command associated with a custom keybinding.</description>
</key>
<key name="name" type="s">
<default>''</default>
<summary>Name</summary>
<description>Description associated with a custom keybinding.</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,11 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.keyboard" path="/org/ukui/control-center/keyboard/">
</schema>
<schema id="org.ukui.control-center.osd" path="/org/ukui/control-center/osd/">
<key type="b" name="show-lock-tip">
<default>true</default>
<summary>show keyboard tip</summary>
<description>show keyboard tip or not. eg. Caps Lock. Num Lock</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,66 @@
<schemalist gettext-domain="ukui-control-center">
<enum id="org.ukui.control-center.noticeorigin.Type">
<value value="0" nick="none"/>
<value value="1" nick="corner"/>
<value value="2" nick="all"/>
</enum>
<schema id="org.ukui.control-center.notice" path="/org/ukui/control-center/notice/">
<key name="show-new-feature" type="b">
<default>true</default>
<summary>Activation of this plugin</summary>
<description>Whether this plugin would be activated by ukui-settings-daemon or not</description>
</key>
<key name="enable-notice" type="b">
<default>true</default>
<summary>Show OSD notification</summary>
<description>Whether an OSD notification is shown to notify about changes</description>
</key>
<key name="show-on-lockscreen" type="b">
<default>true</default>
<summary>Eject</summary>
<description>Binding to eject an optical disc.</description>
</key>
<key name="iscn-env" type="b">
<default>true</default>
<summary>"" </summary>
<description>Determine whether the environment is Chinese</description>
</key>
<key name="blacklist" type="as">
<default>[]</default>
<summary>"" </summary>
<description>Hidden DektopList</description>
</key>
</schema>
<schema id="org.ukui.control-center.noticeorigin">
<key name="messages" type="b">
<default>true</default>
<summary>messages notice</summary>
<description>.</description>
</key>
<key name="voice" type="b">
<default>true</default>
<summary>voice notice</summary>
<description>.</description>
</key>
<key name="maximize" type='i'>
<default>3</default>
<summary>maximize num of messages</summary>
<description>The maximize num of messages on notice window.</description>
</key>
<key name="name-cn" type='s'>
<default>''</default>
<summary>app's name</summary>
<description>The name passed to the sidebar</description>
</key>
<key name="name-us" type='s'>
<default>''</default>
<summary>app's name</summary>
<description>The name passed to the sidebar</description>
</key>
<key name="type" enum="org.ukui.control-center.noticeorigin.Type">
<default>'corner'</default>
<summary>type of notice message</summary>
<description>the type of notice in system.</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,59 @@
<schemalist gettext-domain="ukui-control-center">
<schema id="org.ukui.control-center.panel.plugins" path="/org/ukui/control-center/panel/plugins/">
<key name="hoursystem" type="s">
<default>'24'</default>
<summary>HourSystem status</summary>
<description>hoursystem used in UKUI Desktop Environment ,ontrol by ukui-panel and ukui-control-center</description>
</key>
<key name="synctime" type="b">
<default>true</default>
<summary>sync time from network</summary>
<description></description>
</key>
<key name="ntp" type="s">
<default>''</default>
<summary>customize ntp server address</summary>
<description>user-defined ntp server address</description>
</key>
<key name="timezones" type="as">
<default>[]</default>
<summary>all time zones of time display</summary>
<description>other time zones</description>
</key>
<key name="calendar" type="s">
<default>'lunar'</default>
<summary>Lunar calendar</summary>
<description>calendar system used in UKUI Desktop Environment ,ontrol by ukui-panel and ukui-control-center</description>
</key>
<key name="firstday" type="s">
<default>'monday'</default>
<summary>first of week</summary>
<description>Select the first day of the week</description>
</key>
<key name="date" type="s">
<default>'cn'</default>
<summary>date formate</summary>
<description>date format</description>
</key>
<key name="time" type="s">
<default>'24'</default>
<summary>first of week</summary>
<description>Select the first day of the week</description>
</key>
<key name="showlanguage" type="as">
<default>[]</default>
<summary>show language in plugin area</summary>
<description>show language in plugin area</description>
</key>
<key name="nightmodestatus" type="b">
<default>false</default>
<summary>ukui-control-center sets the night mode status so that ukui-panel can get the status</summary>
<description></description>
</key>
<key name="themebynight" type="b">
<default>false</default>
<summary>ukui-control-center theme changes follow with the night mode</summary>
<description></description>
</key>
</schema>
</schemalist>

Some files were not shown because too many files have changed in this diff Show More