1
0
Fork 0

Adding upstream version 48.0.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
Daniel Baumann 2025-06-22 19:45:29 +02:00
parent ee81d57d08
commit 83b37a3d94
Signed by: daniel.baumann
GPG key ID: BCC918A2ABD66424
341 changed files with 229581 additions and 0 deletions

153
.gitignore vendored Normal file
View file

@ -0,0 +1,153 @@
*~
*.cat
*.cat.m
*.gmo
*.lo
*.mo
.*.*.mo
*.msg
*.o
*.old.po
*.pox
*.tab.c
.*.swp
ABOUT-NLS
at-spi-registryd-wrapper.desktop.in
./autom4te.cache
.deps
_libs
.libs
cat-id-tbl.tmp
config.cache
config.h
config.log
config.lt
config.rpath
config.status
config.status.lineno
configure.lineno
gdm.conf
gdm.conf-custom
gdm-display-glue.h
gdm-display-glue.c
gdm-local-display-glue.h
gdm-local-display-glue.c
gdm-local-display-factory-glue.h
gdm-local-display-factory-glue.c
gdm-manager-glue.c
gdm-manager-glue.h
gdm.pot
gdm-restart
gdm-safe-restart
gdm.schemas
gdm-session-glue.h
gdm-session-glue.c
gdm-session-worker-glue.h
gdm-session-worker-glue.c
gdm-static-display-glue.h
gdm-static-display-glue.c
gdm-static-factory-display-glue.h
gdm-stop
gdm-transient-display-glue.h
gdm-transient-display-glue.c
gdm-xdmcp-display-glue.h
gdm-xdmcp-display-glue.c
gdm-xdmcp-chooser-display-glue.h
gdm-xdmcp-greeter-display-glue.h
gdm-greeter-glue.h
gdm-greeter-glue.c
GNOME_FastUserSwitchApplet.server
GNOME_FastUserSwitchApplet.server.in
gnome-power-manager.desktop.in
gnome-settings-daemon.desktop.in
GPATH
GRTAGS
GSYMS
GTAGS
in
Init
.intltool-merge-cache
libgdmcommon.la
libgdmuser.la
libnotificationarea.la
libtool
Makefile
Makefile.in
Makefile.in.in
na-marshal.c
na-marshal.h
PostSession
POTFILES
PreSession
so_locations
stamp-h1
stamp-it
tags
TAGS
Xsession
INSTALL
aclocal.m4
autom4te.cache/
common/test-log
compile
config.guess
config.h.in
config.sub
configure
daemon/gdm
daemon/gdm-session-worker
daemon/gdm-wayland-session
daemon/gdm-x-session
daemon/test-session-client
daemon/test-external-greeter
daemon/gdm-session-enum-types.c
daemon/gdm-session-enum-types.h
data/applications/gnome-mag.desktop
data/applications/gnome-shell.desktop
data/applications/gnome-shell-wayland.desktop
data/applications/gok.desktop
data/applications/orca-screen-reader.desktop
data/autostart/caribou-autostart.desktop
depcomp
libgdm/gdm-client-glue.h
libgdm/gdm-client-glue.c
libgdm/gdm-manager-glue.h
libgdm/gdm-manager-glue.c
gui/simple-chooser/gdm-host-chooser
gui/simple-chooser/gdm-simple-chooser
install-sh
intltool-extract.in
intltool-merge.in
intltool-update.in
ltmain.sh
m4/*.m4
missing
mkinstalldirs
tests/m-common
utils/gdmflexiserver
*.gschema.valid
*.gschema.xml
*.la
*.pc
*.gir
*.typelib
*.tar.*
gdm-smartcard-worker
dconf-override-db
docs/*/*.stamp
docs/*/legal.xml
docs/*/index.docbook
po/*.gmo
po/*.header
po/*.sed
po/*.sin
po/.intltool-merge-cache
po/Makefile.in.in
po/Makevars.template
po/POTFILES
po/Rules-quot
po/stamp-it
test-driver

113
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,113 @@
include:
- https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates/-/raw/master/templates/fedora.yml
- component: "gitlab.gnome.org/GNOME/citemplates/release-service@master"
inputs:
job-stage: "release"
dist-job-name: "build-fedora"
tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}"
variables:
COMMON_BUILD_OPTIONS: --prefix=/usr --sysconfdir=/etc --localstatedir=/var --mandir=/usr/share/man --libdir=/usr/lib64 -Dpam-prefix=/etc -Drun-dir=/run/gdm -Dudev-dir=/lib/udev/rules.d -Ddefault-path=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin -Dprofiling=true -Dplymouth=enabled -Dselinux=enabled
MESON_BUILD_DIR: build
TARBALL_ARTIFACT_PATH: "${MESON_BUILD_DIR}/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz"
stages:
- prepare
- build
- release
workflow:
rules:
# Allow to switch from branch pipelines to MR pipelines seamlessly
# https://docs.gitlab.com/ee/ci/jobs/job_control.html#avoid-duplicate-pipelines
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# Don't trigger a branch pipeline if there is an open MR
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: '$CI_COMMIT_BRANCH'
- if: '$CI_COMMIT_TAG'
.gdm.fedora:
variables:
FDO_DISTRIBUTION_VERSION: 41
FDO_DISTRIBUTION_TAG: '2025-02-06.0'
FDO_DISTRIBUTION_PACKAGES:
accountsservice-devel
audit-libs-devel
check-devel
dconf
desktop-file-utils
gettext-devel
git
gobject-introspection-devel
iso-codes-devel
itstool
json-glib-devel
keyutils-libs-devel
libattr-devel
libgudev-devel
libdmx-devel
libselinux-devel
libtool
meson
nss-devel
pam-devel
plymouth-devel
redhat-rpm-config
systemd
systemd-devel
which
yelp-devel
gtk3-devel
libXau-devel
libXdmcp-devel
xorg-x11-server-Xorg
xorg-x11-server-devel
.dummy-container-build:
script:
- echo Dummy container build
build-fedora-container:
extends:
#- .fdo.container-build@fedora@x86_64
- .dummy-container-build
- .gdm.fedora
stage: prepare
rules:
- when: always
build-fedora:
extends:
- .fdo.distribution-image@fedora
- .gdm.fedora
stage: build
script:
- meson setup ${MESON_BUILD_DIR} ${COMMON_BUILD_OPTIONS}
- meson compile -C ${MESON_BUILD_DIR}
- meson install -C ${MESON_BUILD_DIR}
- meson dist -C ${MESON_BUILD_DIR}
- meson test -C ${MESON_BUILD_DIR}
rules:
- when: always
artifacts:
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}"
when: always
paths:
- "${TARBALL_ARTIFACT_PATH}"
build-fedora-wayland:
extends:
- .fdo.distribution-image@fedora
- .gdm.fedora
stage: build
script:
- meson setup ${MESON_BUILD_DIR} ${COMMON_BUILD_OPTIONS} -Dx11-support=false
- meson compile -C ${MESON_BUILD_DIR}
- meson install -C ${MESON_BUILD_DIR}
- meson dist -C ${MESON_BUILD_DIR}
- meson test -C ${MESON_BUILD_DIR}
rules:
- if: $CI_COMMIT_TAG == null

2
AUTHORS Normal file
View file

@ -0,0 +1,2 @@
William Jon McCann <mccann@jhu.edu>
Ray Strode <rstrode@redhat.com>

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.

46
HACKING Normal file
View file

@ -0,0 +1,46 @@
Coding Style
============
* Follow the coding style already used.
* Trailing whitespace is not allowed.
* Use spaces (not tabs) for indentation.
* Brace on same line as block statement.
* Use braces on all blocks (even single line blocks).
* Code must conform to C89/C90 (ANSI/ISO C) (ie. no C99).
* Spaces between functions and arguments, or macros and arguments.
* Spaces before and after most binary operators.
* Spaces after most unary operators (including a comma).
* Return value on line before function definition.
* Brace on line after function definition.
* Do not initialize local variables in their declarations.
* Line up function arguments in declarations.
* One variable declaration per line.
* Line up variable names in declarations.
* Limit the use of function prototypes by defining functions
in the file before they are used.
* Whenever possible conditional expressions should not have side
effects (eg. don't set a value or call a function in an if
statement).
* '*' goes with variable not type, when declaring a pointer.
* Function arguments follow the function call on the same line, and if
lengthy are (where possible) wrapped to the column of the first brace.
* Always compare pointers with NULL instead of using "!".
* If you make a non-trivial and copyrightable change to a file
be sure to add your name to the copyright information at the
beginning of the file.
* Use gtk-doc style comments on public functions whenever possible.
* In most cases, don't abbreviate words in function and variable names.
* Function names are lowercase, words separated by underscores.
* Macros and enums are all uppercase, words seperated by
underscores.
* Types are all words capitalized, no separators between words.
* Don't use gchar. "char" is just fine.
* Public functions should check input using g_return_if_fail.
* Private functions should check input using g_assert.
* Handle the default case in switch statements with
a warning or g_assert_not_reached.
* Prefer glib functions over native ones when available.
* Use glib string handling functions when possible.
* When in doubt copy the style of the rest of the file.

3
MAINTAINERS Normal file
View file

@ -0,0 +1,3 @@
Ray Strode
E-mail: rstrode@redhat.com
Userid: halfline

657
NEWS Normal file
View file

@ -0,0 +1,657 @@
=======
Version 48.0
=======
- Allow changing global network settings
- Translation updates
=======
48.beta
=======
- Don't require Xwayland if wayland-only
- Fix pam_syslog detection
- Fix Solaris build
- Fix udev rules for disabling wayland
- Add 'banner-message-path' and '-source' settings
==========
Version 47
==========
- Fix X11 support
=============
Version 47.rc
=============
- Make X11 support optional
- Support logind secure attention key
- Drop gdm-screenshot
- Don't hardcode g-r-d in dbus policy
- Fix numeric local address resolution
- Docs updates
- Translation updates
================
Version 47.alpha
================
- Support for gnome-remote-desktop persistent sessions
- Misc changes
- Translation updates
============
Version 46.0
============
- PAM improvements
- Translation updates
=============
Version 46.rc
=============
- Support for killing conflicting sessions at login time.
- XDMCP fix
- Use wayland by default on certain server chips
- Fix pam extension size computation
- Introspection fix
- Fix for homed users
- Translation updates
================
Version 46.alpha
================
- Support remote login from gnome-remote-desktop (and hopefuly nicedcv in the future)
- Support new JSON pam extension
- Fix build with user-display-server=false
- Minor clean ups
- Move private D-Bus sockets to private directory
- Build goo fixes
- Warning fixes
- Translation updates
==============
Version 45.0.1
==============
- Fix for the crasher fix
============
Version 45.0
============
- Crasher fix
- Translation updates
===============
Version 45.beta
===============
- A ton of small code clean ups and small leak fixes
- Set gnome-initial-setup dconf profile
- Honor settings configured with a template in AccountsService
- Crash fix from stray udev events
- VT handling fixes
- Work better in presence of simpledrm
- wayland multi-seat support
- Translation updates
============
Version 44.0
============
- Translation updates
=============
Version 44.rc
=============
- Lots of code clean ups
- Fix detection of virt on efi setups
- Fix btmp accounting on failed logins
- Ensure pam_close_session is called even if worker is killed
- PAM config update on Arch
- Translation updates
============
Version 43.0
============
- Drop vestigial code
- Fixes in GPU detection
- use _GNU_SOURCE again to avoid compile warning
- Translation updates
============
Version 42.0
============
- Work better on nvidia
- Look in DATADIR for launch environment data files
- PAM updates on exherbo
- Translation updates
============
Version 41.3
============
- Juggle Xorg's -listen/-nolisten command line change better
- Fix session type selection
- Fix crash
- Drop vestigial gdm-pin service
- XDMCP fixes
- Wayland nvidia udev updates
- Translation updates
============
Version 41.0
============
- Translation updates
==============
Version 41.rc1
==============
- Fix fallback to Xorg at login screen
- Fix SessionType in AccountService user config
- Reuse VT on log out
- Translation updates
================
Version 41.alpha
================
- Allow user session to be Wayland even when login screen is Xorg
- Allow wayland user sessions for single GPU vendor nvidia machines
- Translation updates
==========
Version 40
==========
- 100% CPU fix
- Translation updates
================
Version 40.rc
================
- Fingerprint auth fixes
- Fix timeout handling for graphics bringup
- Translation updates
================
Version 40.beta
================
- xinit script improvements
- Build goo fixes
- Support systems that boot before the graphics subsystem fully loads
- Don't overwrite PATH set by user
- Generalize gdm-disable-wayland into new gdm-runtime-config tool
- Fail hard if accountsservice fails
- PAM integration improvements
- Leak fixes
- Stop using deprecated systemd functions
- Translation updates
================
Version 3.38.2.1
================
- Address autologin unlock bug issue (CVE-2020-27837)
- Translation updates
==============
Version 3.38.2
==============
- Fix localization bug to prevented translated messages from showing up
- Deal more appropriately with broken accountsservice
==============
Version 3.38.1
==============
- Fix bug leading to users /etc/gdm/custom.conf getting overwritten on nvidia systems.
- Fix typo in comment
- Translation updates
==============
Version 3.38.0
==============
- Crasher fix
- build goo updates
- systemd unit file improvements
- Translation updates
===============
Version 3.37.90
===============
- Updates to systemd integration
- deprecation fixes
- Support killling X on login even when wayland support is disabled
- Translation updates
==============
Version 3.37.3
==============
- PAM file updates for archlinux
- User switching fix
- Don't keep login screen running in background on Xorg
- Translation updates
==============
Version 3.37.1
==============
- Switch from autogoo to meson
- Fixes for when GDM isn't started on its configured initial VT
- Don't hardcode path to plymouth
- keyutils has a .pc file so use it
- Enable wayland on cirrus
- Chrome remote desktop fix
- Always use separate session bus for greeter sessions
This runs dbus-run-session, so the binary needs to be available
- Translation updates
==============
Version 3.34.1
==============
- De-duplicate sessions on pure Xorg too
- Fix fast user switching by assuming the login screen VT is always the initial
one
- Translation updates
==============
Version 3.34.0
==============
- Translation updates
===============
Version 3.33.92
===============
- Fix typo in debug message
- Revert vt changing fix, because it exposes logind bug and it wasn't quite right anyway
- Ensure login screen gets reaped when user switching
- Translation updates
===============
Version 3.33.90
===============
- Update for changes to gnome-settings-daemon
- initial-setup permissions fix
- allow users to set PATH from ~/.config/environmet
- support systemd user sessions
- misc warning fixes
- leak fix in libgdm
- vt changing fix
- drop some deprecations
- drop unused icons
- Translation updates
==============
Version 3.33.4
==============
- Fix session search directories
- Kill user sessions when stopping gdm
- Add way for sessions to register when they successfully started
- Translation updates
==============
Version 3.32.0
==============
- No updates
===============
Version 3.31.91
===============
- Screen lock bypass fix (when timed login is enabled) (CVE-2019-3825)
- PAM file updates
- Improved debug logging
- Keyboard layout fixes
- Display foreach handling
- Translation updates
==============
Version 3.31.4
==============
- DOAP file fixes
- misc code clean ups
- filter out duplicates from session list
- Translation updates
==============
Version 3.30.2
==============
- Fix autologin crash
- Unlock keyring again on autologin with newerish systemds
- Fix initial-setup
- Translation updates
==============
Version 3.30.1
==============
- make udev rule configurable
- follow up fixes dealing with login screen reaping from two releases ago
- disable wayland on proprietary nvidia machines for now
- Translation updates
==============
Version 3.30.0
==============
- build fixes
===============
Version 3.29.92
===============
- search for sessions in XDG_DATA_DIRS
- blacklist some more wayland unfriendly hardware
- initial setup fix
- flicker fix
- misc bug fixes
===============
Version 3.29.91
===============
- CVE-2018-14424 - double free fix
- follow up fixes dealing with login screen reaping form last release
- add more debug logging
- Translation updates
===============
Version 3.29.90
===============
- display wayland on certain server machines
- lifecycle fixes to libgdm/GdmClient
- drop intltool
- build goo clean ups
- kill login screen when not in use
- clean up stale utmp entries
- misc fixes
- Translation updates
==============
Version 3.29.1
==============
- Reference counting fixes for GdmClient- ensure plymouth is quit properly even when local greeter is disabled
- make sure GDM doesn't hang when called with unknown command line arguments
- Translation updates
==============
Version 3.28.0
==============
- Translation updates
===============
Version 3.27.92
===============
- Translation updates
===============
Version 3.27.91
===============
- Ensure default session for user gets reported to login screen up front
- Translation updates
===============
Version 3.27.90
===============
- Add support for configuration from /run
- Add udev rule to disable wayland with cirrus
- Remove obsolete stuff about Xnest from configure
- Adjust for g-s-d plugin removal
- segfault fix in error condition for session wrappers
- misc warning fixes
- Translation updates
==============
Version 3.27.4
==============
- Fix for invalid DISPLAY/XAUTHORITY in session scripts
- Fix for keyring integration on multidisk systems
- Set GROUP environment variable
- Deprecation fixes
- Translation updates
==============
Version 3.27.3
==============
- don't call gdm_session_defaults_changed from setup
- Add dependency to .pc file
- code clean ups
==============
Version 3.26.1
==============
- Check for Xwayland before agreeing to do wayland
- misc wayland fixes
- xdmcp fixes
- minor clean ups
- allow gnome initial-setup to be forced from kernel command line
- Translation updates
==============
Version 3.26.0
==============
- Fix for unauthenticated unlock when autologin is enabled (CVE-2017-12164)
- Translation updates
===============
Version 3.25.92
===============
- Fix for going to normal mode after classic
- crasher fix when user switching
- make sure reauthentication is run in right context
- send hangup signal to gdm when systemctl request reload
- Translation updates
=================
Version 3.25.90.1
=================
- Fix breakage in greeter and initial setup
- Translation updates
===============
Version 3.25.90
===============
- Fix for going to normal mode after classic
- Translation updates
================
Version 3.25.4.1
================
- brown bag release to fix conflict with latest g-s-d release
===============
Version 3.25.4
===============
- wayland w/ --disable-user-display-server fix
- Make login screen session separate from user session again
- Translation updates
===============
Version 3.25.3
===============
- crasher fix
- x11/wayland selection fix
- greeter lifecycle fix
- systemd unit installation fix
- drop lock down of non-existent setting
- Translation updates
===============
Version 3.24.1
===============
- Don't set DCONF_PROFILE for gnome-initial-setup
- Remove deprecated a11y keys
- autologin fixes
- xdmcp fixes
- user switching fixes
- Translation updates
===============
Version 3.24.0
===============
===============
Version 3.23.92
===============
- Be more robust against misconfigured autologin systems
=================
Version 3.23.91.1
=================
- Fix regression in wayland fallback code
- Fix for headless sessions
- Change around how PostLogin/PostSession scripts are run
- Fix XDMCP in network environments with poor network resolution
- Don't try to user switch with XDMCP
- Translation updates
===============
Version 3.23.91
===============
- Small fix to environment variable importing
- Add configure knob to turn off user X server
==============
Version 3.23.4
==============
- Make X11DisplayName property accurate
- Fix bug that forced wayland on second logins even if user didn't pick it
- kill clients from display on logout (multiseat and xdmcp only)
- send hangup to process group when session exits
- allow specifying pam_gdm install location to configure
==============
Version 3.22.1
==============
- Fix wayland login after Xorg logout for a user
- Prefer /usr/bin/X to /usr/bin/Xorg
==============
Version 3.22.0
==============
- autologin fixes
- Translation updates
===============
Version 3.21.91
===============
- fix autologin on non-LUKS systems
- import environment from systemd user manager
===============
Version 3.21.90
===============
- Use LUKS password for to unlock gnome-keyring at login (when autologin is enabled)
- Translation updates
==============
Version 3.21.4
==============
- Small crasher fix
- Translation updates
==============
Version 3.21.3
==============
- Translation updates
==============
Version 3.21.2
==============
- Import DISPLAY into user bus
- Translation updates
==============
Version 3.20.1
==============
- Fix passwordless logins on Debian/Ubuntu
- Don't allow passwordless XDMCP logins
- Fix redhat pam configuration
- Translation updates
==============
Version 3.20.0
==============
- Translation updates
===============
Version 3.19.92
===============
- leak fix
- Translation updates
===============
Version 3.19.91
===============
- Fix log output
- Fix timed login
- Fix openembedded pam configuration
- Translation updates
===============
Version 3.19.90
===============
- Better build goo output
- Support dbus user bus better
- Fix bug that prevents wayland sessions, from being wayland sometimes
- Translation updates
================
Version 3.19.4.1
================
- Fix crasher introduced in 3.19.4
- Translation updates
==============
Version 3.19.4
==============
- Don't override PAM message for password change
- Disable GVFS when we don't need it
- Fail better when no sessions are installed
- Support gnome-session in different PREFIX than GDM
- doc updates
- ensure unlock screen gets told when verification completes
- Translation updates
==============
Version 3.19.2
==============
- Get rid of "custom" session
- Separate X sessions and Wayland sessions
- Hide Wayland sessions if the login screen is on X
- Pass session mode to the shell via environment
- Rename gnome-wayland session to gnome
- Use -listen instead of -nolisten for new Xorg
- Translation updates
==============
Version 3.18.0
==============
- Translation updates
===============
Version 3.17.92
===============
- Fix log out after autologin
- Translation updates
===============
Version 3.17.90
===============
- Fix GDM_LANG corruption that sometimes fails login
- Rework wtmp handling
- Code clean ups
- Translation updates
==============
Version 3.17.4
==============
- Fixes to handle gdm restarts better
- Crasher fix on logout of wayland sessoin
- systemd build updates
- Translation updates
================
Version 3.17.3.1
================
- Ship systemd unit file (woops)
==============
Version 3.17.3
==============
- Support env.d directory for manipulating session environment
- Drop ConsoleKit support
- Translation updates
==============
Version 3.17.2
==============
- BSD fixes
- Don't build Xsession by default
- Fix monitor hotplug segfault
- kdbus fixes
- Translation updates
For older NEWS updates, please see git.

42
README.md Normal file
View file

@ -0,0 +1,42 @@
GDM - GNOME Display Manager
===========================
http://wiki.gnome.org/Projects/GDM/
The GNOME Display Manager is a system service that is responsible for
providing graphical log-ins and managing local and remote displays.
## Building and installing
To build and install GDM from source, just execute the following commands:
```
$ meson _build
$ ninja -C _build
$ sudo ninja -C _build install
```
## Contributing
You can browse the code, issues and more at GDM's [GitLab repository].
If you find a bug in GDM, please file an issue on the [issue tracker]. Please
try to add reproducible steps and the relevant version of GDM.
If you want to contribute functionality or bug fixes, please open a Merge
Request (MR). For more info on how to do this, see GitLab's [help pages on
MR's]. Please also follow the GDM coding style, which is documented in
`HACKING`.
If GDM is not translated in your language or you believe that the
current translation has errors, you can join one of the various translation
teams in GNOME. Translators do not commit directly to Git, but are advised to
use our separate translation infrastructure instead. More info can be found at
the [translation project wiki page].
## Licensing
GDM is licensed under the GNU General Public License v2.0. For more info, see
the `COPYING` file.
[help pages on MR's]: https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html
[GitLab repository]: https://gitlab.gnome.org/GNOME/gdm
[issue tracker]: https://gitlab.gnome.org/GNOME/gdm/issues
[translation project wiki page]: https://wiki.gnome.org/TranslationProject/

34
build-aux/find-x-server.sh Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
#
# First check with "! -h" for /usr/X11R6 and /usr/X11 since they often
# symlink to each other, and configure should use the more stable
# location (the real directory) if possible.
#
# On Solaris, the /usr/bin/Xserver script is used to decide whether to
# use Xsun or Xorg, so this is used on Solaris.
#
# When testing for /usr/X11R6, first check with "! -h" for /usr/X11R6
# and /usr/X11 since they often symlink to each other, and configure
# should use the more stable location (the real directory) if possible.
#
if test -x /usr/bin/X; then
echo "/usr/bin/X"
elif test -x /usr/X11/bin/Xserver; then
echo "/usr/X11/bin/Xserver"
elif test ! -h /usr/X11R6 -a -x /usr/X11R6/bin/X; then
echo "/usr/X11R6/bin/X"
elif test ! -h /usr/X11 -a -x /usr/X11/bin/X; then
echo "/usr/X11/bin/X"
elif test -x /usr/X11R6/bin/X; then
echo "/usr/X11R6/bin/X"
elif test -x /usr/bin/Xorg; then
echo "/usr/bin/Xorg"
elif test -x /usr/X11/bin/X; then
echo "/usr/X11/bin/X"
elif test -x /usr/openwin/bin/Xsun; then
echo "/usr/openwin/bin/Xsun"
elif test -x /opt/X11R6/bin/X; then
echo "/opt/X11R6/bin/X"
else
echo ""
fi

250
chooser/chooser-main.c Normal file
View file

@ -0,0 +1,250 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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
*/
#include "config.h"
#include <stdlib.h>
#include <libintl.h>
#include <locale.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <glib/gi18n.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include "gdm-common.h"
#include "gdm-log.h"
#include "gdm-chooser-session.h"
#define ACCESSIBILITY_KEY "/desktop/gnome/interface/accessibility"
static Atom AT_SPI_IOR;
static gboolean
assistive_registry_launch (void)
{
GPid pid;
GError *error;
const char *command;
char **argv;
gboolean res;
command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd";
argv = NULL;
error = NULL;
res = g_shell_parse_argv (command, NULL, &argv, &error);
if (! res) {
g_warning ("Unable to parse command: %s", error->message);
return FALSE;
}
error = NULL;
res = g_spawn_async (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH
| G_SPAWN_STDOUT_TO_DEV_NULL
| G_SPAWN_STDERR_TO_DEV_NULL,
NULL,
NULL,
&pid,
&error);
g_strfreev (argv);
if (! res) {
g_warning ("Unable to run command %s: %s", command, error->message);
return FALSE;
}
if (kill (pid, 0) < 0) {
g_warning ("at-spi-registryd not running");
return FALSE;
}
return TRUE;
}
static GdkFilterReturn
filter_watch (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
XEvent *xev = (XEvent *)xevent;
if (xev->xany.type == PropertyNotify
&& xev->xproperty.atom == AT_SPI_IOR) {
gtk_main_quit ();
return GDK_FILTER_REMOVE;
}
return GDK_FILTER_CONTINUE;
}
static gboolean
filter_timeout (gpointer data)
{
g_warning ("The accessibility registry was not found.");
gtk_main_quit ();
return FALSE;
}
static void
assistive_registry_start (void)
{
GdkWindow *root;
guint tid;
root = gdk_get_default_root_window ();
if ( ! AT_SPI_IOR) {
AT_SPI_IOR = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "AT_SPI_IOR", False);
}
gdk_window_set_events (root, GDK_PROPERTY_CHANGE_MASK);
if ( ! assistive_registry_launch ()) {
g_warning ("The accessibility registry could not be started.");
return;
}
gdk_window_add_filter (root, filter_watch, NULL);
tid = g_timeout_add_seconds (5, filter_timeout, NULL);
gtk_main ();
gdk_window_remove_filter (root, filter_watch, NULL);
g_source_remove (tid);
}
static void
at_set_gtk_modules (void)
{
GSList *modules_list;
GSList *l;
const char *old;
char **modules;
gboolean found_gail;
gboolean found_atk_bridge;
int n;
n = 0;
modules_list = NULL;
found_gail = FALSE;
found_atk_bridge = FALSE;
if ((old = g_getenv ("GTK_MODULES")) != NULL) {
modules = g_strsplit (old, ":", -1);
for (n = 0; modules[n]; n++) {
if (!strcmp (modules[n], "gail")) {
found_gail = TRUE;
} else if (!strcmp (modules[n], "atk-bridge")) {
found_atk_bridge = TRUE;
}
modules_list = g_slist_prepend (modules_list, modules[n]);
modules[n] = NULL;
}
g_free (modules);
}
if (!found_gail) {
modules_list = g_slist_prepend (modules_list, "gail");
++n;
}
if (!found_atk_bridge) {
modules_list = g_slist_prepend (modules_list, "atk-bridge");
++n;
}
modules = g_new (char *, n + 1);
modules[n--] = NULL;
for (l = modules_list; l; l = l->next) {
modules[n--] = g_strdup (l->data);
}
g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE);
g_strfreev (modules);
g_slist_free (modules_list);
}
static void
load_a11y (void)
{
assistive_registry_start ();
at_set_gtk_modules ();
}
int
main (int argc, char *argv[])
{
GdmChooserSession *session;
gboolean res;
GError *error;
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
gdm_log_set_debug (TRUE);
g_debug ("Chooser for display %s xauthority:%s",
g_getenv ("DISPLAY"),
g_getenv ("XAUTHORITY"));
gdk_init (&argc, &argv);
load_a11y ();
gtk_init (&argc, &argv);
session = gdm_chooser_session_new ();
if (session == NULL) {
g_critical ("Unable to create chooser session");
exit (EXIT_FAILURE);
}
error = NULL;
res = gdm_chooser_session_start (session, &error);
if (! res) {
g_warning ("Unable to start chooser session: %s", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
gtk_main ();
if (session != NULL) {
g_object_unref (session);
}
return 0;
}

252
chooser/gdm-chooser-host.c Normal file
View file

@ -0,0 +1,252 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-address.h"
#include "gdm-chooser-host.h"
struct _GdmChooserHost
{
GObject parent;
GdmAddress *address;
char *description;
GdmChooserHostKind kind;
gboolean willing;
};
enum {
PROP_0,
PROP_ADDRESS,
PROP_DESCRIPTION,
PROP_KIND,
PROP_WILLING,
};
static void gdm_chooser_host_class_init (GdmChooserHostClass *klass);
static void gdm_chooser_host_init (GdmChooserHost *chooser_host);
static void gdm_chooser_host_finalize (GObject *object);
G_DEFINE_TYPE (GdmChooserHost, gdm_chooser_host, G_TYPE_OBJECT)
GdmAddress *
gdm_chooser_host_get_address (GdmChooserHost *host)
{
g_return_val_if_fail (GDM_IS_CHOOSER_HOST (host), NULL);
return host->address;
}
const char *
gdm_chooser_host_get_description (GdmChooserHost *host)
{
g_return_val_if_fail (GDM_IS_CHOOSER_HOST (host), NULL);
return host->description;
}
GdmChooserHostKind
gdm_chooser_host_get_kind (GdmChooserHost *host)
{
g_return_val_if_fail (GDM_IS_CHOOSER_HOST (host), 0);
return host->kind;
}
gboolean
gdm_chooser_host_get_willing (GdmChooserHost *host)
{
g_return_val_if_fail (GDM_IS_CHOOSER_HOST (host), FALSE);
return host->willing;
}
static void
_gdm_chooser_host_set_address (GdmChooserHost *host,
GdmAddress *address)
{
if (host->address != NULL) {
gdm_address_free (host->address);
}
g_assert (address != NULL);
gdm_address_debug (address);
host->address = gdm_address_copy (address);
}
static void
_gdm_chooser_host_set_description (GdmChooserHost *host,
const char *description)
{
g_free (host->description);
host->description = g_strdup (description);
}
static void
_gdm_chooser_host_set_kind (GdmChooserHost *host,
int kind)
{
if (host->kind != kind) {
host->kind = kind;
}
}
static void
_gdm_chooser_host_set_willing (GdmChooserHost *host,
gboolean willing)
{
if (host->willing != willing) {
host->willing = willing;
}
}
static void
gdm_chooser_host_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GdmChooserHost *host;
host = GDM_CHOOSER_HOST (object);
switch (param_id) {
case PROP_ADDRESS:
_gdm_chooser_host_set_address (host, g_value_get_boxed (value));
break;
case PROP_DESCRIPTION:
_gdm_chooser_host_set_description (host, g_value_get_string (value));
break;
case PROP_KIND:
_gdm_chooser_host_set_kind (host, g_value_get_int (value));
break;
case PROP_WILLING:
_gdm_chooser_host_set_willing (host, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gdm_chooser_host_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GdmChooserHost *host;
host = GDM_CHOOSER_HOST (object);
switch (param_id) {
case PROP_ADDRESS:
g_value_set_boxed (value, host->address);
break;
case PROP_DESCRIPTION:
g_value_set_string (value, host->description);
break;
case PROP_KIND:
g_value_set_int (value, host->kind);
break;
case PROP_WILLING:
g_value_set_boolean (value, host->willing);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gdm_chooser_host_class_init (GdmChooserHostClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gdm_chooser_host_set_property;
object_class->get_property = gdm_chooser_host_get_property;
object_class->finalize = gdm_chooser_host_finalize;
g_object_class_install_property (object_class,
PROP_ADDRESS,
g_param_spec_boxed ("address",
"address",
"address",
GDM_TYPE_ADDRESS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_DESCRIPTION,
g_param_spec_string ("description",
"description",
"description",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_KIND,
g_param_spec_int ("kind",
"kind",
"kind",
0,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_WILLING,
g_param_spec_boolean ("willing",
"willing",
"willing",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
}
static void
gdm_chooser_host_init (GdmChooserHost *widget)
{
}
static void
gdm_chooser_host_finalize (GObject *object)
{
GdmChooserHost *host;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_CHOOSER_HOST (object));
host = GDM_CHOOSER_HOST (object);
g_free (host->description);
gdm_address_free (host->address);
G_OBJECT_CLASS (gdm_chooser_host_parent_class)->finalize (object);
}

View file

@ -0,0 +1,44 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
*
* 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
*/
#ifndef __GDM_CHOOSER_HOST__
#define __GDM_CHOOSER_HOST__
#include <glib-object.h>
#include "gdm-address.h"
G_BEGIN_DECLS
#define GDM_TYPE_CHOOSER_HOST (gdm_chooser_host_get_type ())
G_DECLARE_FINAL_TYPE (GdmChooserHost, gdm_chooser_host, GDM, CHOOSER_HOST, GObject)
typedef enum {
GDM_CHOOSER_HOST_KIND_XDMCP = 1 << 0,
} GdmChooserHostKind;
#define GDM_CHOOSER_HOST_KIND_MASK_ALL (GDM_CHOOSER_HOST_KIND_XDMCP)
const char *gdm_chooser_host_get_description (GdmChooserHost *chooser_host);
GdmAddress * gdm_chooser_host_get_address (GdmChooserHost *chooser_host);
gboolean gdm_chooser_host_get_willing (GdmChooserHost *chooser_host);
GdmChooserHostKind gdm_chooser_host_get_kind (GdmChooserHost *chooser_host);
G_END_DECLS
#endif

View file

@ -0,0 +1,337 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-chooser-session.h"
#include "gdm-client.h"
#include "gdm-host-chooser-dialog.h"
struct _GdmChooserSession
{
GObject parent;
GdmClient *client;
GdmRemoteGreeter *remote_greeter;
GdmChooser *chooser;
GtkWidget *chooser_dialog;
};
enum {
PROP_0,
};
static void gdm_chooser_session_class_init (GdmChooserSessionClass *klass);
static void gdm_chooser_session_init (GdmChooserSession *chooser_session);
static void gdm_chooser_session_finalize (GObject *object);
G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT)
static gpointer session_object = NULL;
static gboolean
launch_compiz (GdmChooserSession *session)
{
GError *error;
gboolean ret;
g_debug ("GdmChooserSession: Launching compiz");
ret = FALSE;
error = NULL;
g_spawn_command_line_async ("gtk-window-decorator --replace", &error);
if (error != NULL) {
g_warning ("Error starting WM: %s", error->message);
g_error_free (error);
goto out;
}
error = NULL;
g_spawn_command_line_async ("compiz --replace", &error);
if (error != NULL) {
g_warning ("Error starting WM: %s", error->message);
g_error_free (error);
goto out;
}
ret = TRUE;
/* FIXME: should try to detect if it actually works */
out:
return ret;
}
static gboolean
launch_metacity (GdmChooserSession *session)
{
GError *error;
gboolean ret;
g_debug ("GdmChooserSession: Launching metacity");
ret = FALSE;
error = NULL;
g_spawn_command_line_async ("metacity --replace", &error);
if (error != NULL) {
g_warning ("Error starting WM: %s", error->message);
g_error_free (error);
goto out;
}
ret = TRUE;
out:
return ret;
}
static void
start_window_manager (GdmChooserSession *session)
{
if (! launch_metacity (session)) {
launch_compiz (session);
}
}
static gboolean
start_settings_daemon (GdmChooserSession *session)
{
GError *error;
gboolean ret;
g_debug ("GdmChooserSession: Launching settings daemon");
ret = FALSE;
error = NULL;
g_spawn_command_line_async (GNOME_SETTINGS_DAEMON_DIR "/gnome-settings-daemon", &error);
if (error != NULL) {
g_warning ("Error starting settings daemon: %s", error->message);
g_error_free (error);
goto out;
}
ret = TRUE;
out:
return ret;
}
static void
on_dialog_response (GtkDialog *dialog,
int response_id,
GdmChooserSession *session)
{
GdmChooserHost *host;
GError *error = NULL;
host = NULL;
switch (response_id) {
case GTK_RESPONSE_OK:
host = gdm_host_chooser_dialog_get_host (GDM_HOST_CHOOSER_DIALOG (dialog));
case GTK_RESPONSE_NONE:
/* delete event */
default:
break;
}
if (host != NULL) {
char *hostname;
/* only support XDMCP hosts in remote chooser */
g_assert (gdm_chooser_host_get_kind (host) == GDM_CHOOSER_HOST_KIND_XDMCP);
hostname = NULL;
gdm_address_get_hostname (gdm_chooser_host_get_address (host), &hostname);
/* FIXME: fall back to numerical address? */
if (hostname != NULL) {
g_debug ("GdmChooserSession: Selected hostname '%s'", hostname);
gdm_chooser_call_select_hostname_sync (session->chooser,
hostname,
NULL,
&error);
if (error != NULL) {
g_debug ("GdmChooserSession: %s", error->message);
g_clear_error (&error);
}
g_free (hostname);
}
}
gdm_remote_greeter_call_disconnect_sync (session->remote_greeter,
NULL,
&error);
if (error != NULL) {
g_debug ("GdmChooserSession: disconnect failed: %s", error->message);
}
}
gboolean
gdm_chooser_session_start (GdmChooserSession *session,
GError **error)
{
g_return_val_if_fail (GDM_IS_CHOOSER_SESSION (session), FALSE);
session->remote_greeter = gdm_client_get_remote_greeter_sync (session->client,
NULL,
error);
if (session->remote_greeter == NULL) {
return FALSE;
}
session->chooser = gdm_client_get_chooser_sync (session->client,
NULL,
error);
if (session->chooser == NULL) {
return FALSE;
}
start_settings_daemon (session);
start_window_manager (session);
/* Only support XDMCP on remote choosers */
session->chooser_dialog = gdm_host_chooser_dialog_new (GDM_CHOOSER_HOST_KIND_XDMCP);
g_signal_connect (session->chooser_dialog,
"response",
G_CALLBACK (on_dialog_response),
session);
gtk_widget_show (session->chooser_dialog);
return TRUE;
}
void
gdm_chooser_session_stop (GdmChooserSession *session)
{
g_return_if_fail (GDM_IS_CHOOSER_SESSION (session));
}
static void
gdm_chooser_session_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_chooser_session_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
gdm_chooser_session_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmChooserSession *chooser_session;
chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
return G_OBJECT (chooser_session);
}
static void
gdm_chooser_session_dispose (GObject *object)
{
g_debug ("GdmChooserSession: Disposing chooser_session");
G_OBJECT_CLASS (gdm_chooser_session_parent_class)->dispose (object);
}
static void
gdm_chooser_session_class_init (GdmChooserSessionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_chooser_session_get_property;
object_class->set_property = gdm_chooser_session_set_property;
object_class->constructor = gdm_chooser_session_constructor;
object_class->dispose = gdm_chooser_session_dispose;
object_class->finalize = gdm_chooser_session_finalize;
}
static void
gdm_chooser_session_init (GdmChooserSession *session)
{
session->client = gdm_client_new ();
}
static void
gdm_chooser_session_finalize (GObject *object)
{
GdmChooserSession *chooser_session;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_CHOOSER_SESSION (object));
chooser_session = GDM_CHOOSER_SESSION (object);
g_return_if_fail (chooser_session != NULL);
g_clear_object (&chooser_session->chooser);
g_clear_object (&chooser_session->remote_greeter);
g_clear_object (&chooser_session->client);
G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object);
}
GdmChooserSession *
gdm_chooser_session_new (void)
{
if (session_object != NULL) {
g_object_ref (session_object);
} else {
session_object = g_object_new (GDM_TYPE_CHOOSER_SESSION, NULL);
g_object_add_weak_pointer (session_object,
(gpointer *) &session_object);
}
return GDM_CHOOSER_SESSION (session_object);
}

View file

@ -0,0 +1,39 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_CHOOSER_SESSION_H
#define __GDM_CHOOSER_SESSION_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_CHOOSER_SESSION (gdm_chooser_session_get_type ())
G_DECLARE_FINAL_TYPE (GdmChooserSession, gdm_chooser_session, GDM, CHOOSER_SESSION, GObject)
GdmChooserSession * gdm_chooser_session_new (void);
gboolean gdm_chooser_session_start (GdmChooserSession *session,
GError **error);
void gdm_chooser_session_stop (GdmChooserSession *session);
G_END_DECLS
#endif /* __GDM_CHOOSER_SESSION_H */

View file

@ -0,0 +1,203 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gdm-host-chooser-dialog.h"
#include "gdm-host-chooser-widget.h"
struct _GdmHostChooserDialog
{
GtkDialog parent;
GtkWidget *chooser_widget;
int kind_mask;
};
enum {
PROP_0,
PROP_KIND_MASK,
};
static void gdm_host_chooser_dialog_class_init (GdmHostChooserDialogClass *klass);
static void gdm_host_chooser_dialog_init (GdmHostChooserDialog *host_chooser_dialog);
G_DEFINE_TYPE (GdmHostChooserDialog, gdm_host_chooser_dialog, GTK_TYPE_DIALOG)
GdmChooserHost *
gdm_host_chooser_dialog_get_host (GdmHostChooserDialog *dialog)
{
GdmChooserHost *host;
g_return_val_if_fail (GDM_IS_HOST_CHOOSER_DIALOG (dialog), NULL);
host = gdm_host_chooser_widget_get_host (GDM_HOST_CHOOSER_WIDGET (dialog->chooser_widget));
return host;
}
static void
_gdm_host_chooser_dialog_set_kind_mask (GdmHostChooserDialog *dialog,
int kind_mask)
{
if (dialog->kind_mask != kind_mask) {
dialog->kind_mask = kind_mask;
}
}
static void
gdm_host_chooser_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmHostChooserDialog *self;
self = GDM_HOST_CHOOSER_DIALOG (object);
switch (prop_id) {
case PROP_KIND_MASK:
_gdm_host_chooser_dialog_set_kind_mask (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_host_chooser_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
on_response (GdmHostChooserDialog *dialog,
gint response_id)
{
switch (response_id) {
case GTK_RESPONSE_APPLY:
gdm_host_chooser_widget_refresh (GDM_HOST_CHOOSER_WIDGET (dialog->chooser_widget));
g_signal_stop_emission_by_name (dialog, "response");
break;
default:
break;
}
}
static GObject *
gdm_host_chooser_dialog_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmHostChooserDialog *dialog;
dialog = GDM_HOST_CHOOSER_DIALOG (G_OBJECT_CLASS (gdm_host_chooser_dialog_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
dialog->chooser_widget = gdm_host_chooser_widget_new (dialog->kind_mask);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), dialog->chooser_widget, TRUE, TRUE, 0);
gtk_container_set_border_width (GTK_CONTAINER (dialog->chooser_widget), 5);
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("_Refresh"), GTK_RESPONSE_APPLY,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onnect"), GTK_RESPONSE_OK,
NULL);
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
gtk_window_set_title (GTK_WINDOW (dialog), _("Select System"));
gtk_window_set_icon_name (GTK_WINDOW (dialog), "computer");
g_signal_connect (dialog,
"response",
G_CALLBACK (on_response),
dialog);
gtk_widget_show_all (GTK_WIDGET (dialog));
return G_OBJECT (dialog);
}
static void
gdm_host_chooser_dialog_dispose (GObject *object)
{
g_debug ("Disposing host_chooser_dialog");
G_OBJECT_CLASS (gdm_host_chooser_dialog_parent_class)->dispose (object);
}
static void
gdm_host_chooser_dialog_class_init (GdmHostChooserDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_host_chooser_dialog_get_property;
object_class->set_property = gdm_host_chooser_dialog_set_property;
object_class->constructor = gdm_host_chooser_dialog_constructor;
object_class->dispose = gdm_host_chooser_dialog_dispose;
g_object_class_install_property (object_class,
PROP_KIND_MASK,
g_param_spec_int ("kind-mask",
"kind mask",
"kind mask",
0,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
}
static void
gdm_host_chooser_dialog_init (GdmHostChooserDialog *dialog)
{
}
GtkWidget *
gdm_host_chooser_dialog_new (int kind_mask)
{
GObject *object;
object = g_object_new (GDM_TYPE_HOST_CHOOSER_DIALOG,
"kind-mask", kind_mask,
NULL);
return GTK_WIDGET (object);
}

View file

@ -0,0 +1,39 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_HOST_CHOOSER_DIALOG_H
#define __GDM_HOST_CHOOSER_DIALOG_H
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gdm-chooser-host.h"
G_BEGIN_DECLS
#define GDM_TYPE_HOST_CHOOSER_DIALOG (gdm_host_chooser_dialog_get_type ())
G_DECLARE_FINAL_TYPE (GdmHostChooserDialog, gdm_host_chooser_dialog, GDM, HOST_CHOOSER_DIALOG, GtkDialog)
GtkWidget * gdm_host_chooser_dialog_new (int kind_mask);
GdmChooserHost * gdm_host_chooser_dialog_get_host (GdmHostChooserDialog *dialog);
G_END_DECLS
#endif /* __GDM_HOST_CHOOSER_DIALOG_H */

View file

@ -0,0 +1,877 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 1998, 1999, 2000 Martin K, Petersen <mkp@mkp.net>
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#ifdef ENABLE_X11_SUPPORT
#include <X11/Xmd.h>
#include <X11/Xdmcp.h>
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gdm-address.h"
#include "gdm-chooser-host.h"
#include "gdm-host-chooser-widget.h"
struct _GdmHostChooserWidget
{
GtkBox parent;
GtkWidget *treeview;
int kind_mask;
char **hosts;
XdmcpBuffer broadcast_buf;
XdmcpBuffer query_buf;
gboolean have_ipv6;
int socket_fd;
guint io_watch_id;
guint scan_time_id;
guint ping_try_id;
int ping_tries;
GSList *broadcast_addresses;
GSList *query_addresses;
GSList *chooser_hosts;
GdmChooserHost *current_host;
};
enum {
PROP_0,
PROP_KIND_MASK,
};
enum {
HOST_ACTIVATED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_host_chooser_widget_class_init (GdmHostChooserWidgetClass *klass);
static void gdm_host_chooser_widget_init (GdmHostChooserWidget *host_chooser_widget);
G_DEFINE_TYPE (GdmHostChooserWidget, gdm_host_chooser_widget, GTK_TYPE_BOX)
#define GDM_XDMCP_PROTOCOL_VERSION 1001
#define SCAN_TIMEOUT 30
#define PING_TIMEOUT 2
#define PING_TRIES 3
enum {
CHOOSER_LIST_ICON_COLUMN = 0,
CHOOSER_LIST_LABEL_COLUMN,
CHOOSER_LIST_HOST_COLUMN
};
static void
chooser_host_add (GdmHostChooserWidget *widget,
GdmChooserHost *host)
{
widget->chooser_hosts = g_slist_prepend (widget->chooser_hosts, host);
}
#if 0
static void
chooser_host_remove (GdmHostChooserWidget *widget,
GdmChooserHost *host)
{
widget->chooser_hosts = g_slist_remove (widget->chooser_hosts, host);
}
#endif
static gboolean
address_hostnames_equal (GdmAddress *address,
GdmAddress *other_address)
{
char *hostname, *other_hostname;
gboolean are_equal;
if (gdm_address_equal (address, other_address)) {
return TRUE;
}
if (!gdm_address_get_hostname (address, &hostname)) {
gdm_address_get_numeric_info (address, &hostname, NULL);
}
if (!gdm_address_get_hostname (other_address, &other_hostname)) {
gdm_address_get_numeric_info (other_address, &other_hostname, NULL);
}
are_equal = g_strcmp0 (hostname, other_hostname) == 0;
g_free (hostname);
g_free (other_hostname);
return are_equal;
}
static GdmChooserHost *
find_known_host (GdmHostChooserWidget *widget,
GdmAddress *address)
{
GSList *li;
GdmChooserHost *host;
for (li = widget->chooser_hosts; li != NULL; li = li->next) {
GdmAddress *other_address;
host = li->data;
other_address = gdm_chooser_host_get_address (host);
if (address_hostnames_equal (address, other_address)) {
goto out;
}
}
host = NULL;
out:
return host;
}
static void
browser_add_host (GdmHostChooserWidget *widget,
GdmChooserHost *host)
{
char *hostname;
char *name;
char *desc;
char *label;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean res;
GtkTreeSelection *selection;
g_assert (host != NULL);
if (! gdm_chooser_host_get_willing (host)) {
gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
return;
}
res = gdm_address_get_hostname (gdm_chooser_host_get_address (host), &hostname);
if (! res) {
gdm_address_get_numeric_info (gdm_chooser_host_get_address (host), &hostname, NULL);
}
name = g_markup_escape_text (hostname, -1);
desc = g_markup_escape_text (gdm_chooser_host_get_description (host), -1);
label = g_strdup_printf ("<b>%s</b>\n%s", name, desc);
g_free (name);
g_free (desc);
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->treeview));
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
CHOOSER_LIST_ICON_COLUMN, NULL,
CHOOSER_LIST_LABEL_COLUMN, label,
CHOOSER_LIST_HOST_COLUMN, host,
-1);
g_free (label);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->treeview));
if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) {
gtk_tree_selection_select_iter (selection, &iter);
}
}
static gboolean
decode_packet (GIOChannel *source,
GIOCondition condition,
GdmHostChooserWidget *widget)
{
struct sockaddr_storage clnt_ss;
GdmAddress *address;
int ss_len;
XdmcpHeader header;
int res;
static XdmcpBuffer buf;
ARRAY8 auth = {0};
ARRAY8 host = {0};
ARRAY8 stat = {0};
char *status;
GdmChooserHost *chooser_host;
status = NULL;
address = NULL;
g_debug ("decode_packet: GIOCondition %d", (int)condition);
if ( ! (condition & G_IO_IN)) {
return TRUE;
}
ss_len = (int) sizeof (clnt_ss);
res = XdmcpFill (widget->socket_fd, &buf, (XdmcpNetaddr)&clnt_ss, &ss_len);
if G_UNLIKELY (! res) {
g_debug (_("XDMCP: Could not create XDMCP buffer!"));
return TRUE;
}
res = XdmcpReadHeader (&buf, &header);
if G_UNLIKELY (! res) {
g_warning (_("XDMCP: Could not read XDMCP header!"));
return TRUE;
}
if G_UNLIKELY (header.version != XDM_PROTOCOL_VERSION &&
header.version != GDM_XDMCP_PROTOCOL_VERSION) {
g_warning (_("XDMCP: Incorrect XDMCP version!"));
return TRUE;
}
address = gdm_address_new_from_sockaddr ((struct sockaddr *) &clnt_ss, ss_len);
if (address == NULL) {
g_warning (_("XDMCP: Unable to parse address"));
return TRUE;
}
gdm_address_debug (address);
if (header.opcode == WILLING) {
if (! XdmcpReadARRAY8 (&buf, &auth)) {
goto done;
}
if (! XdmcpReadARRAY8 (&buf, &host)) {
goto done;
}
if (! XdmcpReadARRAY8 (&buf, &stat)) {
goto done;
}
status = g_strndup ((char *) stat.data, MIN (stat.length, 256));
} else if (header.opcode == UNWILLING) {
/* immaterial, will not be shown */
status = NULL;
} else {
goto done;
}
g_debug ("STATUS: %s", status);
chooser_host = find_known_host (widget, address);
if (chooser_host == NULL) {
chooser_host = g_object_new (GDM_TYPE_CHOOSER_HOST,
"address", address,
"description", status,
"willing", (header.opcode == WILLING),
"kind", GDM_CHOOSER_HOST_KIND_XDMCP,
NULL);
chooser_host_add (widget, chooser_host);
browser_add_host (widget, chooser_host);
} else {
/* server changed it's mind */
if (header.opcode == WILLING
&& ! gdm_chooser_host_get_willing (chooser_host)) {
browser_add_host (widget, chooser_host);
g_object_set (chooser_host, "willing", TRUE, NULL);
}
/* FIXME: handle unwilling? */
}
done:
if (header.opcode == WILLING) {
XdmcpDisposeARRAY8 (&auth);
XdmcpDisposeARRAY8 (&host);
XdmcpDisposeARRAY8 (&stat);
}
g_free (status);
gdm_address_free (address);
return TRUE;
}
static void
do_ping (GdmHostChooserWidget *widget,
gboolean full)
{
GSList *l;
g_debug ("do ping full:%d", full);
for (l = widget->broadcast_addresses; l != NULL; l = l->next) {
GdmAddress *address;
int res;
address = l->data;
gdm_address_debug (address);
errno = 0;
g_debug ("fd:%d", widget->socket_fd);
res = XdmcpFlush (widget->socket_fd,
&widget->broadcast_buf,
(XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)gdm_sockaddr_len (gdm_address_peek_sockaddr_storage (address)));
if (! res) {
g_warning ("Unable to flush the XDMCP broadcast packet: %s", g_strerror (errno));
}
}
if (full) {
for (l = widget->query_addresses; l != NULL; l = l->next) {
GdmAddress *address;
int res;
address = l->data;
gdm_address_debug (address);
res = XdmcpFlush (widget->socket_fd,
&widget->query_buf,
(XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)gdm_sockaddr_len (gdm_address_peek_sockaddr_storage (address)));
if (! res) {
g_warning ("Unable to flush the XDMCP query packet");
}
}
}
}
static gboolean
ping_try (GdmHostChooserWidget *widget)
{
do_ping (widget, FALSE);
widget->ping_tries --;
if (widget->ping_tries <= 0) {
widget->ping_try_id = 0;
return FALSE;
} else {
return TRUE;
}
}
static void
xdmcp_discover (GdmHostChooserWidget *widget)
{
#if 0
gtk_widget_set_sensitive (GTK_WIDGET (manage), FALSE);
gtk_widget_set_sensitive (GTK_WIDGET (rescan), FALSE);
gtk_list_store_clear (GTK_LIST_STORE (browser_model));
gtk_widget_set_sensitive (GTK_WIDGET (browser), FALSE);
gtk_label_set_label (GTK_LABEL (status_label),
_(scanning_message));
while (hl) {
gdm_chooser_host_dispose ((GdmChooserHost *) hl->data);
hl = hl->next;
}
g_list_free (chooser_hosts);
chooser_hosts = NULL;
#endif
do_ping (widget, TRUE);
#if 0
g_clear_handle_id (&widget->scan_time_id, g_source_remove);
widget->scan_time_id = g_timeout_add_seconds (SCAN_TIMEOUT,
chooser_scan_time_update,
widget);
#endif
/* Note we already used up one try */
widget->ping_tries = PING_TRIES - 1;
g_clear_handle_id (&widget->ping_try_id, g_source_remove);
widget->ping_try_id = g_timeout_add_seconds (PING_TIMEOUT,
(GSourceFunc)ping_try,
widget);
}
/* Find broadcast address for all active, non pointopoint interfaces */
static void
find_broadcast_addresses (GdmHostChooserWidget *widget)
{
int i;
int num;
int sock;
struct ifconf ifc;
char *buf;
struct ifreq *ifr;
g_debug ("Finding broadcast addresses");
sock = socket (AF_INET, SOCK_DGRAM, 0);
#ifdef SIOCGIFNUM
if (ioctl (sock, SIOCGIFNUM, &num) < 0) {
num = 64;
}
#else
num = 64;
#endif
ifc.ifc_len = sizeof (struct ifreq) * num;
ifc.ifc_buf = buf = g_malloc0 (ifc.ifc_len);
if (ioctl (sock, SIOCGIFCONF, &ifc) < 0) {
g_warning ("Could not get local addresses!");
goto out;
}
ifr = ifc.ifc_req;
num = ifc.ifc_len / sizeof (struct ifreq);
for (i = 0 ; i < num ; i++) {
const char *name;
name = ifr[i].ifr_name;
g_debug ("Checking if %s", name);
if (name != NULL && name[0] != '\0') {
struct ifreq ifreq;
GdmAddress *address;
struct sockaddr_in sin;
memset (&ifreq, 0, sizeof (ifreq));
strncpy (ifreq.ifr_name,
ifr[i].ifr_name,
sizeof (ifreq.ifr_name));
/* paranoia */
ifreq.ifr_name[sizeof (ifreq.ifr_name) - 1] = '\0';
if ((ioctl (sock, SIOCGIFFLAGS, &ifreq) < 0) && (errno != ENXIO)) {
g_warning ("Could not get SIOCGIFFLAGS for %s", ifr[i].ifr_name);
}
if ((ifreq.ifr_flags & IFF_UP) == 0 ||
(ifreq.ifr_flags & IFF_BROADCAST) == 0 ||
ioctl (sock, SIOCGIFBRDADDR, &ifreq) < 0) {
g_debug ("Skipping if %s", name);
continue;
}
memcpy (&sin, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
sin.sin_port = htons (XDM_UDP_PORT);
address = gdm_address_new_from_sockaddr ((struct sockaddr *) &sin, sizeof (sin));
if (address != NULL) {
g_debug ("Adding if %s", name);
gdm_address_debug (address);
widget->broadcast_addresses = g_slist_append (widget->broadcast_addresses, address);
}
}
}
out:
g_free (buf);
close (sock);
}
static void
add_hosts (GdmHostChooserWidget *widget)
{
int i;
for (i = 0; widget->hosts != NULL && widget->hosts[i] != NULL; i++) {
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *ai;
int gaierr;
const char *name;
char serv_buf [NI_MAXSERV];
const char *serv;
name = widget->hosts[i];
if (strcmp (name, "BROADCAST") == 0) {
find_broadcast_addresses (widget);
continue;
}
if (strcmp (name, "MULTICAST") == 0) {
/*gdm_chooser_find_mcaddr ();*/
continue;
}
result = NULL;
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_STREAM;
snprintf (serv_buf, sizeof (serv_buf), "%u", XDM_UDP_PORT);
serv = serv_buf;
gaierr = getaddrinfo (name, serv, &hints, &result);
if (gaierr != 0) {
g_warning ("Unable to get address info for name %s: %s", name, gai_strerror (gaierr));
continue;
}
for (ai = result; ai != NULL; ai = ai->ai_next) {
GdmAddress *address;
address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
if (address != NULL) {
widget->query_addresses = g_slist_append (widget->query_addresses, address);
}
}
freeaddrinfo (result);
}
if (widget->broadcast_addresses == NULL && widget->query_addresses == NULL) {
find_broadcast_addresses (widget);
}
}
static void
xdmcp_init (GdmHostChooserWidget *widget)
{
XdmcpHeader header;
int sockopts;
int res;
GIOChannel *ioc;
ARRAYofARRAY8 aanames;
sockopts = 1;
widget->socket_fd = -1;
/* Open socket for communication */
#ifdef ENABLE_IPV6
widget->socket_fd = socket (AF_INET6, SOCK_DGRAM, 0);
if (widget->socket_fd != -1) {
widget->have_ipv6 = TRUE;
#ifdef IPV6_V6ONLY
{
int zero = 0;
if (setsockopt(widget->socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) < 0)
g_warning("setsockopt(IPV6_V6ONLY): %s", g_strerror(errno));
}
#endif
}
#endif
if (! widget->have_ipv6) {
widget->socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
if (widget->socket_fd == -1) {
g_critical ("Could not create socket!");
}
}
res = setsockopt (widget->socket_fd,
SOL_SOCKET,
SO_BROADCAST,
(char *) &sockopts,
sizeof (sockopts));
if (res < 0) {
g_critical ("Could not set socket options!");
}
/* Assemble XDMCP BROADCAST_QUERY packet in static buffer */
memset (&header, 0, sizeof (XdmcpHeader));
header.opcode = (CARD16) BROADCAST_QUERY;
header.length = 1;
header.version = XDM_PROTOCOL_VERSION;
aanames.length = 0;
XdmcpWriteHeader (&widget->broadcast_buf, &header);
XdmcpWriteARRAYofARRAY8 (&widget->broadcast_buf, &aanames);
/* Assemble XDMCP QUERY packet in static buffer */
memset (&header, 0, sizeof (XdmcpHeader));
header.opcode = (CARD16) QUERY;
header.length = 1;
header.version = XDM_PROTOCOL_VERSION;
memset (&widget->query_buf, 0, sizeof (XdmcpBuffer));
XdmcpWriteHeader (&widget->query_buf, &header);
XdmcpWriteARRAYofARRAY8 (&widget->query_buf, &aanames);
add_hosts (widget);
ioc = g_io_channel_unix_new (widget->socket_fd);
g_io_channel_set_encoding (ioc, NULL, NULL);
g_io_channel_set_buffered (ioc, FALSE);
widget->io_watch_id = g_io_add_watch (ioc,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc)decode_packet,
widget);
g_io_channel_unref (ioc);
}
void
gdm_host_chooser_widget_refresh (GdmHostChooserWidget *widget)
{
g_return_if_fail (GDM_IS_HOST_CHOOSER_WIDGET (widget));
xdmcp_discover (widget);
}
GdmChooserHost *
gdm_host_chooser_widget_get_host (GdmHostChooserWidget *widget)
{
GdmChooserHost *host;
g_return_val_if_fail (GDM_IS_HOST_CHOOSER_WIDGET (widget), NULL);
host = NULL;
if (widget->current_host != NULL) {
host = g_object_ref (widget->current_host);
}
return host;
}
static void
_gdm_host_chooser_widget_set_kind_mask (GdmHostChooserWidget *widget,
int kind_mask)
{
if (widget->kind_mask != kind_mask) {
widget->kind_mask = kind_mask;
}
}
static void
gdm_host_chooser_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmHostChooserWidget *self;
self = GDM_HOST_CHOOSER_WIDGET (object);
switch (prop_id) {
case PROP_KIND_MASK:
_gdm_host_chooser_widget_set_kind_mask (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_host_chooser_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
gdm_host_chooser_widget_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmHostChooserWidget *widget;
widget = GDM_HOST_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_host_chooser_widget_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
xdmcp_init (widget);
xdmcp_discover (widget);
return G_OBJECT (widget);
}
static void
gdm_host_chooser_widget_dispose (GObject *object)
{
GdmHostChooserWidget *widget;
widget = GDM_HOST_CHOOSER_WIDGET (object);
g_debug ("Disposing host_chooser_widget");
if (widget->broadcast_addresses != NULL) {
g_slist_foreach (widget->broadcast_addresses,
(GFunc)gdm_address_free,
NULL);
g_slist_free (widget->broadcast_addresses);
widget->broadcast_addresses = NULL;
}
if (widget->query_addresses != NULL) {
g_slist_foreach (widget->query_addresses,
(GFunc)gdm_address_free,
NULL);
g_slist_free (widget->query_addresses);
widget->query_addresses = NULL;
}
if (widget->chooser_hosts != NULL) {
g_slist_foreach (widget->chooser_hosts,
(GFunc)g_object_unref,
NULL);
g_slist_free (widget->chooser_hosts);
widget->chooser_hosts = NULL;
}
widget->current_host = NULL;
G_OBJECT_CLASS (gdm_host_chooser_widget_parent_class)->dispose (object);
}
static void
gdm_host_chooser_widget_class_init (GdmHostChooserWidgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_host_chooser_widget_get_property;
object_class->set_property = gdm_host_chooser_widget_set_property;
object_class->constructor = gdm_host_chooser_widget_constructor;
object_class->dispose = gdm_host_chooser_widget_dispose;
g_object_class_install_property (object_class,
PROP_KIND_MASK,
g_param_spec_int ("kind-mask",
"kind mask",
"kind mask",
0,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
signals [HOST_ACTIVATED] = g_signal_new ("host-activated",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
on_host_selected (GtkTreeSelection *selection,
GdmHostChooserWidget *widget)
{
GtkTreeModel *model = NULL;
GtkTreeIter iter = {0};
GdmChooserHost *curhost;
curhost = NULL;
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
gtk_tree_model_get (model, &iter, CHOOSER_LIST_HOST_COLUMN, &curhost, -1);
}
widget->current_host = curhost;
}
static void
on_row_activated (GtkTreeView *tree_view,
GtkTreePath *tree_path,
GtkTreeViewColumn *tree_column,
GdmHostChooserWidget *widget)
{
g_signal_emit (widget, signals[HOST_ACTIVATED], 0);
}
static void
gdm_host_chooser_widget_init (GdmHostChooserWidget *widget)
{
GtkWidget *scrolled;
GtkTreeSelection *selection;
GtkTreeViewColumn *column;
GtkTreeModel *model;
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0);
widget->treeview = gtk_tree_view_new ();
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->treeview), FALSE);
g_signal_connect (widget->treeview,
"row-activated",
G_CALLBACK (on_row_activated),
widget);
gtk_container_add (GTK_CONTAINER (scrolled), widget->treeview);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->treeview));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
g_signal_connect (selection, "changed",
G_CALLBACK (on_host_selected),
widget);
model = (GtkTreeModel *)gtk_list_store_new (3,
GDK_TYPE_PIXBUF,
G_TYPE_STRING,
G_TYPE_POINTER);
gtk_tree_view_set_model (GTK_TREE_VIEW (widget->treeview), model);
column = gtk_tree_view_column_new_with_attributes ("Icon",
gtk_cell_renderer_pixbuf_new (),
"pixbuf", CHOOSER_LIST_ICON_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (widget->treeview), column);
column = gtk_tree_view_column_new_with_attributes ("Hostname",
gtk_cell_renderer_text_new (),
"markup", CHOOSER_LIST_LABEL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (widget->treeview), column);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
CHOOSER_LIST_LABEL_COLUMN,
GTK_SORT_ASCENDING);
}
GtkWidget *
gdm_host_chooser_widget_new (int kind_mask)
{
GObject *object;
object = g_object_new (GDM_TYPE_HOST_CHOOSER_WIDGET,
"orientation", GTK_ORIENTATION_VERTICAL,
"kind-mask", kind_mask,
NULL);
return GTK_WIDGET (object);
}

View file

@ -0,0 +1,41 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_HOST_CHOOSER_WIDGET_H
#define __GDM_HOST_CHOOSER_WIDGET_H
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gdm-chooser-host.h"
G_BEGIN_DECLS
#define GDM_TYPE_HOST_CHOOSER_WIDGET (gdm_host_chooser_widget_get_type ())
G_DECLARE_FINAL_TYPE (GdmHostChooserWidget, gdm_host_chooser_widget, GDM, HOST_CHOOSER_WIDGET, GtkBox)
GtkWidget * gdm_host_chooser_widget_new (int kind_mask);
void gdm_host_chooser_widget_refresh (GdmHostChooserWidget *widget);
GdmChooserHost * gdm_host_chooser_widget_get_host (GdmHostChooserWidget *widget);
G_END_DECLS
#endif /* __GDM_HOST_CHOOSER_WIDGET_H */

252
chooser/gdm-host-chooser.c Normal file
View file

@ -0,0 +1,252 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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
*/
#include "config.h"
#include <stdlib.h>
#include <libintl.h>
#include <locale.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <glib/gi18n.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include "gdm-common.h"
#include "gdm-log.h"
#include "gdm-chooser-host.h"
#include "gdm-host-chooser-dialog.h"
#define ACCESSIBILITY_KEY "/desktop/gnome/interface/accessibility"
static Atom AT_SPI_IOR;
static gboolean
assistive_registry_launch (void)
{
GPid pid;
GError *error;
const char *command;
char **argv;
gboolean res;
command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd";
argv = NULL;
error = NULL;
res = g_shell_parse_argv (command, NULL, &argv, &error);
if (! res) {
g_warning ("Unable to parse command: %s", error->message);
return FALSE;
}
error = NULL;
res = g_spawn_async (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH
| G_SPAWN_STDOUT_TO_DEV_NULL
| G_SPAWN_STDERR_TO_DEV_NULL,
NULL,
NULL,
&pid,
&error);
g_strfreev (argv);
if (! res) {
g_warning ("Unable to run command %s: %s", command, error->message);
return FALSE;
}
if (kill (pid, 0) < 0) {
g_warning ("at-spi-registryd not running");
return FALSE;
}
return TRUE;
}
static GdkFilterReturn
filter_watch (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
XEvent *xev = (XEvent *)xevent;
if (xev->xany.type == PropertyNotify
&& xev->xproperty.atom == AT_SPI_IOR) {
gtk_main_quit ();
return GDK_FILTER_REMOVE;
}
return GDK_FILTER_CONTINUE;
}
static gboolean
filter_timeout (gpointer data)
{
g_warning ("The accessibility registry was not found.");
gtk_main_quit ();
return FALSE;
}
static void
assistive_registry_start (void)
{
GdkWindow *root;
guint tid;
root = gdk_get_default_root_window ();
if ( ! AT_SPI_IOR) {
AT_SPI_IOR = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "AT_SPI_IOR", False);
}
gdk_window_set_events (root, GDK_PROPERTY_CHANGE_MASK);
if ( ! assistive_registry_launch ()) {
g_warning ("The accessibility registry could not be started.");
return;
}
gdk_window_add_filter (root, filter_watch, NULL);
tid = g_timeout_add_seconds (5, filter_timeout, NULL);
gtk_main ();
gdk_window_remove_filter (root, filter_watch, NULL);
g_source_remove (tid);
}
static void
at_set_gtk_modules (void)
{
GSList *modules_list;
GSList *l;
const char *old;
char **modules;
gboolean found_gail;
gboolean found_atk_bridge;
int n;
n = 0;
modules_list = NULL;
found_gail = FALSE;
found_atk_bridge = FALSE;
if ((old = g_getenv ("GTK_MODULES")) != NULL) {
modules = g_strsplit (old, ":", -1);
for (n = 0; modules[n]; n++) {
if (!strcmp (modules[n], "gail")) {
found_gail = TRUE;
} else if (!strcmp (modules[n], "atk-bridge")) {
found_atk_bridge = TRUE;
}
modules_list = g_slist_prepend (modules_list, modules[n]);
modules[n] = NULL;
}
g_free (modules);
}
if (!found_gail) {
modules_list = g_slist_prepend (modules_list, "gail");
++n;
}
if (!found_atk_bridge) {
modules_list = g_slist_prepend (modules_list, "atk-bridge");
++n;
}
modules = g_new (char *, n + 1);
modules[n--] = NULL;
for (l = modules_list; l; l = l->next) {
modules[n--] = g_strdup (l->data);
}
g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE);
g_strfreev (modules);
g_slist_free (modules_list);
}
static void
load_a11y (void)
{
assistive_registry_start ();
at_set_gtk_modules ();
}
int
main (int argc, char *argv[])
{
GtkWidget *chooser;
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
gdm_log_set_debug (TRUE);
g_debug ("Chooser for display %s xauthority:%s",
g_getenv ("DISPLAY"),
g_getenv ("XAUTHORITY"));
gdk_init (&argc, &argv);
load_a11y ();
gtk_init (&argc, &argv);
chooser = gdm_host_chooser_dialog_new (GDM_CHOOSER_HOST_KIND_MASK_ALL);
gtk_widget_set_size_request (chooser, 480, 600);
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) {
GdmChooserHost *host;
host = gdm_host_chooser_dialog_get_host (GDM_HOST_CHOOSER_DIALOG (chooser));
if (host != NULL) {
char *hostname;
/* FIXME: handle different host types here? */
hostname = NULL;
gdm_address_get_hostname (gdm_chooser_host_get_address (host), &hostname);
/* FIXME: fall back to numerical address? */
if (hostname != NULL) {
g_print ("hostname: %s\n", hostname);
g_free (hostname);
}
}
}
gtk_widget_destroy (chooser);
return 0;
}

50
chooser/meson.build Normal file
View file

@ -0,0 +1,50 @@
# Simple chooser
gdm_simple_chooser_src = [
'chooser-main.c',
'gdm-chooser-host.c',
'gdm-chooser-session.c',
'gdm-host-chooser-dialog.c',
'gdm-host-chooser-widget.c',
]
gdm_simple_chooser_deps = [
glib_dep,
gtk_dep,
libgdmcommon_dep,
libgdm_dep,
x_deps,
xdmcp_dep,
]
gdm_simple_chooser = executable('gdm-simple-chooser',
gdm_simple_chooser_src,
dependencies: gdm_simple_chooser_deps,
include_directories: config_h_dir,
install: true,
install_dir: get_option('libexecdir'),
)
# Host chooser
gdm_host_chooser_src = [
'gdm-host-chooser.c',
'gdm-chooser-host.c',
'gdm-host-chooser-dialog.c',
'gdm-host-chooser-widget.c',
]
gdm_host_chooser_deps = [
glib_dep,
gtk_dep,
libgdmcommon_dep,
libgdm_dep,
x_deps,
xdmcp_dep,
]
gdm_host_chooser = executable('gdm-host-chooser',
gdm_host_chooser_src,
dependencies: gdm_host_chooser_deps,
include_directories: config_h_dir,
install: true,
install_dir: get_option('libexecdir'),
)

3
common/gdb-cmd Normal file
View file

@ -0,0 +1,3 @@
bt
thread apply all bt full
q

543
common/gdm-address.c Normal file
View file

@ -0,0 +1,543 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <string.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/types.h>
#include <ifaddrs.h>
#ifndef G_OS_WIN32
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <glib-object.h>
#include "gdm-address.h"
struct _GdmAddress
{
struct sockaddr_storage *ss;
};
/* Register GdmAddress in the glib type system */
GType
gdm_address_get_type (void)
{
static GType addr_type = 0;
if (addr_type == 0) {
addr_type = g_boxed_type_register_static ("GdmAddress",
(GBoxedCopyFunc) gdm_address_copy,
(GBoxedFreeFunc) gdm_address_free);
}
return addr_type;
}
/**
* gdm_address_get_family_type:
* @address: A pointer to a #GdmAddress
*
* Use this function to retrive the address family of @address.
*
* Return value: The address family of @address.
**/
int
gdm_address_get_family_type (GdmAddress *address)
{
g_return_val_if_fail (address != NULL, -1);
return address->ss->ss_family;
}
/**
* gdm_address_new_from_sockaddr:
* @sa: A pointer to a sockaddr.
* @size: size of sockaddr in bytes.
*
* Creates a new #GdmAddress from @sa.
*
* Return value: The new #GdmAddress
* or %NULL if @sa was invalid or the address family isn't supported.
**/
GdmAddress *
gdm_address_new_from_sockaddr (struct sockaddr *sa,
size_t size)
{
GdmAddress *addr;
g_return_val_if_fail (sa != NULL, NULL);
g_return_val_if_fail (size >= sizeof (struct sockaddr), NULL);
g_return_val_if_fail (size <= sizeof (struct sockaddr_storage), NULL);
addr = g_new0 (GdmAddress, 1);
addr->ss = g_new0 (struct sockaddr_storage, 1);
memcpy (addr->ss, sa, size);
return addr;
}
/**
* gdm_address_get_sockaddr_storage:
* @address: A #GdmAddress
*
* This function tanslates @address into a equivalent
* sockaddr_storage
*
* Return value: A newly allocated sockaddr_storage structure the caller must free
* or %NULL if @address did not point to a valid #GdmAddress.
**/
struct sockaddr_storage *
gdm_address_get_sockaddr_storage (GdmAddress *address)
{
struct sockaddr_storage *ss;
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (address->ss != NULL, NULL);
ss = g_memdup2 (address->ss, sizeof (struct sockaddr_storage));
return ss;
}
struct sockaddr_storage *
gdm_address_peek_sockaddr_storage (GdmAddress *address)
{
g_return_val_if_fail (address != NULL, NULL);
return address->ss;
}
static gboolean
v4_v4_equal (const struct sockaddr_in *a,
const struct sockaddr_in *b)
{
return a->sin_addr.s_addr == b->sin_addr.s_addr;
}
#ifdef ENABLE_IPV6
static gboolean
v6_v6_equal (struct sockaddr_in6 *a,
struct sockaddr_in6 *b)
{
return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
}
#endif
#define SA(__s) ((struct sockaddr *) __s)
#define SIN(__s) ((struct sockaddr_in *) __s)
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
gboolean
gdm_address_equal (GdmAddress *a,
GdmAddress *b)
{
guint8 fam_a;
guint8 fam_b;
g_return_val_if_fail (a != NULL, FALSE);
g_return_val_if_fail (a->ss != NULL, FALSE);
g_return_val_if_fail (b != NULL, FALSE);
g_return_val_if_fail (b->ss != NULL, FALSE);
fam_a = a->ss->ss_family;
fam_b = b->ss->ss_family;
if (fam_a == AF_INET && fam_b == AF_INET) {
return v4_v4_equal (SIN (a->ss), SIN (b->ss));
}
#ifdef ENABLE_IPV6
else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
}
#endif
return FALSE;
}
/* for debugging */
static const char *
address_family_str (GdmAddress *address)
{
const char *str;
switch (address->ss->ss_family) {
case AF_INET:
str = "inet";
break;
case AF_INET6:
str = "inet6";
break;
case AF_UNIX:
str = "unix";
break;
case AF_UNSPEC:
str = "unspecified";
break;
default:
str = "unknown";
break;
}
return str;
}
static void
_gdm_address_debug (GdmAddress *address,
const char *host,
const char *port)
{
g_debug ("Address family:%d (%s) host:%s port:%s local:%d loopback:%d",
address->ss->ss_family,
address_family_str (address) ? address_family_str (address) : "(null)",
host ? host : "(null)",
port ? port : "(null)",
gdm_address_is_local (address),
gdm_address_is_loopback (address));
}
void
gdm_address_debug (GdmAddress *address)
{
g_autofree char *hostname = NULL;
g_autofree char *host = NULL;
g_autofree char *port = NULL;
g_return_if_fail (address != NULL);
gdm_address_get_numeric_info (address, &host, &port);
_gdm_address_debug (address, host, port);
}
gboolean
gdm_address_get_hostname (GdmAddress *address,
char **hostnamep)
{
char host [NI_MAXHOST];
int res;
gboolean ret;
g_return_val_if_fail (address != NULL, FALSE);
g_return_val_if_fail (address->ss != NULL, FALSE);
ret = FALSE;
host [0] = '\0';
res = getnameinfo ((const struct sockaddr *)address->ss,
(int) gdm_sockaddr_len (address->ss),
host, sizeof (host),
NULL, 0,
0);
if (res == 0) {
ret = TRUE;
goto done;
} else {
const char *err_msg;
err_msg = gai_strerror (res);
g_warning ("Unable to lookup hostname: %s",
err_msg ? err_msg : "(null)");
_gdm_address_debug (address, NULL, NULL);
}
/* try numeric? */
done:
if (hostnamep != NULL) {
*hostnamep = g_strdup (host);
}
return ret;
}
gboolean
gdm_address_get_numeric_info (GdmAddress *address,
char **hostp,
char **servp)
{
char host [NI_MAXHOST];
char serv [NI_MAXSERV];
int res;
gboolean ret;
g_return_val_if_fail (address != NULL, FALSE);
g_return_val_if_fail (address->ss != NULL, FALSE);
ret = FALSE;
host [0] = '\0';
serv [0] = '\0';
res = getnameinfo ((const struct sockaddr *)address->ss,
(int) gdm_sockaddr_len (address->ss),
host, sizeof (host),
serv, sizeof (serv),
NI_NUMERICHOST | NI_NUMERICSERV);
if (res != 0) {
const char *err_msg;
err_msg = gai_strerror (res);
g_warning ("Unable to lookup numeric info: %s",
err_msg ? err_msg : "(null)");
_gdm_address_debug (address, NULL, NULL);
} else {
ret = TRUE;
}
if (servp != NULL) {
if (g_str_has_prefix (serv, "::ffff:")) {
*servp = g_strdup (serv + 7);
} else {
*servp = g_strdup (serv);
}
}
if (hostp != NULL) {
if (g_str_has_prefix (host, "::ffff:")) {
*hostp = g_strdup (host + 7);
} else {
*hostp = g_strdup (host);
}
}
return ret;
}
gboolean
gdm_address_is_loopback (GdmAddress *address)
{
g_return_val_if_fail (address != NULL, FALSE);
g_return_val_if_fail (address->ss != NULL, FALSE);
switch (address->ss->ss_family){
#ifdef AF_INET6
case AF_INET6:
return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)address->ss)->sin6_addr);
break;
#endif
case AF_INET:
return (INADDR_LOOPBACK == htonl (((struct sockaddr_in *)address->ss)->sin_addr.s_addr));
break;
default:
break;
}
return FALSE;
}
static void
add_local_siocgifconf (GList **list)
{
struct ifconf ifc;
struct ifreq ifreq;
struct ifreq *ifr;
struct ifreq *the_end;
int sock;
char buf[BUFSIZ];
if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) {
perror ("socket");
return;
}
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) {
perror ("SIOCGIFCONF");
close (sock);
return;
}
/* Get IP address of each active IP network interface. */
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
if (ifr->ifr_addr.sa_family == AF_INET) {
/* IP net interface */
ifreq = *ifr;
if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
perror("SIOCGIFFLAGS");
} else if (ifreq.ifr_flags & IFF_UP) { /* active interface */
if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
perror("SIOCGIFADDR");
} else {
GdmAddress *address;
address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr,
sizeof (struct sockaddr));
*list = g_list_append (*list, address);
}
}
}
/* Support for variable-length addresses. */
#ifdef HAS_SA_LEN
ifr = (struct ifreq *) ((caddr_t) ifr
+ ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
#endif
}
close (sock);
}
static void
add_local_addrinfo (GList **list)
{
struct ifaddrs *interface_addresses;
struct ifaddrs *interface_address;
if (getifaddrs (&interface_addresses) < 0) {
g_debug ("Could not get local interface addresses: %m");
return;
}
for (interface_address = interface_addresses; interface_address != NULL; interface_address = interface_address->ifa_next) {
GdmAddress *address;
int family;
if (interface_address->ifa_addr == NULL)
continue;
family = interface_address->ifa_addr->sa_family;
if (family != AF_INET && family != AF_INET6)
continue;
g_debug ("Local interface %s found (family: %s)\n",
interface_address->ifa_name,
family == AF_INET ? "AF_INET" : "AF_INET6");
address = gdm_address_new_from_sockaddr (interface_address->ifa_addr,
(family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6));
*list = g_list_append (*list, address);
}
freeifaddrs (interface_addresses);
}
const GList *
gdm_address_peek_local_list (void)
{
static GList *list = NULL;
static time_t last_time = 0;
/* Don't check more then every 5 seconds */
if (last_time + 5 > time (NULL)) {
return list;
}
g_list_foreach (list, (GFunc)gdm_address_free, NULL);
g_list_free (list);
list = NULL;
last_time = time (NULL);
add_local_siocgifconf (&list);
add_local_addrinfo (&list);
return list;
}
gboolean
gdm_address_is_local (GdmAddress *address)
{
const GList *list;
g_return_val_if_fail (address != NULL, FALSE);
if (gdm_address_is_loopback (address)) {
return TRUE;
}
list = gdm_address_peek_local_list ();
while (list != NULL) {
GdmAddress *addr = list->data;
if (gdm_address_equal (address, addr)) {
return TRUE;
}
list = list->next;
}
return FALSE;
}
/**
* gdm_address_copy:
* @address: A #GdmAddress.
*
* Duplicates @address.
*
* Return value: Duplicated @address or %NULL if @address was not valid.
**/
GdmAddress *
gdm_address_copy (GdmAddress *address)
{
GdmAddress *addr;
g_return_val_if_fail (address != NULL, NULL);
addr = g_new0 (GdmAddress, 1);
addr->ss = g_memdup2 (address->ss, sizeof (struct sockaddr_storage));
return addr;
}
/**
* gdm_address_free:
* @address: A #GdmAddress.
*
* Frees the memory allocated for @address.
**/
void
gdm_address_free (GdmAddress *address)
{
g_return_if_fail (address != NULL);
g_free (address->ss);
g_free (address);
}

73
common/gdm-address.h Normal file
View file

@ -0,0 +1,73 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_ADDRESS_H
#define __GDM_ADDRESS_H
#include <glib-object.h>
#ifndef G_OS_WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <winsock2.h>
#undef interface
#endif
G_BEGIN_DECLS
#define GDM_TYPE_ADDRESS (gdm_address_get_type ())
#define gdm_sockaddr_len(sa) ((sa)->ss_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
typedef struct _GdmAddress GdmAddress;
GType gdm_address_get_type (void);
GdmAddress * gdm_address_new_from_sockaddr (struct sockaddr *sa,
size_t size);
int gdm_address_get_family_type (GdmAddress *address);
struct sockaddr_storage *gdm_address_get_sockaddr_storage (GdmAddress *address);
struct sockaddr_storage *gdm_address_peek_sockaddr_storage (GdmAddress *address);
gboolean gdm_address_get_hostname (GdmAddress *address,
char **hostname);
gboolean gdm_address_get_numeric_info (GdmAddress *address,
char **numeric_hostname,
char **service);
gboolean gdm_address_is_local (GdmAddress *address);
gboolean gdm_address_is_loopback (GdmAddress *address);
gboolean gdm_address_equal (GdmAddress *a,
GdmAddress *b);
GdmAddress * gdm_address_copy (GdmAddress *address);
void gdm_address_free (GdmAddress *address);
void gdm_address_debug (GdmAddress *address);
const GList * gdm_address_peek_local_list (void);
G_END_DECLS
#endif /* __GDM_ADDRESS_H */

1122
common/gdm-common.c Normal file

File diff suppressed because it is too large Load diff

110
common/gdm-common.h Normal file
View file

@ -0,0 +1,110 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GDM_COMMON_H
#define _GDM_COMMON_H
#include <glib-unix.h>
#include <gio/gio.h>
#include <pwd.h>
#include <errno.h>
#define REGISTER_SESSION_TIMEOUT 10
#define VE_IGNORE_EINTR(expr) \
do { \
errno = 0; \
expr; \
} while G_UNLIKELY (errno == EINTR);
#define GDM_SYSTEMD_SESSION_REQUIRE_ONLINE 0
GQuark gdm_common_error_quark (void);
#define GDM_COMMON_ERROR gdm_common_error_quark()
typedef char * (*GdmExpandVarFunc) (const char *var,
gpointer user_data);
typedef void (*GdmLoadEnvVarFunc) (const char *var,
const char *value,
gpointer user_data);
G_BEGIN_DECLS
int gdm_wait_on_pid (int pid);
int gdm_wait_on_and_disown_pid (int pid,
int timeout);
int gdm_signal_pid (int pid,
int signal);
gboolean gdm_find_display_session (GPid pid,
const uid_t uid,
char **out_session_id,
GError **error);
gboolean gdm_get_pwent_for_name (const char *name,
struct passwd **pwentp);
gboolean gdm_clear_close_on_exec_flag (int fd);
char *gdm_generate_random_bytes (gsize size,
GError **error);
gboolean gdm_get_login_window_session_id (const char *seat_id,
char **session_id);
gboolean gdm_goto_login_session (GCancellable *cancellable,
GError **error);
GPtrArray *gdm_get_script_environment (const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_run_script (const char *dir,
const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_shell_var_is_valid_char (char c,
gboolean first);
char * gdm_shell_expand (const char *str,
GdmExpandVarFunc expand_func,
gpointer user_data);
gboolean gdm_activate_session_by_id (GDBusConnection *connection,
GCancellable *cancellable,
const char *seat_id,
const char *session_id);
gboolean gdm_terminate_session_by_id (GDBusConnection *connection,
GCancellable *cancellable,
const char *session_id);
void gdm_load_env_d (GdmLoadEnvVarFunc load_env_func,
GdmExpandVarFunc expand_func,
gpointer user_data);
G_END_DECLS
#endif /* _GDM_COMMON_H */

145
common/gdm-log.c Normal file
View file

@ -0,0 +1,145 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
* Authors: William Jon McCann <mccann@jhu.edu>
*
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <syslog.h>
#include <systemd/sd-daemon.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "gdm-log.h"
static gboolean initialized = FALSE;
static gboolean is_sd_booted = FALSE;
static gboolean debug_enabled = FALSE;
static gint
get_syslog_priority_from_log_level (GLogLevelFlags log_level)
{
switch (log_level & G_LOG_LEVEL_MASK) {
case G_LOG_FLAG_FATAL:
return LOG_EMERG;
case G_LOG_LEVEL_ERROR:
/* fatal error - a critical error, in the syslog world */
return LOG_CRIT;
case G_LOG_LEVEL_CRITICAL:
/* critical warning - an error, in the syslog world */
return LOG_ERR;
case G_LOG_LEVEL_WARNING:
case G_LOG_LEVEL_MESSAGE:
return LOG_NOTICE;
case G_LOG_LEVEL_INFO:
return LOG_INFO;
case G_LOG_LEVEL_DEBUG:
default:
return LOG_DEBUG;
}
}
static void
gdm_log_default_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer unused_data)
{
int priority;
gdm_log_init ();
if ((log_level & G_LOG_LEVEL_MASK) == G_LOG_LEVEL_DEBUG &&
!debug_enabled) {
return;
}
/* Process the message prefix and priority */
priority = get_syslog_priority_from_log_level (log_level);
if (is_sd_booted) {
fprintf (stderr,
"<%d>%s%s%s\n",
priority,
log_domain != NULL? log_domain : "",
log_domain != NULL? ": " : "",
message);
fflush (stderr);
} else {
syslog (priority,
"%s%s%s\n",
log_domain != NULL? log_domain : "",
log_domain != NULL? ": " : "",
message);
}
}
void
gdm_log_toggle_debug (void)
{
gdm_log_set_debug (!debug_enabled);
}
void
gdm_log_set_debug (gboolean debug)
{
g_assert (initialized);
if (debug_enabled == debug) {
return;
}
if (debug) {
debug_enabled = debug;
g_debug ("Enabling debugging");
} else {
g_debug ("Disabling debugging");
debug_enabled = debug;
}
}
void
gdm_log_init (void)
{
if (initialized)
return;
initialized = TRUE;
g_log_set_default_handler (gdm_log_default_handler, NULL);
}
void
gdm_log_shutdown (void)
{
if (!initialized)
return;
if (!is_sd_booted)
closelog ();
initialized = FALSE;
}

38
common/gdm-log.h Normal file
View file

@ -0,0 +1,38 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
* Authors: William Jon McCann <mccann@jhu.edu>
*
*/
#ifndef __GDM_LOG_H
#define __GDM_LOG_H
#include <stdarg.h>
#include <glib.h>
G_BEGIN_DECLS
void gdm_log_set_debug (gboolean debug);
void gdm_log_toggle_debug (void);
void gdm_log_init (void);
void gdm_log_shutdown (void);
G_END_DECLS
#endif /* __GDM_LOG_H */

72
common/gdm-profile.c Normal file
View file

@ -0,0 +1,72 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2005 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
* Authors: William Jon McCann <mccann@jhu.edu>
*
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "gdm-profile.h"
void
_gdm_profile_log (const char *func,
const char *note,
const char *format,
...)
{
va_list args;
g_autofree char *str = NULL;
g_autofree char *formatted = NULL;
const char *prgname;
if (format == NULL) {
formatted = g_strdup ("");
} else {
va_start (args, format);
formatted = g_strdup_vprintf (format, args);
va_end (args);
}
prgname = g_get_prgname();
if (func != NULL) {
str = g_strdup_printf ("MARK: %s %s: %s %s",
prgname ? prgname : "(null)",
func,
note ? note : "",
formatted);
} else {
str = g_strdup_printf ("MARK: %s: %s %s",
prgname ? prgname : "(null)",
note ? note : "",
formatted);
}
g_access (str, F_OK);
}

53
common/gdm-profile.h Normal file
View file

@ -0,0 +1,53 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2005 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
* Authors: William Jon McCann <mccann@jhu.edu>
*
*/
#ifndef __GDM_PROFILE_H
#define __GDM_PROFILE_H
#include <glib.h>
G_BEGIN_DECLS
#ifdef ENABLE_PROFILING
#ifdef G_HAVE_ISO_VARARGS
#define gdm_profile_start(...) _gdm_profile_log (G_STRFUNC, "start", __VA_ARGS__)
#define gdm_profile_end(...) _gdm_profile_log (G_STRFUNC, "end", __VA_ARGS__)
#define gdm_profile_msg(...) _gdm_profile_log (NULL, NULL, __VA_ARGS__)
#elif defined(G_HAVE_GNUC_VARARGS)
#define gdm_profile_start(format...) _gdm_profile_log (G_STRFUNC, "start", format)
#define gdm_profile_end(format...) _gdm_profile_log (G_STRFUNC, "end", format)
#define gdm_profile_msg(format...) _gdm_profile_log (NULL, NULL, format)
#endif
#else
#define gdm_profile_start(...)
#define gdm_profile_end(...)
#define gdm_profile_msg(...)
#endif
void _gdm_profile_log (const char *func,
const char *note,
const char *format,
...) G_GNUC_PRINTF (3, 4);
G_END_DECLS
#endif /* __GDM_PROFILE_H */

View file

@ -0,0 +1,169 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-settings-backend.h"
enum {
VALUE_CHANGED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_settings_backend_class_init (GdmSettingsBackendClass *klass);
static void gdm_settings_backend_init (GdmSettingsBackend *settings_backend);
static void gdm_settings_backend_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (GdmSettingsBackend, gdm_settings_backend, G_TYPE_OBJECT)
GQuark
gdm_settings_backend_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_settings_backend_error");
}
return ret;
}
static gboolean
gdm_settings_backend_real_get_value (GdmSettingsBackend *settings_backend,
const char *key,
char **value,
GError **error)
{
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (settings_backend), FALSE);
return FALSE;
}
static gboolean
gdm_settings_backend_real_set_value (GdmSettingsBackend *settings_backend,
const char *key,
const char *value,
GError **error)
{
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (settings_backend), FALSE);
return FALSE;
}
gboolean
gdm_settings_backend_get_value (GdmSettingsBackend *settings_backend,
const char *key,
char **value,
GError **error)
{
gboolean ret;
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (settings_backend), FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_object_ref (settings_backend);
ret = GDM_SETTINGS_BACKEND_GET_CLASS (settings_backend)->get_value (settings_backend, key, value, error);
g_object_unref (settings_backend);
return ret;
}
gboolean
gdm_settings_backend_set_value (GdmSettingsBackend *settings_backend,
const char *key,
const char *value,
GError **error)
{
gboolean ret;
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (settings_backend), FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_object_ref (settings_backend);
ret = GDM_SETTINGS_BACKEND_GET_CLASS (settings_backend)->set_value (settings_backend, key, value, error);
g_object_unref (settings_backend);
return ret;
}
void
gdm_settings_backend_value_changed (GdmSettingsBackend *settings_backend,
const char *key,
const char *old_value,
const char *new_value)
{
g_return_if_fail (GDM_IS_SETTINGS_BACKEND (settings_backend));
g_signal_emit (settings_backend, signals[VALUE_CHANGED], 0, key, old_value, new_value);
}
static void
gdm_settings_backend_class_init (GdmSettingsBackendClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdm_settings_backend_finalize;
klass->get_value = gdm_settings_backend_real_get_value;
klass->set_value = gdm_settings_backend_real_set_value;
signals [VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdmSettingsBackendClass, value_changed),
NULL,
NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE,
3,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING);
}
static void
gdm_settings_backend_init (GdmSettingsBackend *settings_backend)
{
}
static void
gdm_settings_backend_finalize (GObject *object)
{
g_return_if_fail (GDM_IS_SETTINGS_BACKEND (object));
G_OBJECT_CLASS (gdm_settings_backend_parent_class)->finalize (object);
}

View file

@ -0,0 +1,79 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SETTINGS_BACKEND_H
#define __GDM_SETTINGS_BACKEND_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SETTINGS_BACKEND (gdm_settings_backend_get_type ())
G_DECLARE_DERIVABLE_TYPE (GdmSettingsBackend, gdm_settings_backend, GDM, SETTINGS_BACKEND, GObject)
struct _GdmSettingsBackendClass
{
GObjectClass parent_class;
/* methods */
gboolean (*get_value) (GdmSettingsBackend *settings_backend,
const char *key,
char **value,
GError **error);
gboolean (*set_value) (GdmSettingsBackend *settings_backend,
const char *key,
const char *value,
GError **error);
/* signals */
void (* value_changed) (GdmSettingsBackend *settings_backend,
const char *key,
const char *old_value,
const char **new_value);
};
typedef enum
{
GDM_SETTINGS_BACKEND_ERROR_GENERAL,
GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND
} GdmSettingsBackendError;
#define GDM_SETTINGS_BACKEND_ERROR gdm_settings_backend_error_quark ()
GQuark gdm_settings_backend_error_quark (void);
gboolean gdm_settings_backend_get_value (GdmSettingsBackend *settings_backend,
const char *key,
char **value,
GError **error);
gboolean gdm_settings_backend_set_value (GdmSettingsBackend *settings_backend,
const char *key,
const char *value,
GError **error);
void gdm_settings_backend_value_changed (GdmSettingsBackend *settings_backend,
const char *key,
const char *old_value,
const char *new_value);
G_END_DECLS
#endif /* __GDM_SETTINGS_BACKEND_H */

View file

@ -0,0 +1,399 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include "gdm-settings-desktop-backend.h"
struct _GdmSettingsDesktopBackend
{
GdmSettingsBackend parent;
char *filename;
GKeyFile *key_file;
gboolean dirty;
guint save_id;
};
enum {
PROP_0,
PROP_FILENAME,
};
static void gdm_settings_desktop_backend_class_init (GdmSettingsDesktopBackendClass *klass);
static void gdm_settings_desktop_backend_init (GdmSettingsDesktopBackend *settings_desktop_backend);
static void gdm_settings_desktop_backend_finalize (GObject *object);
G_DEFINE_TYPE (GdmSettingsDesktopBackend, gdm_settings_desktop_backend, GDM_TYPE_SETTINGS_BACKEND)
static void
_gdm_settings_desktop_backend_set_file_name (GdmSettingsDesktopBackend *backend,
const char *filename)
{
gboolean res;
g_autoptr(GError) error = NULL;
g_autofree char *contents = NULL;
g_free (backend->filename);
backend->filename = g_strdup (filename);
backend->key_file = g_key_file_new ();
res = g_key_file_load_from_file (backend->key_file,
backend->filename,
G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
&error);
if (! res) {
g_warning ("Unable to load file '%s': %s", backend->filename, error->message);
}
contents = g_key_file_to_data (backend->key_file, NULL, NULL);
if (contents != NULL) {
g_debug ("GdmSettings: %s is:\n%s\n", backend->filename, contents);
}
}
static void
gdm_settings_desktop_backend_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmSettingsDesktopBackend *self;
self = GDM_SETTINGS_DESKTOP_BACKEND (object);
switch (prop_id) {
case PROP_FILENAME:
_gdm_settings_desktop_backend_set_file_name (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_settings_desktop_backend_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmSettingsDesktopBackend *self;
self = GDM_SETTINGS_DESKTOP_BACKEND (object);
switch (prop_id) {
case PROP_FILENAME:
g_value_set_string (value, self->filename);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
parse_key_string (const char *keystring,
char **group,
char **key,
char **locale,
char **value)
{
g_auto(GStrv) split1 = NULL;
g_auto(GStrv) split2 = NULL;
char *g;
char *k;
char *l;
char *v;
char *tmp1;
char *tmp2;
g_return_val_if_fail (keystring != NULL, FALSE);
g = k = v = l = NULL;
if (group != NULL) {
*group = g;
}
if (key != NULL) {
*key = k;
}
if (locale != NULL) {
*locale = l;
}
if (value != NULL) {
*value = v;
}
/*g_debug ("Attempting to parse key string: %s", keystring);*/
split1 = g_strsplit (keystring, "/", 2);
if (split1 == NULL
|| split1 [0] == NULL
|| split1 [1] == NULL
|| split1 [0][0] == '\0'
|| split1 [1][0] == '\0') {
g_warning ("GdmSettingsDesktopBackend: invalid key: %s", keystring);
return FALSE;
}
g = split1 [0];
split2 = g_strsplit (split1 [1], "=", 2);
if (split2 == NULL) {
k = split1 [1];
} else {
k = split2 [0];
v = split2 [1];
}
/* trim off the locale */
tmp1 = strchr (k, '[');
tmp2 = strchr (k, ']');
if (tmp1 != NULL && tmp2 != NULL && tmp2 > tmp1) {
l = g_strndup (tmp1 + 1, tmp2 - tmp1 - 1);
*tmp1 = '\0';
}
if (group != NULL) {
*group = g_strdup (g);
}
if (key != NULL) {
*key = g_strdup (k);
}
if (locale != NULL) {
*locale = g_strdup (l);
}
if (value != NULL) {
*value = g_strdup (v);
}
return TRUE;
}
static gboolean
gdm_settings_desktop_backend_get_value (GdmSettingsBackend *backend,
const char *key,
char **value,
GError **error)
{
g_autoptr(GError) local_error = NULL;
g_autofree char *val = NULL;
g_autofree char *g = NULL;
g_autofree char *k = NULL;
g_autofree char *l = NULL;
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (backend), FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
*value = NULL;
/*GDM_SETTINGS_BACKEND_CLASS (gdm_settings_desktop_backend_parent_class)->get_value (display);*/
if (! parse_key_string (key, &g, &k, &l, NULL)) {
g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
return FALSE;
}
/*g_debug ("Getting key: %s %s %s", g, k, l);*/
val = g_key_file_get_value (GDM_SETTINGS_DESKTOP_BACKEND (backend)->key_file,
g,
k,
&local_error);
if (local_error != NULL) {
g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
return FALSE;
}
*value = g_strdup (val);
return TRUE;
}
static void
save_settings (GdmSettingsDesktopBackend *backend)
{
g_autoptr(GError) local_error = NULL;
g_autofree char *contents = NULL;
gsize length;
if (! backend->dirty) {
return;
}
g_debug ("Saving settings to %s", backend->filename);
contents = g_key_file_to_data (backend->key_file, &length, &local_error);
if (local_error != NULL) {
g_warning ("Unable to save settings: %s", local_error->message);
return;
}
g_file_set_contents (backend->filename,
contents,
length,
&local_error);
if (local_error != NULL) {
g_warning ("Unable to save settings: %s", local_error->message);
return;
}
backend->dirty = FALSE;
}
static gboolean
save_settings_timer (GdmSettingsDesktopBackend *backend)
{
save_settings (backend);
backend->save_id = 0;
return FALSE;
}
static void
queue_save (GdmSettingsDesktopBackend *backend)
{
if (! backend->dirty) {
return;
}
if (backend->save_id != 0) {
/* already pending */
return;
}
backend->save_id = g_timeout_add_seconds (5, (GSourceFunc)save_settings_timer, backend);
}
static gboolean
gdm_settings_desktop_backend_set_value (GdmSettingsBackend *backend,
const char *key,
const char *value,
GError **error)
{
g_autofree char *old_val = NULL;
g_autofree char *g = NULL;
g_autofree char *k = NULL;
g_autofree char *l = NULL;
g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (backend), FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
/*GDM_SETTINGS_BACKEND_CLASS (gdm_settings_desktop_backend_parent_class)->get_value (display);*/
if (! parse_key_string (key, &g, &k, &l, NULL)) {
g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
return FALSE;
}
old_val = g_key_file_get_value (GDM_SETTINGS_DESKTOP_BACKEND (backend)->key_file,
g,
k,
NULL);
/*g_debug ("Setting key: %s %s %s", g, k, l);*/
g_key_file_set_value (GDM_SETTINGS_DESKTOP_BACKEND (backend)->key_file,
g,
k,
value);
GDM_SETTINGS_DESKTOP_BACKEND (backend)->dirty = TRUE;
queue_save (GDM_SETTINGS_DESKTOP_BACKEND (backend));
gdm_settings_backend_value_changed (backend, key, old_val, value);
return TRUE;
}
static void
gdm_settings_desktop_backend_class_init (GdmSettingsDesktopBackendClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdmSettingsBackendClass *backend_class = GDM_SETTINGS_BACKEND_CLASS (klass);
object_class->get_property = gdm_settings_desktop_backend_get_property;
object_class->set_property = gdm_settings_desktop_backend_set_property;
object_class->finalize = gdm_settings_desktop_backend_finalize;
backend_class->get_value = gdm_settings_desktop_backend_get_value;
backend_class->set_value = gdm_settings_desktop_backend_set_value;
g_object_class_install_property (object_class,
PROP_FILENAME,
g_param_spec_string ("filename",
"File Name",
"The name of the configuration file",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
gdm_settings_desktop_backend_init (GdmSettingsDesktopBackend *backend)
{
}
static void
gdm_settings_desktop_backend_finalize (GObject *object)
{
GdmSettingsDesktopBackend *backend;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_SETTINGS_DESKTOP_BACKEND (object));
backend = GDM_SETTINGS_DESKTOP_BACKEND (object);
save_settings (backend);
g_key_file_free (backend->key_file);
g_free (backend->filename);
G_OBJECT_CLASS (gdm_settings_desktop_backend_parent_class)->finalize (object);
}
GdmSettingsBackend *
gdm_settings_desktop_backend_new (const char* filename)
{
GObject *object;
g_return_val_if_fail (filename != NULL, NULL);
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
return NULL;
object = g_object_new (GDM_TYPE_SETTINGS_DESKTOP_BACKEND,
"filename", filename,
NULL);
return GDM_SETTINGS_BACKEND (object);
}

View file

@ -0,0 +1,37 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SETTINGS_DESKTOP_BACKEND_H
#define __GDM_SETTINGS_DESKTOP_BACKEND_H
#include <glib-object.h>
#include "gdm-settings-backend.h"
G_BEGIN_DECLS
#define GDM_TYPE_SETTINGS_DESKTOP_BACKEND (gdm_settings_desktop_backend_get_type ())
G_DECLARE_FINAL_TYPE (GdmSettingsDesktopBackend, gdm_settings_desktop_backend, GDM, SETTINGS_DESKTOP_BACKEND, GdmSettingsBackend)
GdmSettingsBackend *gdm_settings_desktop_backend_new (const char* filename);
G_END_DECLS
#endif /* __GDM_SETTINGS_DESKTOP_BACKEND_H */

View file

@ -0,0 +1,244 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include "gdm-settings.h"
#include "gdm-settings-utils.h"
#include "gdm-settings-direct.h"
static GHashTable *schemas;
static GdmSettings *settings_object;
static GdmSettingsEntry *
get_entry_for_key (const char *key)
{
GdmSettingsEntry *entry;
entry = g_hash_table_lookup (schemas, key);
return entry;
}
static void
assert_signature (GdmSettingsEntry *entry,
const char *signature)
{
const char *sig;
sig = gdm_settings_entry_get_signature (entry);
g_assert (sig != NULL);
g_assert (signature != NULL);
g_assert (strcmp (signature, sig) == 0);
}
static gboolean
get_value (const char *key,
char **value)
{
g_autofree char *str = NULL;
gboolean res;
res = gdm_settings_get_value (settings_object, key, &str, NULL);
if (! res) {
return FALSE;
}
if (value != NULL) {
*value = g_strdup (str);
}
return TRUE;
}
gboolean
gdm_settings_direct_get_int (const char *key,
int *value)
{
GdmSettingsEntry *entry;
gboolean ret;
gboolean res;
g_autofree char *str = NULL;
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
entry = get_entry_for_key (key);
g_assert (entry != NULL);
assert_signature (entry, "i");
res = get_value (key, &str);
if (! res) {
/* use the default */
str = g_strdup (gdm_settings_entry_get_default_value (entry));
}
ret = gdm_settings_parse_value_as_integer (str, value);
return ret;
}
gboolean
gdm_settings_direct_get_uint (const char *key,
uint *value)
{
gboolean ret;
int intvalue;
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
ret = gdm_settings_direct_get_int (key, &intvalue);
if (intvalue >= 0)
*value = intvalue;
else
ret = FALSE;
return ret;
}
gboolean
gdm_settings_direct_get_boolean (const char *key,
gboolean *value)
{
GdmSettingsEntry *entry;
gboolean ret;
gboolean res;
g_autofree char *str = NULL;
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
entry = get_entry_for_key (key);
g_assert (entry != NULL);
assert_signature (entry, "b");
res = get_value (key, &str);
if (! res) {
/* use the default */
str = g_strdup (gdm_settings_entry_get_default_value (entry));
}
ret = gdm_settings_parse_value_as_boolean (str, value);
return ret;
}
gboolean
gdm_settings_direct_get_string (const char *key,
char **value)
{
GdmSettingsEntry *entry;
gboolean ret;
gboolean res;
g_autofree char *str = NULL;
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
entry = get_entry_for_key (key);
g_assert (entry != NULL);
assert_signature (entry, "s");
ret = TRUE;
res = get_value (key, &str);
if (! res) {
/* use the default */
str = g_strdup (gdm_settings_entry_get_default_value (entry));
}
*value = g_strdup (str);
return ret;
}
static void
hashify_list (GdmSettingsEntry *entry,
gpointer data)
{
g_hash_table_insert (schemas, g_strdup (gdm_settings_entry_get_key (entry)), entry);
}
gboolean
gdm_settings_direct_init (GdmSettings *settings,
const char *file,
const char *root)
{
GSList *list;
g_return_val_if_fail (file != NULL, FALSE);
g_return_val_if_fail (root != NULL, FALSE);
g_debug ("Settings Direct Init");
if (schemas != NULL) {
g_hash_table_unref (schemas);
schemas = NULL;
}
if (! gdm_settings_parse_schemas (file, root, &list)) {
g_warning ("Unable to parse schemas");
return FALSE;
}
schemas = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)gdm_settings_entry_free);
g_slist_foreach (list, (GFunc)hashify_list, NULL);
settings_object = settings;
return TRUE;
}
void
gdm_settings_direct_reload (void)
{
if (!settings_object)
return;
gdm_settings_reload (settings_object);
}
void
gdm_settings_direct_shutdown (void)
{
}

View file

@ -0,0 +1,48 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SETTINGS_DIRECT_H
#define __GDM_SETTINGS_DIRECT_H
#include <glib-object.h>
#include "gdm-settings.h"
G_BEGIN_DECLS
gboolean gdm_settings_direct_init (GdmSettings *settings,
const char *schemas_file,
const char *root);
void gdm_settings_direct_reload (void);
void gdm_settings_direct_shutdown (void);
gboolean gdm_settings_direct_get_int (const char *key,
int *value);
gboolean gdm_settings_direct_get_uint (const char *key,
uint *value);
gboolean gdm_settings_direct_get_boolean (const char *key,
gboolean *value);
gboolean gdm_settings_direct_get_string (const char *key,
char **value);
G_END_DECLS
#endif /* __GDM_SETTINGS_DIRECT_H */

View file

@ -0,0 +1,66 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GDM_SETTINGS_KEYS_H
#define _GDM_SETTINGS_KEYS_H
#include <glib.h>
G_BEGIN_DECLS
#define GDM_KEY_USER "daemon/User"
#define GDM_KEY_GROUP "daemon/Group"
#define GDM_KEY_AUTO_LOGIN_ENABLE "daemon/AutomaticLoginEnable"
#define GDM_KEY_AUTO_LOGIN_USER "daemon/AutomaticLogin"
#define GDM_KEY_TIMED_LOGIN_ENABLE "daemon/TimedLoginEnable"
#define GDM_KEY_TIMED_LOGIN_USER "daemon/TimedLogin"
#define GDM_KEY_TIMED_LOGIN_DELAY "daemon/TimedLoginDelay"
#define GDM_KEY_INITIAL_SETUP_ENABLE "daemon/InitialSetupEnable"
#define GDM_KEY_PREFERRED_DISPLAY_SERVER "daemon/PreferredDisplayServer"
#ifdef ENABLE_WAYLAND_SUPPORT
#define GDM_KEY_WAYLAND_ENABLE "daemon/WaylandEnable"
#endif
#ifdef ENABLE_X11_SUPPORT
#define GDM_KEY_XORG_ENABLE "daemon/XorgEnable"
#endif
#define GDM_KEY_REMOTE_LOGIN_ENABLE "daemon/RemoteLoginEnable"
#define GDM_KEY_DEBUG "debug/Enable"
#define GDM_KEY_DISALLOW_TCP "security/DisallowTCP"
#define GDM_KEY_ALLOW_REMOTE_AUTOLOGIN "security/AllowRemoteAutoLogin"
#define GDM_KEY_XDMCP_ENABLE "xdmcp/Enable"
#define GDM_KEY_SHOW_LOCAL_GREETER "xdmcp/ShowLocalGreeter"
#define GDM_KEY_MAX_PENDING "xdmcp/MaxPending"
#define GDM_KEY_MAX_SESSIONS "xdmcp/MaxSessions"
#define GDM_KEY_MAX_WAIT "xdmcp/MaxWait"
#define GDM_KEY_DISPLAYS_PER_HOST "xdmcp/DisplaysPerHost"
#define GDM_KEY_UDP_PORT "xdmcp/Port"
#define GDM_KEY_INDIRECT "xdmcp/HonorIndirect"
#define GDM_KEY_MAX_WAIT_INDIRECT "xdmcp/MaxWaitIndirect"
#define GDM_KEY_WILLING "xdmcp/Willing"
#define GDM_KEY_MULTICAST "chooser/Multicast"
#define GDM_KEY_MULTICAST_ADDR "chooser/MulticastAddr"
G_END_DECLS
#endif /* _GDM_SETTINGS_KEYS_H */

352
common/gdm-settings-utils.c Normal file
View file

@ -0,0 +1,352 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include "gdm-settings-utils.h"
struct _GdmSettingsEntry
{
char *key;
char *signature;
char *default_value;
char *value;
};
GdmSettingsEntry *
gdm_settings_entry_new (void)
{
GdmSettingsEntry *entry = NULL;
entry = g_new0 (GdmSettingsEntry, 1);
entry->key = NULL;
entry->signature = NULL;
entry->value = NULL;
entry->default_value = NULL;
return entry;
}
const char *
gdm_settings_entry_get_key (GdmSettingsEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return entry->key;
}
const char *
gdm_settings_entry_get_signature (GdmSettingsEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return entry->signature;
}
const char *
gdm_settings_entry_get_default_value (GdmSettingsEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return entry->default_value;
}
const char *
gdm_settings_entry_get_value (GdmSettingsEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return entry->value;
}
void
gdm_settings_entry_set_value (GdmSettingsEntry *entry,
const char *value)
{
g_return_if_fail (entry != NULL);
g_free (entry->value);
entry->value = g_strdup (value);
}
void
gdm_settings_entry_free (GdmSettingsEntry *entry)
{
g_return_if_fail (entry != NULL);
g_free (entry->key);
g_free (entry->signature);
g_free (entry->default_value);
g_free (entry->value);
g_free (entry);
}
typedef struct {
GSList *list;
GdmSettingsEntry *entry;
gboolean in_key;
gboolean in_signature;
gboolean in_default;
} ParserInfo;
static void
start_element_cb (GMarkupParseContext *ctx,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
gpointer user_data,
GError **error)
{
ParserInfo *info;
info = (ParserInfo *) user_data;
/*g_debug ("parsing start: '%s'", element_name);*/
if (strcmp (element_name, "schema") == 0) {
info->entry = gdm_settings_entry_new ();
} else if (strcmp (element_name, "key") == 0) {
info->in_key = TRUE;
} else if (strcmp (element_name, "signature") == 0) {
info->in_signature = TRUE;
} else if (strcmp (element_name, "default") == 0) {
info->in_default = TRUE;
}
}
static void
add_schema_entry (ParserInfo *info)
{
/*g_debug ("Inserting entry %s", info->entry->key);*/
info->list = g_slist_prepend (info->list, info->entry);
}
static void
end_element_cb (GMarkupParseContext *ctx,
const char *element_name,
gpointer user_data,
GError **error)
{
ParserInfo *info;
info = (ParserInfo *) user_data;
/*g_debug ("parsing end: '%s'", element_name);*/
if (strcmp (element_name, "schema") == 0) {
add_schema_entry (info);
} else if (strcmp (element_name, "key") == 0) {
info->in_key = FALSE;
} else if (strcmp (element_name, "signature") == 0) {
info->in_signature = FALSE;
} else if (strcmp (element_name, "default") == 0) {
info->in_default = FALSE;
}
}
static void
text_cb (GMarkupParseContext *ctx,
const char *text,
gsize text_len,
gpointer user_data,
GError **error)
{
ParserInfo *info;
char *t;
info = (ParserInfo *) user_data;
t = g_strndup (text, text_len);
if (info->in_key) {
info->entry->key = g_strdup (t);
} else if (info->in_signature) {
info->entry->signature = g_strdup (t);
} else if (info->in_default) {
info->entry->default_value = g_strdup (t);
}
g_free (t);
}
static void
error_cb (GMarkupParseContext *ctx,
GError *error,
gpointer user_data)
{
}
static GMarkupParser parser = {
start_element_cb,
end_element_cb,
text_cb,
NULL,
error_cb
};
gboolean
gdm_settings_parse_schemas (const char *file,
const char *root,
GSList **schemas)
{
GMarkupParseContext *ctx;
ParserInfo *info;
char *contents;
gsize len;
GError *error;
gboolean res;
g_return_val_if_fail (file != NULL, FALSE);
g_return_val_if_fail (root != NULL, FALSE);
g_return_val_if_fail (schemas != NULL, FALSE);
contents = NULL;
error = NULL;
res = g_file_get_contents (file, &contents, &len, &error);
if (! res) {
g_warning ("Unable to read schemas file: %s", error->message);
g_error_free (error);
return FALSE;
}
info = g_new0 (ParserInfo, 1);
ctx = g_markup_parse_context_new (&parser, 0, info, NULL);
g_markup_parse_context_parse (ctx, contents, len, NULL);
*schemas = info->list;
g_markup_parse_context_free (ctx);
g_free (info);
g_free (contents);
return TRUE;
}
char *
gdm_settings_parse_double_as_value (gdouble doubleval)
{
char result[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_dtostr (result, sizeof (result), doubleval);
return g_strdup (result);
}
char *
gdm_settings_parse_integer_as_value (int intval)
{
return g_strdup_printf ("%d", intval);
}
char *
gdm_settings_parse_boolean_as_value (gboolean boolval)
{
if (boolval) {
return g_strdup ("true");
} else {
return g_strdup ("false");
}
}
/* adapted from GKeyFile */
gboolean
gdm_settings_parse_value_as_boolean (const char *value,
gboolean *bool)
{
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (bool != NULL, FALSE);
if (g_ascii_strcasecmp (value, "true") == 0 || strcmp (value, "1") == 0) {
*bool = TRUE;
return TRUE;
} else if (g_ascii_strcasecmp (value, "false") == 0 || strcmp (value, "0") == 0) {
*bool = FALSE;
return TRUE;
} else {
return FALSE;
}
}
gboolean
gdm_settings_parse_value_as_integer (const char *value,
int *intval)
{
char *end_of_valid_int;
glong long_value;
gint int_value;
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (intval != NULL, FALSE);
errno = 0;
long_value = strtol (value, &end_of_valid_int, 10);
if (*value == '\0' || *end_of_valid_int != '\0') {
return FALSE;
}
int_value = long_value;
if (int_value != long_value || errno == ERANGE) {
return FALSE;
}
*intval = int_value;
return TRUE;
}
gboolean
gdm_settings_parse_value_as_double (const char *value,
gdouble *doubleval)
{
char *end_of_valid_d;
gdouble double_value = 0;
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (doubleval != NULL, FALSE);
double_value = g_ascii_strtod (value, &end_of_valid_d);
if (*end_of_valid_d != '\0' || end_of_valid_d == value) {
return FALSE;
}
*doubleval = double_value;
return TRUE;
}

View file

@ -0,0 +1,60 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SETTINGS_UTILS_H
#define __GDM_SETTINGS_UTILS_H
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _GdmSettingsEntry GdmSettingsEntry;
GdmSettingsEntry * gdm_settings_entry_new (void);
void gdm_settings_entry_free (GdmSettingsEntry *entry);
const char * gdm_settings_entry_get_key (GdmSettingsEntry *entry);
const char * gdm_settings_entry_get_signature (GdmSettingsEntry *entry);
const char * gdm_settings_entry_get_default_value (GdmSettingsEntry *entry);
const char * gdm_settings_entry_get_value (GdmSettingsEntry *entry);
void gdm_settings_entry_set_value (GdmSettingsEntry *entry,
const char *value);
gboolean gdm_settings_parse_schemas (const char *file,
const char *root,
GSList **list);
gboolean gdm_settings_parse_value_as_boolean (const char *value,
gboolean *bool);
gboolean gdm_settings_parse_value_as_integer (const char *value,
int *intval);
gboolean gdm_settings_parse_value_as_double (const char *value,
gdouble *doubleval);
char * gdm_settings_parse_boolean_as_value (gboolean boolval);
char * gdm_settings_parse_integer_as_value (int intval);
char * gdm_settings_parse_double_as_value (gdouble doubleval);
G_END_DECLS
#endif /* __GDM_SETTINGS_UTILS_H */

257
common/gdm-settings.c Normal file
View file

@ -0,0 +1,257 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include <gio/gio.h>
#include "gdm-settings.h"
#include "gdm-settings-desktop-backend.h"
struct _GdmSettings
{
GObject parent;
GList *backends;
};
enum {
VALUE_CHANGED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_settings_class_init (GdmSettingsClass *klass);
static void gdm_settings_init (GdmSettings *settings);
static void gdm_settings_finalize (GObject *object);
static gpointer settings_object = NULL;
G_DEFINE_TYPE (GdmSettings, gdm_settings, G_TYPE_OBJECT)
GQuark
gdm_settings_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_settings_error");
}
return ret;
}
gboolean
gdm_settings_get_value (GdmSettings *settings,
const char *key,
char **value,
GError **error)
{
GError *local_error;
gboolean res;
GList *l;
g_return_val_if_fail (GDM_IS_SETTINGS (settings), FALSE);
g_return_val_if_fail (settings->backends != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
local_error = NULL;
for (l = settings->backends; l; l = g_list_next (l)) {
GdmSettingsBackend *backend = l->data;
if (local_error) {
g_error_free (local_error);
local_error = NULL;
}
res = gdm_settings_backend_get_value (backend,
key,
value,
&local_error);
if (res)
break;
}
if (! res) {
g_propagate_error (error, local_error);
}
return res;
}
gboolean
gdm_settings_set_value (GdmSettings *settings,
const char *key,
const char *value,
GError **error)
{
GError *local_error;
gboolean res;
GList *l;
g_return_val_if_fail (GDM_IS_SETTINGS (settings), FALSE);
g_return_val_if_fail (settings->backends != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_debug ("Setting value %s", key);
local_error = NULL;
for (l = settings->backends; l; l = g_list_next (l)) {
GdmSettingsBackend *backend = l->data;
if (local_error) {
g_error_free (local_error);
local_error = NULL;
}
res = gdm_settings_backend_set_value (backend,
key,
value,
&local_error);
if (res)
break;
}
if (! res) {
g_propagate_error (error, local_error);
}
return res;
}
static void
gdm_settings_class_init (GdmSettingsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdm_settings_finalize;
signals [VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE,
3,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING);
}
static void
backend_value_changed (GdmSettingsBackend *backend,
const char *key,
const char *old_value,
const char *new_value,
GdmSettings *settings)
{
g_debug ("Emitting value-changed %s %s %s", key, old_value, new_value);
/* proxy it to internal listeners */
g_signal_emit (settings, signals [VALUE_CHANGED], 0, key, old_value, new_value);
}
void
gdm_settings_reload (GdmSettings *settings)
{
GList *l;
GdmSettingsBackend *backend;
g_return_if_fail (GDM_IS_SETTINGS (settings));
g_list_foreach (settings->backends, (GFunc) g_object_unref, NULL);
g_list_free (settings->backends);
settings->backends = NULL;
backend = gdm_settings_desktop_backend_new (GDM_CUSTOM_CONF);
if (backend)
settings->backends = g_list_prepend (NULL, backend);
backend = gdm_settings_desktop_backend_new (GDM_RUNTIME_CONF);
if (backend)
settings->backends = g_list_prepend (settings->backends, backend);
for (l = settings->backends; l; l = g_list_next (l)) {
backend = l->data;
g_signal_connect (backend,
"value-changed",
G_CALLBACK (backend_value_changed),
settings);
}
}
static void
gdm_settings_init (GdmSettings *settings)
{
gdm_settings_reload (settings);
}
static void
gdm_settings_finalize (GObject *object)
{
GdmSettings *settings;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_SETTINGS (object));
settings = GDM_SETTINGS (object);
g_return_if_fail (settings != NULL);
g_list_foreach (settings->backends, (GFunc) g_object_unref, NULL);
g_list_free (settings->backends);
settings->backends = NULL;
settings_object = NULL;
G_OBJECT_CLASS (gdm_settings_parent_class)->finalize (object);
}
GdmSettings *
gdm_settings_new (void)
{
if (settings_object != NULL) {
g_object_ref (settings_object);
} else {
settings_object = g_object_new (GDM_TYPE_SETTINGS, NULL);
}
return GDM_SETTINGS (settings_object);
}

58
common/gdm-settings.h Normal file
View file

@ -0,0 +1,58 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SETTINGS_H
#define __GDM_SETTINGS_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SETTINGS (gdm_settings_get_type ())
G_DECLARE_FINAL_TYPE (GdmSettings, gdm_settings, GDM, SETTINGS, GObject)
typedef enum
{
GDM_SETTINGS_ERROR_GENERAL,
GDM_SETTINGS_ERROR_KEY_NOT_FOUND
} GdmSettingsError;
#define GDM_SETTINGS_ERROR gdm_settings_error_quark ()
GQuark gdm_settings_error_quark (void);
GdmSettings * gdm_settings_new (void);
void gdm_settings_reload (GdmSettings *settings);
/* exported */
gboolean gdm_settings_get_value (GdmSettings *settings,
const char *key,
char **value,
GError **error);
gboolean gdm_settings_set_value (GdmSettings *settings,
const char *key,
const char *value,
GError **error);
G_END_DECLS
#endif /* __GDM_SETTINGS_H */

43
common/meson.build Normal file
View file

@ -0,0 +1,43 @@
libgdmcommon_src = files(
'gdm-address.c',
'gdm-common.c',
'gdm-log.c',
'gdm-profile.c',
'gdm-settings-backend.c',
'gdm-settings-desktop-backend.c',
'gdm-settings-direct.c',
'gdm-settings-utils.c',
'gdm-settings.c',
)
libgdmcommon_deps = [
logind_dep,
gobject_dep,
gio_dep,
gio_unix_dep,
]
if libselinux_dep.found()
libgdmcommon_deps += libselinux_dep
endif
libgdmcommon_lib = static_library('gdmcommon',
libgdmcommon_src,
dependencies: libgdmcommon_deps,
include_directories: config_h_dir,
)
libgdmcommon_dep = declare_dependency(
link_with: libgdmcommon_lib,
dependencies: libgdmcommon_deps,
include_directories: include_directories('.'),
)
install_data('gdb-cmd')
# test-log exectuable
test_log = executable('test-log',
'test-log.c',
dependencies: libgdmcommon_dep,
include_directories: config_h_dir,
)

60
common/test-log.c Normal file
View file

@ -0,0 +1,60 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <glib.h>
#include "gdm-common.h"
#include "gdm-log.h"
static void
test_log (void)
{
gdm_log_init ();
g_debug ("Test debug 1");
gdm_log_set_debug (TRUE);
g_debug ("Test debug 2");
g_message ("Test message");
g_warning ("Test warning");
g_critical ("Test critical");
g_error ("Test error");
}
int
main (int argc, char **argv)
{
test_log ();
return 0;
}

202
daemon/gdm-dbus-util.c Normal file
View file

@ -0,0 +1,202 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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.
*
*/
#include "config.h"
#include "gdm-dbus-util.h"
#include <string.h>
#include <glib/gstdio.h>
#include <gio/gunixsocketaddress.h>
/* a subset of org.freedesktop.DBus interface, to be used by internal servers */
static const char *dbus_introspection =
"<node name=\"/org/freedesktop/DBus\">"
" <interface name=\"org.freedesktop.DBus\">"
" <method name=\"AddMatch\">"
" <arg name=\"match_rule\" type=\"s\" direction=\"in\" />"
" </method>"
" </interface>"
"</node>";
static void
handle_bus_method (GDBusConnection *connection,
const char *sender,
const char *object_path,
const char *interface_name,
const char *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
g_dbus_method_invocation_return_value (invocation, NULL);
}
static gboolean
handle_connection (GDBusServer *server,
GDBusConnection *new_connection,
gpointer user_data)
{
g_autoptr(GDBusNodeInfo) bus_info = NULL;
GDBusInterfaceVTable bus_vtable = { handle_bus_method };
bus_info = g_dbus_node_info_new_for_xml (dbus_introspection,
NULL);
g_debug ("GdmDBusServer: new connection %p", new_connection);
g_dbus_connection_register_object (new_connection,
"/org/freedesktop/DBus",
bus_info->interfaces[0],
&bus_vtable,
NULL, NULL, NULL);
/* We're not handling the signal */
return FALSE;
}
GDBusServer *
gdm_dbus_setup_private_server (GDBusAuthObserver *observer,
GError **error)
{
g_autofree char *guid = NULL;
const char *client_address;
g_autoptr(GDBusServer) server = NULL;
/* Ensure the private bus directory exists */
if (g_mkdir_with_parents (GDM_PRIVATE_DBUS_DIR, 0711) == -1) {
g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno), g_strerror (errno));
return NULL;
}
if (g_chmod (GDM_PRIVATE_DBUS_DIR, 0711) == -1) {
g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno), g_strerror (errno));
return NULL;
}
guid = g_dbus_generate_guid ();
server = g_dbus_server_new_sync ("unix:dir=" GDM_PRIVATE_DBUS_DIR,
G_DBUS_SERVER_FLAGS_NONE,
guid,
observer,
NULL,
error);
client_address = g_dbus_server_get_client_address (server);
if (g_str_has_prefix (client_address, "unix:path=")) {
client_address += strlen("unix:path=");
g_chmod (client_address, 0666);
}
g_signal_connect (server, "new-connection",
G_CALLBACK (handle_connection),
NULL);
return g_steal_pointer (&server);
}
gboolean
gdm_dbus_get_pid_for_name (const char *system_bus_name,
pid_t *out_pid,
GError **error)
{
g_autoptr(GDBusConnection) bus = NULL;
g_autoptr(GVariant) reply = NULL;
unsigned int v;
g_return_val_if_fail (system_bus_name != NULL, FALSE);
g_return_val_if_fail (out_pid != NULL, FALSE);
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
if (bus == NULL) {
return FALSE;
}
reply = g_dbus_connection_call_sync (bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixProcessID",
g_variant_new ("(s)", system_bus_name),
G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, error);
if (reply == NULL) {
return FALSE;
}
g_variant_get (reply, "(u)", &v);
*out_pid = v;
return TRUE;
}
gboolean
gdm_dbus_get_uid_for_name (const char *system_bus_name,
uid_t *out_uid,
GError **error)
{
g_autoptr(GDBusConnection) bus = NULL;
g_autoptr(GVariant) reply = NULL;
unsigned int v;
g_return_val_if_fail (system_bus_name != NULL, FALSE);
g_return_val_if_fail (out_uid != NULL, FALSE);
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
if (bus == NULL) {
return FALSE;
}
reply = g_dbus_connection_call_sync (bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixUser",
g_variant_new ("(s)", system_bus_name),
G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, error);
if (reply == NULL) {
return FALSE;
}
g_variant_get (reply, "(u)", &v);
*out_uid = v;
return TRUE;
}
void
gdm_dbus_error_ensure (GQuark domain)
{
/* The primary purpose of this function is to make sure the error quark
* is registered internally with gdbus before any bus traffic occurs,
* so we get remote errors mapped correctly to their local counterparts.
* This error quark registration happens implicitly the first time the
* quark is used.
* Note that g_debug is never optimized away, only the output is suppressed.
*/
g_debug ("GdmDBusUtils: Registered DBus error domain '%s'",
g_quark_to_string (domain));
}

40
daemon/gdm-dbus-util.h Normal file
View file

@ -0,0 +1,40 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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.
*
*/
#ifndef __GDM_DBUS_UTIL_H
#define __GDM_DBUS_UTIL_H
#include <gio/gio.h>
#include <unistd.h>
#include <sys/types.h>
GDBusServer *gdm_dbus_setup_private_server (GDBusAuthObserver *observer,
GError **error);
gboolean gdm_dbus_get_pid_for_name (const char *system_bus_name,
pid_t *out_pid,
GError **error);
gboolean gdm_dbus_get_uid_for_name (const char *system_bus_name,
uid_t *out_uid,
GError **error);
void gdm_dbus_error_ensure (GQuark domain);
#endif

View file

@ -0,0 +1,604 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* gdm-display-access-file.c - Abstraction around xauth cookies
*
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
*
* 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, 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.
*/
#include "config.h"
#include <errno.h>
#include <limits.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#ifdef ENABLE_X11_SUPPORT
#include <X11/Xauth.h>
#endif
#include "gdm-display-access-file.h"
#include "gdm-common.h"
struct _GdmDisplayAccessFile
{
GObject parent;
char *username;
FILE *fp;
char *path;
};
#ifndef GDM_DISPLAY_ACCESS_COOKIE_SIZE
#define GDM_DISPLAY_ACCESS_COOKIE_SIZE 16
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
static void gdm_display_access_file_finalize (GObject * object);
enum
{
PROP_0 = 0,
PROP_USERNAME,
PROP_PATH
};
G_DEFINE_TYPE (GdmDisplayAccessFile, gdm_display_access_file, G_TYPE_OBJECT)
static void
gdm_display_access_file_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmDisplayAccessFile *access_file;
access_file = GDM_DISPLAY_ACCESS_FILE (object);
switch (prop_id) {
case PROP_USERNAME:
g_value_set_string (value, access_file->username);
break;
case PROP_PATH:
g_value_set_string (value, access_file->path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdm_display_access_file_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmDisplayAccessFile *access_file;
access_file = GDM_DISPLAY_ACCESS_FILE (object);
switch (prop_id) {
case PROP_USERNAME:
g_assert (access_file->username == NULL);
access_file->username = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdm_display_access_file_class_init (GdmDisplayAccessFileClass *access_file_class)
{
GObjectClass *object_class;
GParamSpec *param_spec;
object_class = G_OBJECT_CLASS (access_file_class);
object_class->finalize = gdm_display_access_file_finalize;
object_class->get_property = gdm_display_access_file_get_property;
object_class->set_property = gdm_display_access_file_set_property;
param_spec = g_param_spec_string ("username",
"Username",
"Owner of Xauthority file",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, PROP_USERNAME, param_spec);
param_spec = g_param_spec_string ("path",
"Path",
"Path to Xauthority file",
NULL,
G_PARAM_READABLE);
g_object_class_install_property (object_class, PROP_PATH, param_spec);
}
static void
gdm_display_access_file_init (GdmDisplayAccessFile *access_file)
{
}
static void
gdm_display_access_file_finalize (GObject *object)
{
GdmDisplayAccessFile *file;
GObjectClass *parent_class;
file = GDM_DISPLAY_ACCESS_FILE (object);
parent_class = G_OBJECT_CLASS (gdm_display_access_file_parent_class);
if (file->fp != NULL) {
gdm_display_access_file_close (file);
}
g_assert (file->path == NULL);
if (file->username != NULL) {
g_free (file->username);
file->username = NULL;
g_object_notify (object, "username");
}
if (parent_class->finalize != NULL) {
parent_class->finalize (object);
}
}
GQuark
gdm_display_access_file_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0) {
error_quark = g_quark_from_static_string ("gdm-display-access-file");
}
return error_quark;
}
GdmDisplayAccessFile *
gdm_display_access_file_new (const char *username)
{
GdmDisplayAccessFile *access_file;
g_return_val_if_fail (username != NULL, NULL);
access_file = g_object_new (GDM_TYPE_DISPLAY_ACCESS_FILE,
"username", username,
NULL);
return access_file;
}
static gboolean
_get_uid_and_gid_for_user (const char *username,
uid_t *uid,
gid_t *gid)
{
struct passwd *passwd_entry;
g_assert (username != NULL);
g_assert (uid != NULL);
g_assert (gid != NULL);
errno = 0;
gdm_get_pwent_for_name (username, &passwd_entry);
if (passwd_entry == NULL) {
return FALSE;
}
*uid = passwd_entry->pw_uid;
*gid = passwd_entry->pw_gid;
return TRUE;
}
static void
clean_up_stale_auth_subdirs (void)
{
g_autoptr(GDir) dir = NULL;
const char *filename;
dir = g_dir_open (GDM_XAUTH_DIR, 0, NULL);
if (dir == NULL) {
return;
}
while ((filename = g_dir_read_name (dir)) != NULL) {
g_autofree char *path = NULL;
path = g_build_filename (GDM_XAUTH_DIR, filename, NULL);
/* Will only succeed if the directory is empty
*/
g_rmdir (path);
}
}
static FILE *
_create_xauth_file_for_user (const char *username,
char **filename,
GError **error)
{
g_autofree char *template = NULL;
g_autofree char *auth_filename = NULL;
const char *dir_name;
int fd;
FILE *fp;
uid_t uid;
gid_t gid;
g_assert (filename != NULL);
*filename = NULL;
/* Create directory if not exist, then set permission 0711 and ownership root:gdm */
if (g_file_test (GDM_XAUTH_DIR, G_FILE_TEST_IS_DIR) == FALSE) {
g_remove (GDM_XAUTH_DIR);
if (g_mkdir (GDM_XAUTH_DIR, 0711) != 0) {
g_set_error_literal (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
g_strerror (errno));
return NULL;
}
g_chmod (GDM_XAUTH_DIR, 0711);
if (!_get_uid_and_gid_for_user (GDM_USERNAME, &uid, &gid)) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_USER_INFO,
_("Could not find user “%s” on system"),
GDM_USERNAME);
return NULL;
}
if (chown (GDM_XAUTH_DIR, 0, gid) != 0) {
g_warning ("Unable to change owner of '%s'",
GDM_XAUTH_DIR);
}
} else {
/* if it does exist make sure it has correct mode 0711 */
g_chmod (GDM_XAUTH_DIR, 0711);
/* and clean up any stale auth subdirs */
clean_up_stale_auth_subdirs ();
}
if (!_get_uid_and_gid_for_user (username, &uid, &gid)) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_USER_INFO,
_("Could not find user “%s” on system"),
username);
return NULL;
}
template = g_strdup_printf (GDM_XAUTH_DIR
"/auth-for-%s-XXXXXX",
username);
g_debug ("GdmDisplayAccessFile: creating xauth directory %s", template);
/* Initially create with mode 01700 then later chmod after we create database */
errno = 0;
dir_name = g_mkdtemp (template);
if (dir_name == NULL) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
"Unable to create temp dir from tempalte '%s': %s",
template,
g_strerror (errno));
return NULL;
}
g_debug ("GdmDisplayAccessFile: chowning %s to %u:%u",
dir_name, (guint)uid, (guint)gid);
errno = 0;
if (chown (dir_name, uid, gid) < 0) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
"Unable to change permission of '%s': %s",
dir_name,
g_strerror (errno));
return NULL;
}
auth_filename = g_build_filename (dir_name, "database", NULL);
g_debug ("GdmDisplayAccessFile: creating %s", auth_filename);
/* mode 00600 */
errno = 0;
fd = g_open (auth_filename,
O_RDWR | O_CREAT | O_EXCL | O_BINARY,
S_IRUSR | S_IWUSR);
if (fd < 0) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
"Unable to open '%s': %s",
auth_filename,
g_strerror (errno));
return NULL;
}
g_debug ("GdmDisplayAccessFile: chowning %s to %u:%u", auth_filename, (guint)uid, (guint)gid);
errno = 0;
if (fchown (fd, uid, gid) < 0) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
"Unable to change owner for '%s': %s",
auth_filename,
g_strerror (errno));
close (fd);
return NULL;
}
/* now open up permissions on per-session directory */
g_debug ("GdmDisplayAccessFile: chmoding %s to 0711", dir_name);
g_chmod (dir_name, 0711);
errno = 0;
fp = fdopen (fd, "w");
if (fp == NULL) {
g_set_error_literal (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
g_strerror (errno));
close (fd);
return NULL;
}
*filename = g_steal_pointer (&auth_filename);
/* don't close fd on purpose */
return fp;
}
gboolean
gdm_display_access_file_open (GdmDisplayAccessFile *file,
GError **error)
{
g_autoptr(GError) create_error = NULL;
g_return_val_if_fail (GDM_IS_DISPLAY_ACCESS_FILE (file), FALSE);
g_return_val_if_fail (file->fp == NULL, FALSE);
g_return_val_if_fail (file->path == NULL, FALSE);
file->fp = _create_xauth_file_for_user (file->username,
&file->path,
&create_error);
if (file->fp == NULL) {
g_propagate_error (error, g_steal_pointer (&create_error));
return FALSE;
}
return TRUE;
}
#ifdef ENABLE_X11_SUPPORT
static void
_get_auth_info_for_display (GdmDisplayAccessFile *file,
GdmDisplay *display,
unsigned short *family,
unsigned short *address_length,
char **address,
unsigned short *number_length,
char **number,
unsigned short *name_length,
char **name)
{
int display_number;
gboolean is_local;
gdm_display_is_local (display, &is_local, NULL);
if (is_local) {
/* We could just use FamilyWild here except xauth
* (and by extension su and ssh) doesn't support it yet
*
* https://bugs.freedesktop.org/show_bug.cgi?id=43425
*/
char localhost[_POSIX_HOST_NAME_MAX + 1] = "";
*family = FamilyLocal;
if (gethostname (localhost, _POSIX_HOST_NAME_MAX) == 0) {
*address = g_strdup (localhost);
} else {
*address = g_strdup ("localhost");
}
} else {
*family = FamilyWild;
gdm_display_get_remote_hostname (display, address, NULL);
}
*address_length = strlen (*address);
gdm_display_get_x11_display_number (display, &display_number, NULL);
*number = g_strdup_printf ("%d", display_number);
*number_length = strlen (*number);
*name = g_strdup ("MIT-MAGIC-COOKIE-1");
*name_length = strlen (*name);
}
#endif
gboolean
gdm_display_access_file_add_display (GdmDisplayAccessFile *file,
GdmDisplay *display,
char **cookie,
gsize *cookie_size,
GError **error)
{
g_autoptr(GError) add_error = NULL;
gboolean display_added;
g_return_val_if_fail (GDM_IS_DISPLAY_ACCESS_FILE (file), FALSE);
g_return_val_if_fail (file->path != NULL, FALSE);
g_return_val_if_fail (display != NULL, FALSE);
g_return_val_if_fail (cookie != NULL, FALSE);
*cookie = gdm_generate_random_bytes (GDM_DISPLAY_ACCESS_COOKIE_SIZE,
&add_error);
if (*cookie == NULL) {
g_propagate_error (error, g_steal_pointer (&add_error));
return FALSE;
}
*cookie_size = GDM_DISPLAY_ACCESS_COOKIE_SIZE;
display_added = gdm_display_access_file_add_display_with_cookie (file, display,
*cookie,
*cookie_size,
&add_error);
if (!display_added) {
g_free (*cookie);
*cookie = NULL;
g_propagate_error (error, g_steal_pointer (&add_error));
return FALSE;
}
return TRUE;
}
gboolean
gdm_display_access_file_add_display_with_cookie (GdmDisplayAccessFile *file,
GdmDisplay *display,
const char *cookie,
gsize cookie_size,
GError **error)
{
#ifdef ENABLE_X11_SUPPORT
Xauth auth_entry;
gboolean display_added;
g_return_val_if_fail (GDM_IS_DISPLAY_ACCESS_FILE (file), FALSE);
g_return_val_if_fail (file->path != NULL, FALSE);
g_return_val_if_fail (display != NULL, FALSE);
g_return_val_if_fail (cookie != NULL, FALSE);
_get_auth_info_for_display (file, display,
&auth_entry.family,
&auth_entry.address_length,
&auth_entry.address,
&auth_entry.number_length,
&auth_entry.number,
&auth_entry.name_length,
&auth_entry.name);
auth_entry.data = (char *) cookie;
auth_entry.data_length = cookie_size;
/* FIXME: We should lock the file in case the X server is
* trying to use it, too.
*/
if (!XauWriteAuth (file->fp, &auth_entry)
|| fflush (file->fp) == EOF) {
g_set_error_literal (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
g_strerror (errno));
display_added = FALSE;
} else {
display_added = TRUE;
}
/* If we wrote a FamilyLocal entry, we still want a FamilyWild
* entry, because it's more resiliant against hostname changes
*
*/
if (auth_entry.family == FamilyLocal) {
auth_entry.family = FamilyWild;
if (XauWriteAuth (file->fp, &auth_entry)
&& fflush (file->fp) != EOF) {
display_added = TRUE;
}
}
g_free (auth_entry.address);
g_free (auth_entry.number);
g_free (auth_entry.name);
return display_added;
#else
return FALSE;
#endif
}
void
gdm_display_access_file_close (GdmDisplayAccessFile *file)
{
g_autofree char *auth_dir = NULL;
g_return_if_fail (GDM_IS_DISPLAY_ACCESS_FILE (file));
g_return_if_fail (file->fp != NULL);
g_return_if_fail (file->path != NULL);
errno = 0;
if (g_unlink (file->path) != 0) {
g_warning ("GdmDisplayAccessFile: Unable to remove X11 authority database '%s': %s",
file->path,
g_strerror (errno));
}
/* still try to remove dir even if file remove failed,
may have already been removed by someone else */
/* we own the parent directory too */
auth_dir = g_path_get_dirname (file->path);
if (auth_dir != NULL) {
errno = 0;
if (g_rmdir (auth_dir) != 0) {
g_warning ("GdmDisplayAccessFile: Unable to remove X11 authority directory '%s': %s",
auth_dir,
g_strerror (errno));
}
}
g_free (file->path);
file->path = NULL;
g_object_notify (G_OBJECT (file), "path");
fclose (file->fp);
file->fp = NULL;
}
char *
gdm_display_access_file_get_path (GdmDisplayAccessFile *file)
{
g_return_val_if_fail (GDM_IS_DISPLAY_ACCESS_FILE (file), NULL);
return g_strdup (file->path);
}

View file

@ -0,0 +1,67 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* gdm-display-access-file.h - Abstraction around xauth cookies
*
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
*
* Written by Ray Strode <rstrode@redhat.com>
*
* 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, 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.
*/
#ifndef __GDM_DISPLAY_ACCESS_FILE_H__
#define __GDM_DISPLAY_ACCESS_FILE_H__
#include <glib.h>
#include <glib-object.h>
#include "gdm-display.h"
G_BEGIN_DECLS
#define GDM_TYPE_DISPLAY_ACCESS_FILE (gdm_display_access_file_get_type ())
G_DECLARE_FINAL_TYPE (GdmDisplayAccessFile, gdm_display_access_file, GDM, DISPLAY_ACCESS_FILE, GObject)
#define GDM_DISPLAY_ACCESS_FILE_ERROR (gdm_display_access_file_error_quark ())
typedef enum _GdmDisplayAccessFileError GdmDisplayAccessFileError;
enum _GdmDisplayAccessFileError
{
GDM_DISPLAY_ACCESS_FILE_ERROR_GENERAL = 0,
GDM_DISPLAY_ACCESS_FILE_ERROR_FINDING_AUTH_ENTRY
};
GQuark gdm_display_access_file_error_quark (void);
GdmDisplayAccessFile *gdm_display_access_file_new (const char *username);
gboolean gdm_display_access_file_open (GdmDisplayAccessFile *file,
GError **error);
gboolean gdm_display_access_file_add_display (GdmDisplayAccessFile *file,
GdmDisplay *display,
char **cookie,
gsize *cookie_size,
GError **error);
gboolean gdm_display_access_file_add_display_with_cookie (GdmDisplayAccessFile *file,
GdmDisplay *display,
const char *cookie,
gsize cookie_size,
GError **error);
void gdm_display_access_file_close (GdmDisplayAccessFile *file);
char *gdm_display_access_file_get_path (GdmDisplayAccessFile *file);
G_END_DECLS
#endif /* __GDM_DISPLAY_ACCESS_FILE_H__ */

View file

@ -0,0 +1,241 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-display-factory.h"
#include "gdm-display-store.h"
typedef struct _GdmDisplayFactoryPrivate
{
GdmDisplayStore *display_store;
guint purge_displays_id;
} GdmDisplayFactoryPrivate;
enum {
PROP_0,
PROP_DISPLAY_STORE,
};
static void gdm_display_factory_class_init (GdmDisplayFactoryClass *klass);
static void gdm_display_factory_init (GdmDisplayFactory *factory);
static void gdm_display_factory_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdmDisplayFactory, gdm_display_factory, G_TYPE_OBJECT)
GQuark
gdm_display_factory_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_display_factory_error");
}
return ret;
}
static gboolean
purge_display (char *id,
GdmDisplay *display,
gpointer user_data)
{
int status;
status = gdm_display_get_status (display);
switch (status) {
case GDM_DISPLAY_FINISHED:
case GDM_DISPLAY_FAILED:
return TRUE;
default:
return FALSE;
}
}
static gboolean
purge_displays (GdmDisplayFactory *factory)
{
GdmDisplayFactoryPrivate *priv;
priv = gdm_display_factory_get_instance_private (factory);
priv->purge_displays_id = 0;
gdm_display_store_foreach_remove (priv->display_store,
(GdmDisplayStoreFunc)purge_display,
NULL);
return G_SOURCE_REMOVE;
}
void
gdm_display_factory_queue_purge_displays (GdmDisplayFactory *factory)
{
GdmDisplayFactoryPrivate *priv;
g_return_if_fail (GDM_IS_DISPLAY_FACTORY (factory));
priv = gdm_display_factory_get_instance_private (factory);
if (priv->purge_displays_id == 0) {
priv->purge_displays_id = g_idle_add ((GSourceFunc) purge_displays, factory);
}
}
GdmDisplayStore *
gdm_display_factory_get_display_store (GdmDisplayFactory *factory)
{
GdmDisplayFactoryPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), NULL);
priv = gdm_display_factory_get_instance_private (factory);
return priv->display_store;
}
gboolean
gdm_display_factory_start (GdmDisplayFactory *factory)
{
gboolean ret;
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
g_object_ref (factory);
ret = GDM_DISPLAY_FACTORY_GET_CLASS (factory)->start (factory);
g_object_unref (factory);
return ret;
}
gboolean
gdm_display_factory_stop (GdmDisplayFactory *factory)
{
gboolean ret;
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
g_object_ref (factory);
ret = GDM_DISPLAY_FACTORY_GET_CLASS (factory)->stop (factory);
g_object_unref (factory);
return ret;
}
static void
gdm_display_factory_set_display_store (GdmDisplayFactory *factory,
GdmDisplayStore *display_store)
{
GdmDisplayFactoryPrivate *priv;
priv = gdm_display_factory_get_instance_private (factory);
g_clear_object (&priv->display_store);
if (display_store != NULL) {
priv->display_store = g_object_ref (display_store);
}
}
static void
gdm_display_factory_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmDisplayFactory *self;
self = GDM_DISPLAY_FACTORY (object);
switch (prop_id) {
case PROP_DISPLAY_STORE:
gdm_display_factory_set_display_store (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_display_factory_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmDisplayFactory *self;
GdmDisplayFactoryPrivate *priv;
self = GDM_DISPLAY_FACTORY (object);
priv = gdm_display_factory_get_instance_private (self);
switch (prop_id) {
case PROP_DISPLAY_STORE:
g_value_set_object (value, priv->display_store);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_display_factory_class_init (GdmDisplayFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_display_factory_get_property;
object_class->set_property = gdm_display_factory_set_property;
object_class->finalize = gdm_display_factory_finalize;
g_object_class_install_property (object_class,
PROP_DISPLAY_STORE,
g_param_spec_object ("display-store",
"display store",
"display store",
GDM_TYPE_DISPLAY_STORE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
gdm_display_factory_init (GdmDisplayFactory *factory)
{
}
static void
gdm_display_factory_finalize (GObject *object)
{
GdmDisplayFactory *factory;
GdmDisplayFactoryPrivate *priv;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_DISPLAY_FACTORY (object));
factory = GDM_DISPLAY_FACTORY (object);
priv = gdm_display_factory_get_instance_private (factory);
g_return_if_fail (priv != NULL);
g_clear_handle_id (&priv->purge_displays_id, g_source_remove);
G_OBJECT_CLASS (gdm_display_factory_parent_class)->finalize (object);
}

View file

@ -0,0 +1,59 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_DISPLAY_FACTORY_H
#define __GDM_DISPLAY_FACTORY_H
#include <glib-object.h>
#include "gdm-display-store.h"
G_BEGIN_DECLS
#define GDM_TYPE_DISPLAY_FACTORY (gdm_display_factory_get_type ())
G_DECLARE_DERIVABLE_TYPE (GdmDisplayFactory, gdm_display_factory, GDM, DISPLAY_FACTORY, GObject)
struct _GdmDisplayFactoryClass
{
GObjectClass parent_class;
gboolean (*start) (GdmDisplayFactory *factory);
gboolean (*stop) (GdmDisplayFactory *factory);
};
typedef enum
{
GDM_DISPLAY_FACTORY_ERROR_GENERAL
} GdmDisplayFactoryError;
#define GDM_DISPLAY_FACTORY_ERROR gdm_display_factory_error_quark ()
GQuark gdm_display_factory_error_quark (void);
GType gdm_display_factory_get_type (void);
gboolean gdm_display_factory_start (GdmDisplayFactory *manager);
gboolean gdm_display_factory_stop (GdmDisplayFactory *manager);
GdmDisplayStore * gdm_display_factory_get_display_store (GdmDisplayFactory *manager);
void gdm_display_factory_queue_purge_displays (GdmDisplayFactory *manager);
G_END_DECLS
#endif /* __GDM_DISPLAY_FACTORY_H */

327
daemon/gdm-display-store.c Normal file
View file

@ -0,0 +1,327 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-display-store.h"
#include "gdm-display.h"
struct _GdmDisplayStore
{
GObject parent;
GHashTable *displays;
};
typedef struct
{
GdmDisplayStore *store;
GdmDisplay *display;
} StoredDisplay;
enum {
DISPLAY_ADDED,
DISPLAY_REMOVED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_display_store_class_init (GdmDisplayStoreClass *klass);
static void gdm_display_store_init (GdmDisplayStore *display_store);
static void gdm_display_store_finalize (GObject *object);
G_DEFINE_TYPE (GdmDisplayStore, gdm_display_store, G_TYPE_OBJECT)
static StoredDisplay *
stored_display_new (GdmDisplayStore *store,
GdmDisplay *display)
{
StoredDisplay *stored_display;
stored_display = g_slice_new (StoredDisplay);
stored_display->store = store;
stored_display->display = g_object_ref (display);
return stored_display;
}
static void
stored_display_free (StoredDisplay *stored_display)
{
g_signal_emit (G_OBJECT (stored_display->store),
signals[DISPLAY_REMOVED],
0,
stored_display->display);
g_debug ("GdmDisplayStore: Unreffing display: %p",
stored_display->display);
g_object_unref (stored_display->display);
g_slice_free (StoredDisplay, stored_display);
}
GQuark
gdm_display_store_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_display_store_error");
}
return ret;
}
void
gdm_display_store_clear (GdmDisplayStore *store)
{
g_return_if_fail (GDM_IS_DISPLAY_STORE (store));
g_debug ("GdmDisplayStore: Clearing display store");
g_hash_table_remove_all (store->displays);
}
static gboolean
remove_display (char *id,
GdmDisplay *display,
GdmDisplay *display_to_remove)
{
if (display == display_to_remove) {
return TRUE;
}
return FALSE;
}
gboolean
gdm_display_store_remove (GdmDisplayStore *store,
GdmDisplay *display)
{
g_return_val_if_fail (GDM_IS_DISPLAY_STORE (store), FALSE);
g_return_val_if_fail (display != NULL, FALSE);
gdm_display_store_foreach_remove (store,
(GdmDisplayStoreFunc)remove_display,
display);
return FALSE;
}
typedef struct
{
GdmDisplayStoreFunc predicate;
gpointer user_data;
} FindClosure;
static gboolean
find_func (const char *id,
StoredDisplay *stored_display,
FindClosure *closure)
{
return closure->predicate (id,
stored_display->display,
closure->user_data);
}
static void
foreach_func (const char *id,
StoredDisplay *stored_display,
FindClosure *closure)
{
(void) closure->predicate (id,
stored_display->display,
closure->user_data);
}
void
gdm_display_store_foreach (GdmDisplayStore *store,
GdmDisplayStoreFunc func,
gpointer user_data)
{
FindClosure closure;
g_return_if_fail (GDM_IS_DISPLAY_STORE (store));
g_return_if_fail (func != NULL);
closure.predicate = func;
closure.user_data = user_data;
g_hash_table_foreach (store->displays,
(GHFunc) foreach_func,
&closure);
}
GdmDisplay *
gdm_display_store_lookup (GdmDisplayStore *store,
const char *id)
{
StoredDisplay *stored_display;
g_return_val_if_fail (GDM_IS_DISPLAY_STORE (store), NULL);
g_return_val_if_fail (id != NULL, NULL);
stored_display = g_hash_table_lookup (store->displays,
id);
if (stored_display == NULL) {
return NULL;
}
return stored_display->display;
}
GdmDisplay *
gdm_display_store_find (GdmDisplayStore *store,
GdmDisplayStoreFunc predicate,
gpointer user_data)
{
StoredDisplay *stored_display;
FindClosure closure;
g_return_val_if_fail (GDM_IS_DISPLAY_STORE (store), NULL);
g_return_val_if_fail (predicate != NULL, NULL);
closure.predicate = predicate;
closure.user_data = user_data;
stored_display = g_hash_table_find (store->displays,
(GHRFunc) find_func,
&closure);
if (stored_display == NULL) {
return NULL;
}
return stored_display->display;
}
guint
gdm_display_store_foreach_remove (GdmDisplayStore *store,
GdmDisplayStoreFunc func,
gpointer user_data)
{
FindClosure closure;
guint ret;
g_return_val_if_fail (GDM_IS_DISPLAY_STORE (store), 0);
g_return_val_if_fail (func != NULL, 0);
closure.predicate = func;
closure.user_data = user_data;
ret = g_hash_table_foreach_remove (store->displays,
(GHRFunc) find_func,
&closure);
return ret;
}
void
gdm_display_store_add (GdmDisplayStore *store,
GdmDisplay *display)
{
char *id;
StoredDisplay *stored_display;
g_return_if_fail (GDM_IS_DISPLAY_STORE (store));
g_return_if_fail (display != NULL);
gdm_display_get_id (display, &id, NULL);
g_debug ("GdmDisplayStore: Adding display %s to store", id);
stored_display = stored_display_new (store, display);
g_hash_table_insert (store->displays,
id,
stored_display);
g_signal_emit (G_OBJECT (store),
signals[DISPLAY_ADDED],
0,
id);
}
static void
gdm_display_store_class_init (GdmDisplayStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdm_display_store_finalize;
signals [DISPLAY_ADDED] =
g_signal_new ("display-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1, G_TYPE_STRING);
signals [DISPLAY_REMOVED] =
g_signal_new ("display-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1, G_TYPE_OBJECT);
}
static void
gdm_display_store_init (GdmDisplayStore *store)
{
store->displays = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify)
stored_display_free);
}
static void
gdm_display_store_finalize (GObject *object)
{
GdmDisplayStore *store;
g_return_if_fail (GDM_IS_DISPLAY_STORE (object));
store = GDM_DISPLAY_STORE (object);
g_hash_table_destroy (store->displays);
G_OBJECT_CLASS (gdm_display_store_parent_class)->finalize (object);
}
GdmDisplayStore *
gdm_display_store_new (void)
{
GObject *object;
object = g_object_new (GDM_TYPE_DISPLAY_STORE,
NULL);
return GDM_DISPLAY_STORE (object);
}

View file

@ -0,0 +1,69 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_DISPLAY_STORE_H
#define __GDM_DISPLAY_STORE_H
#include <glib-object.h>
#include "gdm-display.h"
G_BEGIN_DECLS
#define GDM_TYPE_DISPLAY_STORE (gdm_display_store_get_type ())
G_DECLARE_FINAL_TYPE (GdmDisplayStore, gdm_display_store, GDM, DISPLAY_STORE, GObject)
typedef enum
{
GDM_DISPLAY_STORE_ERROR_GENERAL
} GdmDisplayStoreError;
#define GDM_DISPLAY_STORE_ERROR gdm_display_store_error_quark ()
typedef gboolean (*GdmDisplayStoreFunc) (const char *id,
GdmDisplay *display,
gpointer user_data);
GQuark gdm_display_store_error_quark (void);
GdmDisplayStore * gdm_display_store_new (void);
void gdm_display_store_add (GdmDisplayStore *store,
GdmDisplay *display);
void gdm_display_store_clear (GdmDisplayStore *store);
gboolean gdm_display_store_remove (GdmDisplayStore *store,
GdmDisplay *display);
void gdm_display_store_foreach (GdmDisplayStore *store,
GdmDisplayStoreFunc func,
gpointer user_data);
guint gdm_display_store_foreach_remove (GdmDisplayStore *store,
GdmDisplayStoreFunc func,
gpointer user_data);
GdmDisplay * gdm_display_store_lookup (GdmDisplayStore *store,
const char *id);
GdmDisplay * gdm_display_store_find (GdmDisplayStore *store,
GdmDisplayStoreFunc predicate,
gpointer user_data);
G_END_DECLS
#endif /* __GDM_DISPLAY_STORE_H */

1942
daemon/gdm-display.c Normal file

File diff suppressed because it is too large Load diff

117
daemon/gdm-display.h Normal file
View file

@ -0,0 +1,117 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_DISPLAY_H
#define __GDM_DISPLAY_H
#include <glib-object.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#define GDM_TYPE_DISPLAY (gdm_display_get_type ())
G_DECLARE_DERIVABLE_TYPE (GdmDisplay, gdm_display, GDM, DISPLAY, GObject)
typedef enum {
GDM_DISPLAY_UNMANAGED = 0,
GDM_DISPLAY_PREPARED,
GDM_DISPLAY_MANAGED,
GDM_DISPLAY_WAITING_TO_FINISH,
GDM_DISPLAY_FINISHED,
GDM_DISPLAY_FAILED,
} GdmDisplayStatus;
struct _GdmDisplayClass
{
GObjectClass parent_class;
/* methods */
gboolean (*prepare) (GdmDisplay *display);
void (*manage) (GdmDisplay *self);
};
typedef enum
{
GDM_DISPLAY_ERROR_GENERAL,
GDM_DISPLAY_ERROR_GETTING_USER_INFO,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
} GdmDisplayError;
#define GDM_DISPLAY_ERROR gdm_display_error_quark ()
GQuark gdm_display_error_quark (void);
int gdm_display_get_status (GdmDisplay *display);
time_t gdm_display_get_creation_time (GdmDisplay *display);
const char * gdm_display_get_session_id (GdmDisplay *display);
gboolean gdm_display_create_authority (GdmDisplay *display);
gboolean gdm_display_prepare (GdmDisplay *display);
gboolean gdm_display_manage (GdmDisplay *display);
gboolean gdm_display_finish (GdmDisplay *display);
gboolean gdm_display_unmanage (GdmDisplay *display);
GDBusObjectSkeleton *gdm_display_get_object_skeleton (GdmDisplay *display);
/* exported to bus */
gboolean gdm_display_get_id (GdmDisplay *display,
char **id,
GError **error);
gboolean gdm_display_get_remote_hostname (GdmDisplay *display,
char **hostname,
GError **error);
gboolean gdm_display_get_x11_display_number (GdmDisplay *display,
int *number,
GError **error);
gboolean gdm_display_get_x11_display_name (GdmDisplay *display,
char **x11_display,
GError **error);
gboolean gdm_display_get_seat_id (GdmDisplay *display,
char **seat_id,
GError **error);
gboolean gdm_display_is_local (GdmDisplay *display,
gboolean *local,
GError **error);
gboolean gdm_display_is_initial (GdmDisplay *display,
gboolean *initial,
GError **error);
gboolean gdm_display_get_x11_cookie (GdmDisplay *display,
const char **x11_cookie,
gsize *x11_cookie_size,
GError **error);
gboolean gdm_display_get_x11_authority_file (GdmDisplay *display,
char **filename,
GError **error);
gboolean gdm_display_add_user_authorization (GdmDisplay *display,
const char *username,
char **filename,
GError **error);
gboolean gdm_display_remove_user_authorization (GdmDisplay *display,
const char *username,
GError **error);
void gdm_display_start_greeter_session (GdmDisplay *display);
void gdm_display_stop_greeter_session (GdmDisplay *display);
gboolean gdm_display_connect (GdmDisplay *self);
G_END_DECLS
#endif /* __GDM_DISPLAY_H */

23
daemon/gdm-display.xml Normal file
View file

@ -0,0 +1,23 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.gnome.DisplayManager.Display">
<method name="GetId">
<arg name="id" direction="out" type="o"/>
</method>
<method name="GetX11DisplayName">
<arg name="name" direction="out" type="s"/>
</method>
<method name="GetSeatId">
<arg name="filename" direction="out" type="s"/>
</method>
<method name="IsInitial">
<arg name="initial" direction="out" type="b"/>
</method>
<method name="GetRemoteHostname">
<arg name="hostname" direction="out" type="s"/>
</method>
<method name="IsLocal">
<arg name="local" direction="out" type="b"/>
</method>
</interface>
</node>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
*
* 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.
*
*/
#ifndef __GDM_LAUNCH_ENVIRONMENT_H
#define __GDM_LAUNCH_ENVIRONMENT_H
#include <glib-object.h>
#include "gdm-session.h"
G_BEGIN_DECLS
#define GDM_TYPE_LAUNCH_ENVIRONMENT (gdm_launch_environment_get_type ())
G_DECLARE_FINAL_TYPE (GdmLaunchEnvironment, gdm_launch_environment, GDM, LAUNCH_ENVIRONMENT, GObject)
gboolean gdm_launch_environment_start (GdmLaunchEnvironment *launch_environment);
gboolean gdm_launch_environment_stop (GdmLaunchEnvironment *launch_environment);
GdmSession * gdm_launch_environment_get_session (GdmLaunchEnvironment *launch_environment);
char * gdm_launch_environment_get_session_id (GdmLaunchEnvironment *launch_environment);
GdmLaunchEnvironment *gdm_create_greeter_launch_environment (const char *display_name,
const char *seat_id,
const char *session_type,
const char *display_hostname,
gboolean display_is_local);
GdmLaunchEnvironment *gdm_create_initial_setup_launch_environment (const char *display_name,
const char *seat_id,
const char *session_type,
const char *display_hostname,
gboolean display_is_local);
GdmLaunchEnvironment *gdm_create_chooser_launch_environment (const char *display_name,
const char *seat_id,
const char *display_hostname);
G_END_DECLS
#endif /* __GDM_LAUNCH_ENVIRONMENT_H */

292
daemon/gdm-legacy-display.c Normal file
View file

@ -0,0 +1,292 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-common.h"
#include "gdm-display.h"
#include "gdm-launch-environment.h"
#include "gdm-legacy-display.h"
#include "gdm-local-display-glue.h"
#include "gdm-server.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
struct _GdmLegacyDisplay
{
GdmDisplay parent;
GdmDBusLocalDisplay *skeleton;
GdmServer *server;
};
static void gdm_legacy_display_class_init (GdmLegacyDisplayClass *klass);
static void gdm_legacy_display_init (GdmLegacyDisplay *legacy_display);
G_DEFINE_TYPE (GdmLegacyDisplay, gdm_legacy_display, GDM_TYPE_DISPLAY)
static GObject *
gdm_legacy_display_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmLegacyDisplay *display;
display = GDM_LEGACY_DISPLAY (G_OBJECT_CLASS (gdm_legacy_display_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
display->skeleton = GDM_DBUS_LOCAL_DISPLAY (gdm_dbus_local_display_skeleton_new ());
g_dbus_object_skeleton_add_interface (gdm_display_get_object_skeleton (GDM_DISPLAY (display)),
G_DBUS_INTERFACE_SKELETON (display->skeleton));
return G_OBJECT (display);
}
static void
gdm_legacy_display_finalize (GObject *object)
{
GdmLegacyDisplay *display = GDM_LEGACY_DISPLAY (object);
g_clear_object (&display->skeleton);
g_clear_object (&display->server);
G_OBJECT_CLASS (gdm_legacy_display_parent_class)->finalize (object);
}
static gboolean
gdm_legacy_display_prepare (GdmDisplay *display)
{
GdmLegacyDisplay *self = GDM_LEGACY_DISPLAY (display);
g_autoptr(GdmLaunchEnvironment) launch_environment = NULL;
g_autofree char *display_name = NULL;
g_autofree gchar *seat_id = NULL;
gboolean doing_initial_setup = FALSE;
g_object_get (self,
"x11-display-name", &display_name,
"seat-id", &seat_id,
"doing-initial-setup", &doing_initial_setup,
NULL);
if (!doing_initial_setup) {
launch_environment = gdm_create_greeter_launch_environment (display_name,
seat_id,
NULL,
NULL,
TRUE);
} else {
launch_environment = gdm_create_initial_setup_launch_environment (display_name,
seat_id,
NULL,
NULL,
TRUE);
}
g_object_set (self, "launch-environment", launch_environment, NULL);
if (!gdm_display_create_authority (display)) {
g_warning ("Unable to set up access control for display %s",
display_name);
return FALSE;
}
return GDM_DISPLAY_CLASS (gdm_legacy_display_parent_class)->prepare (display);
}
static void
on_server_ready (GdmServer *server,
GdmLegacyDisplay *self)
{
gboolean ret;
ret = gdm_display_connect (GDM_DISPLAY (self));
if (!ret) {
g_debug ("GdmDisplay: could not connect to display");
gdm_display_unmanage (GDM_DISPLAY (self));
} else {
g_autoptr(GdmLaunchEnvironment) launch_environment = NULL;
g_autofree char *display_device = NULL;
display_device = gdm_server_get_display_device (server);
g_object_get (G_OBJECT (self),
"launch-environment", &launch_environment,
NULL);
g_object_set (G_OBJECT (launch_environment),
"x11-display-device",
display_device,
NULL);
g_debug ("GdmDisplay: connected to display");
g_object_set (G_OBJECT (self), "status", GDM_DISPLAY_MANAGED, NULL);
}
}
static void
on_server_exited (GdmServer *server,
int exit_code,
GdmDisplay *self)
{
g_debug ("GdmDisplay: server exited with code %d\n", exit_code);
gdm_display_unmanage (GDM_DISPLAY (self));
}
static void
on_server_died (GdmServer *server,
int signal_number,
GdmDisplay *self)
{
g_debug ("GdmDisplay: server died with signal %d, (%s)",
signal_number,
g_strsignal (signal_number));
gdm_display_unmanage (GDM_DISPLAY (self));
}
static void
gdm_legacy_display_manage (GdmDisplay *display)
{
GdmLegacyDisplay *self = GDM_LEGACY_DISPLAY (display);
g_autofree char *display_name = NULL;
g_autofree char *auth_file = NULL;
g_autofree char *seat_id = NULL;
gboolean is_initial;
gboolean res;
gboolean disable_tcp;
g_object_get (G_OBJECT (self),
"x11-display-name", &display_name,
"x11-authority-file", &auth_file,
"seat-id", &seat_id,
"is-initial", &is_initial,
NULL);
self->server = gdm_server_new (display_name, seat_id, auth_file, is_initial);
disable_tcp = TRUE;
if (gdm_settings_direct_get_boolean (GDM_KEY_DISALLOW_TCP, &disable_tcp)) {
g_object_set (self->server,
"disable-tcp", disable_tcp,
NULL);
}
g_signal_connect (self->server,
"exited",
G_CALLBACK (on_server_exited),
self);
g_signal_connect (self->server,
"died",
G_CALLBACK (on_server_died),
self);
g_signal_connect (self->server,
"ready",
G_CALLBACK (on_server_ready),
self);
res = gdm_server_start (self->server);
if (! res) {
g_warning (_("Could not start the X "
"server (your graphical environment) "
"due to an internal error. "
"Please contact your system administrator "
"or check your syslog to diagnose. "
"In the meantime this display will be "
"disabled. Please restart GDM when "
"the problem is corrected."));
gdm_display_unmanage (GDM_DISPLAY (self));
}
g_debug ("GdmDisplay: Started X server");
}
static void
gdm_legacy_display_class_init (GdmLegacyDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
object_class->constructor = gdm_legacy_display_constructor;
object_class->finalize = gdm_legacy_display_finalize;
display_class->prepare = gdm_legacy_display_prepare;
display_class->manage = gdm_legacy_display_manage;
}
static void
on_display_status_changed (GdmLegacyDisplay *self)
{
int status;
status = gdm_display_get_status (GDM_DISPLAY (self));
switch (status) {
case GDM_DISPLAY_UNMANAGED:
if (self->server != NULL)
gdm_server_stop (self->server);
break;
default:
break;
}
}
static void
gdm_legacy_display_init (GdmLegacyDisplay *legacy_display)
{
g_signal_connect (legacy_display, "notify::status",
G_CALLBACK (on_display_status_changed),
NULL);
}
GdmDisplay *
gdm_legacy_display_new (int display_number)
{
GObject *object;
g_autofree char *x11_display = NULL;
x11_display = g_strdup_printf (":%d", display_number);
object = g_object_new (GDM_TYPE_LEGACY_DISPLAY,
"x11-display-number", display_number,
"x11-display-name", x11_display,
NULL);
return GDM_DISPLAY (object);
}

View file

@ -0,0 +1,38 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_LEGACY_DISPLAY_H
#define __GDM_LEGACY_DISPLAY_H
#include <glib-object.h>
#include "gdm-display.h"
G_BEGIN_DECLS
#define GDM_TYPE_LEGACY_DISPLAY (gdm_legacy_display_get_type ())
G_DECLARE_FINAL_TYPE (GdmLegacyDisplay, gdm_legacy_display, GDM, LEGACY_DISPLAY, GdmDisplay)
GdmDisplay * gdm_legacy_display_new (int display_number);
G_END_DECLS
#endif /* __GDM_LEGACY_DISPLAY_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,51 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_LOCAL_DISPLAY_FACTORY_H
#define __GDM_LOCAL_DISPLAY_FACTORY_H
#include <glib-object.h>
#include "gdm-display-factory.h"
#include "gdm-display-store.h"
G_BEGIN_DECLS
#define GDM_TYPE_LOCAL_DISPLAY_FACTORY (gdm_local_display_factory_get_type ())
G_DECLARE_FINAL_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM, LOCAL_DISPLAY_FACTORY, GdmDisplayFactory)
typedef enum
{
GDM_LOCAL_DISPLAY_FACTORY_ERROR_GENERAL
} GdmLocalDisplayFactoryError;
#define GDM_LOCAL_DISPLAY_FACTORY_ERROR gdm_local_display_factory_error_quark ()
GQuark gdm_local_display_factory_error_quark (void);
GdmLocalDisplayFactory * gdm_local_display_factory_new (GdmDisplayStore *display_store);
gboolean gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
char **id,
GError **error);
G_END_DECLS
#endif /* __GDM_LOCAL_DISPLAY_FACTORY_H */

View file

@ -0,0 +1,8 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/LocalDisplayFactory">
<interface name="org.gnome.DisplayManager.LocalDisplayFactory">
<method name="CreateTransientDisplay">
<arg name="id" direction="out" type="o"/>
</method>
</interface>
</node>

162
daemon/gdm-local-display.c Normal file
View file

@ -0,0 +1,162 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-common.h"
#include "gdm-display.h"
#include "gdm-launch-environment.h"
#include "gdm-local-display.h"
#include "gdm-local-display-glue.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
struct _GdmLocalDisplay
{
GdmDisplay parent;
GdmDBusLocalDisplay *skeleton;
};
static void gdm_local_display_class_init (GdmLocalDisplayClass *klass);
static void gdm_local_display_init (GdmLocalDisplay *local_display);
G_DEFINE_TYPE (GdmLocalDisplay, gdm_local_display, GDM_TYPE_DISPLAY)
static GObject *
gdm_local_display_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmLocalDisplay *display;
display = GDM_LOCAL_DISPLAY (G_OBJECT_CLASS (gdm_local_display_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
display->skeleton = GDM_DBUS_LOCAL_DISPLAY (gdm_dbus_local_display_skeleton_new ());
g_dbus_object_skeleton_add_interface (gdm_display_get_object_skeleton (GDM_DISPLAY (display)),
G_DBUS_INTERFACE_SKELETON (display->skeleton));
return G_OBJECT (display);
}
static void
gdm_local_display_finalize (GObject *object)
{
GdmLocalDisplay *display = GDM_LOCAL_DISPLAY (object);
g_clear_object (&display->skeleton);
G_OBJECT_CLASS (gdm_local_display_parent_class)->finalize (object);
}
static gboolean
gdm_local_display_prepare (GdmDisplay *display)
{
GdmLocalDisplay *self = GDM_LOCAL_DISPLAY (display);
GdmLaunchEnvironment *launch_environment;
char *seat_id;
char *session_class;
char *session_type;
gboolean doing_initial_setup = FALSE;
seat_id = NULL;
g_object_get (self,
"seat-id", &seat_id,
"doing-initial-setup", &doing_initial_setup,
"session-class", &session_class,
"session-type", &session_type,
NULL);
if (g_strcmp0 (session_class, "greeter") != 0) {
goto out;
}
g_debug ("doing initial setup? %s", doing_initial_setup? "yes" : "no");
if (!doing_initial_setup) {
launch_environment = gdm_create_greeter_launch_environment (NULL,
seat_id,
session_type,
NULL,
TRUE);
} else {
launch_environment = gdm_create_initial_setup_launch_environment (NULL,
seat_id,
session_type,
NULL,
TRUE);
}
g_object_set (self, "launch-environment", launch_environment, NULL);
g_object_unref (launch_environment);
out:
g_free (seat_id);
g_free (session_class);
g_free (session_type);
return GDM_DISPLAY_CLASS (gdm_local_display_parent_class)->prepare (display);
}
static void
gdm_local_display_class_init (GdmLocalDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
object_class->constructor = gdm_local_display_constructor;
object_class->finalize = gdm_local_display_finalize;
display_class->prepare = gdm_local_display_prepare;
}
static void
gdm_local_display_init (GdmLocalDisplay *local_display)
{
}
GdmDisplay *
gdm_local_display_new (void)
{
GObject *object;
object = g_object_new (GDM_TYPE_LOCAL_DISPLAY, NULL);
return GDM_DISPLAY (object);
}

View file

@ -0,0 +1,38 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_LOCAL_DISPLAY_H
#define __GDM_LOCAL_DISPLAY_H
#include <glib-object.h>
#include "gdm-display.h"
G_BEGIN_DECLS
#define GDM_TYPE_LOCAL_DISPLAY (gdm_local_display_get_type ())
G_DECLARE_FINAL_TYPE (GdmLocalDisplay, gdm_local_display, GDM, LOCAL_DISPLAY, GdmDisplay)
GdmDisplay * gdm_local_display_new (void);
G_END_DECLS
#endif /* __GDM_LOCAL_DISPLAY_H */

View file

@ -0,0 +1,5 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.gnome.DisplayManager.LocalDisplay">
</interface>
</node>

3051
daemon/gdm-manager.c Normal file

File diff suppressed because it is too large Load diff

61
daemon/gdm-manager.h Normal file
View file

@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_MANAGER_H
#define __GDM_MANAGER_H
#include <glib-object.h>
#include "gdm-display.h"
#include "gdm-manager-glue.h"
G_BEGIN_DECLS
#define GDM_TYPE_MANAGER (gdm_manager_get_type ())
G_DECLARE_FINAL_TYPE (GdmManager, gdm_manager, GDM, MANAGER, GdmDBusManagerSkeleton)
typedef enum
{
GDM_MANAGER_ERROR_GENERAL
} GdmManagerError;
#define GDM_MANAGER_ERROR gdm_manager_error_quark ()
GQuark gdm_manager_error_quark (void);
GdmManager * gdm_manager_new (void);
void gdm_manager_start (GdmManager *manager);
void gdm_manager_stop (GdmManager *manager);
void gdm_manager_set_xdmcp_enabled (GdmManager *manager,
gboolean enabled);
void gdm_manager_set_show_local_greeter (GdmManager *manager,
gboolean show_local_greeter);
void gdm_manager_set_remote_login_enabled (GdmManager *manager,
gboolean enabled);
gboolean gdm_manager_get_displays (GdmManager *manager,
GPtrArray **displays,
GError **error);
G_END_DECLS
#endif /* __GDM_MANAGER_H */

19
daemon/gdm-manager.xml Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/Manager">
<interface name="org.gnome.DisplayManager.Manager">
<method name="RegisterDisplay">
<arg name="details" direction="in" type="a{ss}"/>
</method>
<method name="RegisterSession">
<arg name="details" direction="in" type="a{sv}"/>
</method>
<method name="OpenSession">
<arg name="address" direction="out" type="s"/>
</method>
<method name="OpenReauthenticationChannel">
<arg name="username" direction="in" type="s"/>
<arg name="address" direction="out" type="s"/>
</method>
<property name="Version" type="s" access="read"/>
</interface>
</node>

View file

@ -0,0 +1,357 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
*
* 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.
*
*/
#include "config.h"
#include "gdm-remote-display.h"
#include "gdm-remote-display-factory.h"
#include "gdm-remote-display-factory-glue.h"
#define GDM_REMOTE_DISPLAY_FACTORY_DBUS_PATH "/org/gnome/DisplayManager/RemoteDisplayFactory"
struct _GdmRemoteDisplayFactory
{
GdmDisplayFactory parent;
GdmDBusRemoteDisplayFactory *skeleton;
GDBusConnection *connection;
int remote_displays_count;
gboolean suspend_inhibited;
int inhibit_suspend_fd;
};
static void gdm_remote_display_factory_class_init (GdmRemoteDisplayFactoryClass *klass);
static void gdm_remote_display_factory_init (GdmRemoteDisplayFactory *factory);
static void gdm_remote_display_factory_finalize (GObject *object);
static gpointer remote_display_factory_object = NULL;
G_DEFINE_TYPE (GdmRemoteDisplayFactory, gdm_remote_display_factory, GDM_TYPE_DISPLAY_FACTORY)
static void
on_display_status_changed (GdmDisplay *display,
GParamSpec *arg1,
GdmRemoteDisplayFactory *factory)
{
g_debug ("GdmRemoteDisplayFactory: remote display status changed: %d",
gdm_display_get_status (display));
}
static gboolean
gdm_remote_display_factory_create_remote_display (GdmRemoteDisplayFactory *factory,
const char *remote_id)
{
GdmDisplay *display = NULL;
GdmDisplayStore *store;
g_debug ("GdmRemoteDisplayFactory: Creating remote display");
display = gdm_remote_display_new (remote_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_add (store, display);
if (!gdm_display_prepare (display)) {
gdm_display_unmanage (display);
g_object_unref (display);
return FALSE;
}
g_signal_connect_after (display,
"notify::status",
G_CALLBACK (on_display_status_changed),
factory);
g_object_unref (display);
return TRUE;
}
static gboolean
handle_create_remote_display (GdmDBusRemoteDisplayFactory *skeleton,
GDBusMethodInvocation *invocation,
const char *remote_id,
GdmRemoteDisplayFactory *factory)
{
if (!gdm_remote_display_factory_create_remote_display (factory, remote_id))
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Error creating remote display");
else
gdm_dbus_remote_display_factory_complete_create_remote_display (factory->skeleton,
invocation);
return TRUE;
}
static gboolean
register_factory (GdmRemoteDisplayFactory *factory)
{
GError *error = NULL;
factory->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (factory->connection == NULL) {
g_critical ("Error getting system bus: %s", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
factory->skeleton = GDM_DBUS_REMOTE_DISPLAY_FACTORY (gdm_dbus_remote_display_factory_skeleton_new ());
g_signal_connect (factory->skeleton,
"handle-create-remote-display",
G_CALLBACK (handle_create_remote_display),
factory);
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (factory->skeleton),
factory->connection,
GDM_REMOTE_DISPLAY_FACTORY_DBUS_PATH,
&error)) {
g_critical ("Error exporting RemoteDisplayFactory object: %s", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
return TRUE;
}
static void
gdm_remote_display_factory_finalize (GObject *object)
{
GdmRemoteDisplayFactory *factory;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (object));
factory = GDM_REMOTE_DISPLAY_FACTORY (object);
g_return_if_fail (factory != NULL);
g_clear_object (&factory->connection);
g_clear_object (&factory->skeleton);
if (factory->inhibit_suspend_fd != -1)
close (factory->inhibit_suspend_fd);
G_OBJECT_CLASS (gdm_remote_display_factory_parent_class)->finalize (object);
}
static GObject *
gdm_remote_display_factory_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmRemoteDisplayFactory *factory;
gboolean res;
factory = GDM_REMOTE_DISPLAY_FACTORY (G_OBJECT_CLASS (gdm_remote_display_factory_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
res = register_factory (factory);
if (!res) {
g_warning ("Unable to register remote display factory with system bus");
}
return G_OBJECT (factory);
}
static void
on_inhibit_suspend_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GDBusProxy *proxy = G_DBUS_PROXY (source);
GdmRemoteDisplayFactory *factory = user_data;
g_autoptr (GUnixFDList) fd_list = NULL;
g_autoptr (GVariant) res = NULL;
g_autoptr (GError) error = NULL;
int idx;
res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy,
&fd_list,
result,
&error);
if (!res) {
g_warning ("Unable to inhibit suspend: %s", error->message);
factory->suspend_inhibited = FALSE;
return;
}
g_variant_get (res, "(h)", &idx);
factory->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &error);
if (factory->inhibit_suspend_fd == -1) {
g_warning ("Failed to receive system inhibitor fd: %s", error->message);
factory->suspend_inhibited = FALSE;
}
}
static void
inhibit_suspend (GdmRemoteDisplayFactory *factory)
{
g_autoptr (GDBusProxy) proxy = NULL;
g_autoptr (GError) error = NULL;
if (factory->suspend_inhibited)
return;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
NULL,
&error);
if (!proxy) {
g_warning ("Failed to acquire login1 manager proxy: %s", error->message);
return;
}
factory->suspend_inhibited = TRUE;
g_dbus_proxy_call_with_unix_fd_list (proxy,
"Inhibit",
g_variant_new ("(ssss)",
"sleep",
g_get_user_name (),
"Remote sessions would die on suspend",
"block"),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT,
NULL,
NULL,
on_inhibit_suspend_done,
factory);
}
static void
on_display_added (GdmDisplayStore *store,
const char *id,
GdmRemoteDisplayFactory *factory)
{
GdmDisplay *display = gdm_display_store_lookup (store, id);
if (!GDM_IS_REMOTE_DISPLAY (display))
return;
factory->remote_displays_count++;
if (factory->remote_displays_count > 0)
inhibit_suspend (factory);
}
static void
uninhibit_suspend (GdmRemoteDisplayFactory *factory)
{
if (factory->inhibit_suspend_fd == -1)
return;
close (factory->inhibit_suspend_fd);
factory->inhibit_suspend_fd = -1;
factory->suspend_inhibited = FALSE;
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmRemoteDisplayFactory *factory)
{
g_assert (factory->remote_displays_count >= 0);
if (!GDM_IS_REMOTE_DISPLAY (display))
return;
factory->remote_displays_count--;
if (factory->remote_displays_count == 0)
uninhibit_suspend (factory);
}
static gboolean
gdm_remote_display_factory_start (GdmDisplayFactory *base_factory)
{
GdmRemoteDisplayFactory *factory = GDM_REMOTE_DISPLAY_FACTORY (base_factory);
GdmDisplayStore *store;
g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (factory), FALSE);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
g_signal_connect_object (G_OBJECT (store),
"display-added",
G_CALLBACK (on_display_added),
factory,
G_CONNECT_DEFAULT);
g_signal_connect_object (G_OBJECT (store),
"display-removed",
G_CALLBACK (on_display_removed),
factory,
G_CONNECT_DEFAULT);
return TRUE;
}
static gboolean
gdm_remote_display_factory_stop (GdmDisplayFactory *base_factory)
{
GdmRemoteDisplayFactory *factory = GDM_REMOTE_DISPLAY_FACTORY (base_factory);
g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (factory), FALSE);
return TRUE;
}
static void
gdm_remote_display_factory_class_init (GdmRemoteDisplayFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdmDisplayFactoryClass *factory_class = GDM_DISPLAY_FACTORY_CLASS (klass);
object_class->finalize = gdm_remote_display_factory_finalize;
object_class->constructor = gdm_remote_display_factory_constructor;
factory_class->start = gdm_remote_display_factory_start;
factory_class->stop = gdm_remote_display_factory_stop;
}
static void
gdm_remote_display_factory_init (GdmRemoteDisplayFactory *factory)
{
factory->inhibit_suspend_fd = -1;
}
GdmRemoteDisplayFactory *
gdm_remote_display_factory_new (GdmDisplayStore *store)
{
if (remote_display_factory_object != NULL) {
g_object_ref (remote_display_factory_object);
} else {
remote_display_factory_object = g_object_new (GDM_TYPE_REMOTE_DISPLAY_FACTORY,
"display-store", store,
NULL);
g_object_add_weak_pointer (remote_display_factory_object,
(gpointer *) &remote_display_factory_object);
}
return GDM_REMOTE_DISPLAY_FACTORY (remote_display_factory_object);
}

View file

@ -0,0 +1,39 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
*
* 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.
*
*/
#ifndef __GDM_REMOTE_DISPLAY_FACTORY_H
#define __GDM_REMOTE_DISPLAY_FACTORY_H
#include <glib-object.h>
#include "gdm-display-factory.h"
#include "gdm-display-store.h"
G_BEGIN_DECLS
#define GDM_TYPE_REMOTE_DISPLAY_FACTORY (gdm_remote_display_factory_get_type ())
G_DECLARE_FINAL_TYPE (GdmRemoteDisplayFactory, gdm_remote_display_factory, GDM, REMOTE_DISPLAY_FACTORY, GdmDisplayFactory)
GdmRemoteDisplayFactory * gdm_remote_display_factory_new (GdmDisplayStore *display_store);
G_END_DECLS
#endif /* __GDM_REMOTE_DISPLAY_FACTORY_H */

View file

@ -0,0 +1,8 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/RemoteDisplayFactory">
<interface name="org.gnome.DisplayManager.RemoteDisplayFactory">
<method name="CreateRemoteDisplay">
<arg name="remote_id" direction="in" type="o"/>
</method>
</interface>
</node>

152
daemon/gdm-remote-display.c Normal file
View file

@ -0,0 +1,152 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
*
* 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.
*
*/
#include "config.h"
#include <glib-object.h>
#include "gdm-display.h"
#include "gdm-launch-environment.h"
#include "gdm-remote-display.h"
#include "gdm-remote-display-glue.h"
struct _GdmRemoteDisplay
{
GdmDisplay parent;
GdmDBusRemoteDisplay *skeleton;
};
static void gdm_remote_display_class_init (GdmRemoteDisplayClass *klass);
static void gdm_remote_display_init (GdmRemoteDisplay *remote_display);
G_DEFINE_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM_TYPE_DISPLAY)
char *
gdm_remote_display_get_remote_id (GdmRemoteDisplay *display)
{
g_autofree char *remote_id = NULL;
g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY (display), NULL);
g_object_get (G_OBJECT (display->skeleton),
"remote-id", &remote_id,
NULL);
return g_steal_pointer (&remote_id);
}
void
gdm_remote_display_set_remote_id (GdmRemoteDisplay *display,
const char *remote_id)
{
g_object_set (G_OBJECT (display->skeleton), "remote-id", remote_id, NULL);
}
static GObject *
gdm_remote_display_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmRemoteDisplay *display;
display = GDM_REMOTE_DISPLAY (G_OBJECT_CLASS (gdm_remote_display_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
display->skeleton = GDM_DBUS_REMOTE_DISPLAY (gdm_dbus_remote_display_skeleton_new ());
g_dbus_object_skeleton_add_interface (gdm_display_get_object_skeleton (GDM_DISPLAY (display)),
G_DBUS_INTERFACE_SKELETON (display->skeleton));
g_object_bind_property (display, "session-id", display->skeleton, "session-id", G_BINDING_SYNC_CREATE);
return G_OBJECT (display);
}
static void
gdm_remote_display_finalize (GObject *object)
{
GdmRemoteDisplay *display = GDM_REMOTE_DISPLAY (object);
g_clear_object (&display->skeleton);
G_OBJECT_CLASS (gdm_remote_display_parent_class)->finalize (object);
}
static gboolean
gdm_remote_display_prepare (GdmDisplay *display)
{
GdmRemoteDisplay *self = GDM_REMOTE_DISPLAY (display);
g_autoptr (GdmLaunchEnvironment) launch_environment = NULL;
g_autofree char *session_type = NULL;
g_object_get (self,
"session-type", &session_type,
NULL);
launch_environment = gdm_create_greeter_launch_environment (NULL,
NULL,
session_type,
NULL,
FALSE);
g_object_set (self, "launch-environment", launch_environment, NULL);
return GDM_DISPLAY_CLASS (gdm_remote_display_parent_class)->prepare (display);
}
static void
gdm_remote_display_class_init (GdmRemoteDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
object_class->constructor = gdm_remote_display_constructor;
object_class->finalize = gdm_remote_display_finalize;
display_class->prepare = gdm_remote_display_prepare;
}
static void
gdm_remote_display_init (GdmRemoteDisplay *remote_display)
{
}
GdmDisplay *
gdm_remote_display_new (const char *remote_id)
{
GObject *object;
GdmRemoteDisplay *self;
const char *session_types[] = { "wayland", NULL };
object = g_object_new (GDM_TYPE_REMOTE_DISPLAY,
"is-local", FALSE,
"session-type", session_types[0],
"supported-session-types", session_types,
NULL);
self = GDM_REMOTE_DISPLAY (object);
g_object_set (G_OBJECT (self->skeleton), "remote-id", remote_id, NULL);
return GDM_DISPLAY (object);
}

View file

@ -0,0 +1,45 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
*
* 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.
*
*/
#ifndef __GDM_REMOTE_DISPLAY_H
#define __GDM_REMOTE_DISPLAY_H
#include <glib-object.h>
#include <stdint.h>
#include "gdm-display.h"
G_BEGIN_DECLS
#define GDM_TYPE_REMOTE_DISPLAY (gdm_remote_display_get_type ())
G_DECLARE_FINAL_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM, REMOTE_DISPLAY, GdmDisplay)
GdmDisplay * gdm_remote_display_new (const char *remote_id);
char * gdm_remote_display_get_remote_id (GdmRemoteDisplay *self);
void gdm_remote_display_set_remote_id (GdmRemoteDisplay *self,
const char *remote_id);
G_END_DECLS
#endif /* __GDM_REMOTE_DISPLAY_H */

View file

@ -0,0 +1,7 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.gnome.DisplayManager.RemoteDisplay">
<property name="RemoteId" type="o" access="read"/>
<property name="SessionId" type="s" access="read"/>
</interface>
</node>

1089
daemon/gdm-server.c Normal file

File diff suppressed because it is too large Load diff

42
daemon/gdm-server.h Normal file
View file

@ -0,0 +1,42 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SERVER_H
#define __GDM_SERVER_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SERVER (gdm_server_get_type ())
G_DECLARE_FINAL_TYPE (GdmServer, gdm_server, GDM, SERVER, GObject);
GdmServer * gdm_server_new (const char *display_id,
const char *seat_id,
const char *auth_file,
gboolean initial);
gboolean gdm_server_start (GdmServer *server);
gboolean gdm_server_stop (GdmServer *server);
char * gdm_server_get_display_device (GdmServer *server);
G_END_DECLS
#endif /* __GDM_SERVER_H */

View file

@ -0,0 +1,334 @@
/* gdm-session-auditor.c - Object for auditing session login/logout
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#include "config.h"
#include "gdm-session-auditor.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gi18n.h>
typedef struct _GdmSessionAuditorPrivate
{
char *username;
char *hostname;
char *display_device;
} GdmSessionAuditorPrivate;
static void gdm_session_auditor_finalize (GObject *object);
static void gdm_session_auditor_class_install_properties (GdmSessionAuditorClass *
auditor_class);
static void gdm_session_auditor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gdm_session_auditor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
enum {
PROP_0 = 0,
PROP_USERNAME,
PROP_HOSTNAME,
PROP_DISPLAY_DEVICE
};
G_DEFINE_TYPE_WITH_PRIVATE (GdmSessionAuditor, gdm_session_auditor, G_TYPE_OBJECT)
static void
gdm_session_auditor_class_init (GdmSessionAuditorClass *auditor_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (auditor_class);
object_class->finalize = gdm_session_auditor_finalize;
gdm_session_auditor_class_install_properties (auditor_class);
}
static void
gdm_session_auditor_class_install_properties (GdmSessionAuditorClass *auditor_class)
{
GObjectClass *object_class;
GParamSpec *param_spec;
object_class = G_OBJECT_CLASS (auditor_class);
object_class->set_property = gdm_session_auditor_set_property;
object_class->get_property = gdm_session_auditor_get_property;
param_spec = g_param_spec_string ("username", _("Username"),
_("The username"),
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_USERNAME, param_spec);
param_spec = g_param_spec_string ("hostname", _("Hostname"),
_("The hostname"),
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_HOSTNAME, param_spec);
param_spec = g_param_spec_string ("display-device", _("Display Device"),
_("The display device"),
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_DISPLAY_DEVICE, param_spec);
}
static void
gdm_session_auditor_init (GdmSessionAuditor *auditor)
{
}
static void
gdm_session_auditor_finalize (GObject *object)
{
GdmSessionAuditor *auditor;
GdmSessionAuditorPrivate *priv;
GObjectClass *parent_class;
auditor = GDM_SESSION_AUDITOR (object);
priv = gdm_session_auditor_get_instance_private (auditor);
g_free (priv->username);
g_free (priv->hostname);
g_free (priv->display_device);
parent_class = G_OBJECT_CLASS (gdm_session_auditor_parent_class);
if (parent_class->finalize != NULL) {
parent_class->finalize (object);
}
}
void
gdm_session_auditor_set_username (GdmSessionAuditor *auditor,
const char *username)
{
GdmSessionAuditorPrivate *priv;
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
priv = gdm_session_auditor_get_instance_private (auditor);
if (username == priv->username) {
return;
}
if ((username == NULL || priv->username == NULL) ||
strcmp (username, priv->username) != 0) {
priv->username = g_strdup (username);
g_object_notify (G_OBJECT (auditor), "username");
}
}
static void
gdm_session_auditor_set_hostname (GdmSessionAuditor *auditor,
const char *hostname)
{
GdmSessionAuditorPrivate *priv;
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
priv = gdm_session_auditor_get_instance_private (auditor);
priv->hostname = g_strdup (hostname);
}
static void
gdm_session_auditor_set_display_device (GdmSessionAuditor *auditor,
const char *display_device)
{
GdmSessionAuditorPrivate *priv;
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
priv = gdm_session_auditor_get_instance_private (auditor);
priv->display_device = g_strdup (display_device);
}
static char *
gdm_session_auditor_get_username (GdmSessionAuditor *auditor)
{
GdmSessionAuditorPrivate *priv;
priv = gdm_session_auditor_get_instance_private (auditor);
return g_strdup (priv->username);
}
static char *
gdm_session_auditor_get_hostname (GdmSessionAuditor *auditor)
{
GdmSessionAuditorPrivate *priv;
priv = gdm_session_auditor_get_instance_private (auditor);
return g_strdup (priv->hostname);
}
static char *
gdm_session_auditor_get_display_device (GdmSessionAuditor *auditor)
{
GdmSessionAuditorPrivate *priv;
priv = gdm_session_auditor_get_instance_private (auditor);
return g_strdup (priv->display_device);
}
static void
gdm_session_auditor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmSessionAuditor *auditor;
auditor = GDM_SESSION_AUDITOR (object);
switch (prop_id) {
case PROP_USERNAME:
gdm_session_auditor_set_username (auditor, g_value_get_string (value));
break;
case PROP_HOSTNAME:
gdm_session_auditor_set_hostname (auditor, g_value_get_string (value));
break;
case PROP_DISPLAY_DEVICE:
gdm_session_auditor_set_display_device (auditor, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdm_session_auditor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmSessionAuditor *auditor;
auditor = GDM_SESSION_AUDITOR (object);
switch (prop_id) {
case PROP_USERNAME:
g_value_take_string (value, gdm_session_auditor_get_username (auditor));
break;
case PROP_HOSTNAME:
g_value_take_string (value, gdm_session_auditor_get_hostname (auditor));
break;
case PROP_DISPLAY_DEVICE:
g_value_take_string (value, gdm_session_auditor_get_display_device (auditor));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
GdmSessionAuditor *
gdm_session_auditor_new (const char *hostname,
const char *display_device)
{
GdmSessionAuditor *auditor;
auditor = g_object_new (GDM_TYPE_SESSION_AUDITOR,
"hostname", hostname,
"display-device", display_device,
NULL);
return auditor;
}
void
gdm_session_auditor_report_password_changed (GdmSessionAuditor *auditor)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_password_changed != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_password_changed (auditor);
}
}
void
gdm_session_auditor_report_password_change_failure (GdmSessionAuditor *auditor)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_password_change_failure != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_password_change_failure (auditor);
}
}
void
gdm_session_auditor_report_user_accredited (GdmSessionAuditor *auditor)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_user_accredited != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_user_accredited (auditor);
}
}
void
gdm_session_auditor_report_login (GdmSessionAuditor *auditor)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_login != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_login (auditor);
}
}
void
gdm_session_auditor_report_login_failure (GdmSessionAuditor *auditor,
int error_code,
const char *error_message)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_login_failure != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_login_failure (auditor, error_code, error_message);
}
}
void
gdm_session_auditor_report_logout (GdmSessionAuditor *auditor)
{
g_return_if_fail (GDM_IS_SESSION_AUDITOR (auditor));
if (GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_logout != NULL) {
GDM_SESSION_AUDITOR_GET_CLASS (auditor)->report_logout (auditor);
}
}

View file

@ -0,0 +1,65 @@
/* gdm-session-auditor.h - Object for auditing session login/logout
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#ifndef GDM_SESSION_AUDITOR_H
#define GDM_SESSION_AUDITOR_H
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_AUDITOR (gdm_session_auditor_get_type ())
G_DECLARE_DERIVABLE_TYPE (GdmSessionAuditor, gdm_session_auditor, GDM, SESSION_AUDITOR, GObject)
struct _GdmSessionAuditorClass
{
GObjectClass parent_class;
void (* report_password_changed) (GdmSessionAuditor *auditor);
void (* report_password_change_failure) (GdmSessionAuditor *auditor);
void (* report_user_accredited) (GdmSessionAuditor *auditor);
void (* report_login) (GdmSessionAuditor *auditor);
void (* report_login_failure) (GdmSessionAuditor *auditor,
int error_code,
const char *error_message);
void (* report_logout) (GdmSessionAuditor *auditor);
};
GdmSessionAuditor *gdm_session_auditor_new (const char *hostname,
const char *display_device);
void gdm_session_auditor_set_username (GdmSessionAuditor *auditor,
const char *username);
void gdm_session_auditor_report_password_changed (GdmSessionAuditor *auditor);
void gdm_session_auditor_report_password_change_failure (GdmSessionAuditor *auditor);
void gdm_session_auditor_report_user_accredited (GdmSessionAuditor *auditor);
void gdm_session_auditor_report_login (GdmSessionAuditor *auditor);
void gdm_session_auditor_report_login_failure (GdmSessionAuditor *auditor,
int error_code,
const char *error_message);
void gdm_session_auditor_report_logout (GdmSessionAuditor *auditor);
G_END_DECLS
#endif /* GDM_SESSION_AUDITOR_H */

View file

@ -0,0 +1,42 @@
/*** BEGIN file-header ***/
#include <glib-object.h>
/*** END file-header ***/
/*** BEGIN file-production ***/
#include "@filename@"
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
GType
@enum_name@_get_type (void)
{
static GType etype = 0;
if (G_UNLIKELY(etype == 0)) {
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
}
return etype;
}
/*** END value-tail ***/
/*** BEGIN file-tail ***/
/**/
/*** END file-tail ***/

View file

@ -0,0 +1,24 @@
/*** BEGIN file-header ***/
#ifndef GDM_SESSION_ENUM_TYPES_H
#define GDM_SESSION_ENUM_TYPES_H
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* GDM_SESSION_ENUM_TYPES_H */
/*** END file-tail ***/

View file

@ -0,0 +1,161 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#include "config.h"
#include "gdm-session-linux-auditor.h"
#include <fcntl.h>
#include <pwd.h>
#include <syslog.h>
#include <unistd.h>
#include <libaudit.h>
#include <glib.h>
#include "gdm-common.h"
struct _GdmSessionLinuxAuditor
{
GdmSessionAuditor parent;
int audit_fd;
};
static void gdm_session_linux_auditor_finalize (GObject *object);
G_DEFINE_TYPE (GdmSessionLinuxAuditor, gdm_session_linux_auditor, GDM_TYPE_SESSION_AUDITOR)
static void
log_user_message (GdmSessionAuditor *auditor,
gint type,
gint result)
{
GdmSessionLinuxAuditor *linux_auditor;
char buf[512];
g_autofree char *username = NULL;
g_autofree char *hostname = NULL;
g_autofree char *display_device = NULL;
struct passwd *pw;
linux_auditor = GDM_SESSION_LINUX_AUDITOR (auditor);
g_object_get (G_OBJECT (auditor), "username", &username, NULL);
g_object_get (G_OBJECT (auditor), "hostname", &hostname, NULL);
g_object_get (G_OBJECT (auditor), "display-device", &display_device, NULL);
if (username != NULL) {
gdm_get_pwent_for_name (username, &pw);
} else {
username = g_strdup ("unknown");
pw = NULL;
}
if (pw != NULL) {
g_snprintf (buf, sizeof (buf), "uid=%d", pw->pw_uid);
audit_log_user_message (linux_auditor->audit_fd, type,
buf, hostname, NULL, display_device,
result);
} else {
g_snprintf (buf, sizeof (buf), "acct=%s", username);
audit_log_user_message (linux_auditor->audit_fd, type,
buf, hostname, NULL, display_device,
result);
}
}
static void
gdm_session_linux_auditor_report_login (GdmSessionAuditor *auditor)
{
log_user_message (auditor, AUDIT_USER_LOGIN, 1);
}
static void
gdm_session_linux_auditor_report_login_failure (GdmSessionAuditor *auditor,
int pam_error_code,
const char *pam_error_string)
{
log_user_message (auditor, AUDIT_USER_LOGIN, 0);
}
static void
gdm_session_linux_auditor_report_logout (GdmSessionAuditor *auditor)
{
log_user_message (auditor, AUDIT_USER_LOGOUT, 1);
}
static void
gdm_session_linux_auditor_class_init (GdmSessionLinuxAuditorClass *klass)
{
GObjectClass *object_class;
GdmSessionAuditorClass *auditor_class;
object_class = G_OBJECT_CLASS (klass);
auditor_class = GDM_SESSION_AUDITOR_CLASS (klass);
object_class->finalize = gdm_session_linux_auditor_finalize;
auditor_class->report_login = gdm_session_linux_auditor_report_login;
auditor_class->report_login_failure = gdm_session_linux_auditor_report_login_failure;
auditor_class->report_logout = gdm_session_linux_auditor_report_logout;
}
static void
gdm_session_linux_auditor_init (GdmSessionLinuxAuditor *auditor)
{
auditor->audit_fd = audit_open ();
}
static void
gdm_session_linux_auditor_finalize (GObject *object)
{
GdmSessionLinuxAuditor *linux_auditor;
GObjectClass *parent_class;
linux_auditor = GDM_SESSION_LINUX_AUDITOR (object);
close (linux_auditor->audit_fd);
parent_class = G_OBJECT_CLASS (gdm_session_linux_auditor_parent_class);
if (parent_class->finalize != NULL) {
parent_class->finalize (object);
}
}
GdmSessionAuditor *
gdm_session_linux_auditor_new (const char *hostname,
const char *display_device)
{
GObject *auditor;
auditor = g_object_new (GDM_TYPE_SESSION_LINUX_AUDITOR,
"hostname", hostname,
"display-device", display_device,
NULL);
return GDM_SESSION_AUDITOR (auditor);
}

View file

@ -0,0 +1,43 @@
/* gdm-linux-session-auditor.h - Object for linux auditing of session login/logout
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#ifndef GDM_SESSION_LINUX_AUDITOR_H
#define GDM_SESSION_LINUX_AUDITOR_H
#include <glib.h>
#include <glib-object.h>
#include "gdm-session-auditor.h"
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_LINUX_AUDITOR (gdm_session_linux_auditor_get_type ())
G_DECLARE_FINAL_TYPE (GdmSessionLinuxAuditor, gdm_session_linux_auditor, GDM, SESSION_LINUX_AUDITOR, GdmSessionAuditor)
GdmSessionAuditor *gdm_session_linux_auditor_new (const char *hostname,
const char *display_device);
G_END_DECLS
#endif /* GDM_SESSION_LINUX_AUDITOR_H */

308
daemon/gdm-session-record.c Normal file
View file

@ -0,0 +1,308 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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, 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.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(HAVE_UTMPX_H)
#include <utmpx.h>
#endif
#if defined(HAVE_UTMP_H)
#include <utmp.h>
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include "gdm-session-record.h"
#ifndef GDM_BAD_SESSION_RECORDS_FILE
#define GDM_BAD_SESSION_RECORDS_FILE "/var/log/btmp"
#endif
#if !defined(GDM_NEW_SESSION_RECORDS_FILE)
# if defined(WTMPX_FILE)
# define GDM_NEW_SESSION_RECORDS_FILE WTMPX_FILE
# elif defined(_PATH_WTMPX)
# define GDM_NEW_SESSION_RECORDS_FILE _PATH_WTMPX
# elif defined(WTMPX_FILENAME)
# define GDM_NEW_SESSION_RECORDS_FILE WTMPX_FILENAME
# elif defined(WTMP_FILE)
# define GDM_NEW_SESSION_RECORDS_FILE WTMP_FILE
# elif defined(_PATH_WTMP) /* BSD systems */
# define GDM_NEW_SESSION_RECORDS_FILE _PATH_WTMP
# else
# define GDM_NEW_SESSION_RECORDS_FILE "/var/log/wtmp"
# endif
#endif
static void
record_set_username (UTMP *u,
const char *username)
{
#if defined(HAVE_UT_UT_USER)
memccpy (u->ut_user, username, '\0', sizeof (u->ut_user));
g_debug ("using ut_user %.*s",
(int) sizeof (u->ut_user),
u->ut_user);
#elif defined(HAVE_UT_UT_NAME)
memccpy (u->ut_name, username, '\0', sizeof (u->ut_name));
g_debug ("using ut_name %.*s",
(int) sizeof (u->ut_name),
u->ut_name);
#endif
}
static void
record_set_timestamp (UTMP *u)
{
#if defined(HAVE_UT_UT_TV)
gint64 now;
/* Set time in TV format */
now = g_get_real_time();
u->ut_tv.tv_sec = now / G_USEC_PER_SEC;
u->ut_tv.tv_usec = now % G_USEC_PER_SEC;
g_debug ("using ut_tv time %ld",
(glong) u->ut_tv.tv_sec);
#elif defined(HAVE_UT_UT_TIME)
/* Set time in time format */
time (&u->ut_time);
g_debug ("using ut_time %ld",
(glong) u->ut_time);
#endif
}
static void
record_set_pid (UTMP *u,
GPid pid)
{
#if defined(HAVE_UT_UT_PID)
/* Set pid */
if (pid != 0) {
u->ut_pid = pid;
}
g_debug ("using ut_pid %d", (int) u->ut_pid);
#endif
}
static void
record_set_host (UTMP *u,
const char *x11_display_name,
const char *host_name)
{
g_autofree char *hostname = NULL;
#if defined(HAVE_UT_UT_HOST)
/*
* Set ut_host to hostname:$DISPLAY if remote, otherwise set
* to $DISPLAY
*/
if (host_name != NULL
&& x11_display_name != NULL
&& g_str_has_prefix (x11_display_name, ":")) {
hostname = g_strdup_printf ("%s%s", host_name, x11_display_name);
} else {
hostname = g_strdup (x11_display_name);
}
if (hostname != NULL) {
memccpy (u->ut_host, hostname, '\0', sizeof (u->ut_host));
g_debug ("using ut_host %.*s", (int) sizeof (u->ut_host), u->ut_host);
#ifdef HAVE_UT_UT_SYSLEN
u->ut_syslen = MIN (strlen (hostname), sizeof (u->ut_host));
#endif
}
#endif
}
static void
record_set_line (UTMP *u,
const char *display_device,
const char *x11_display_name)
{
/*
* Set ut_line to the device name associated with this display
* but remove the "/dev/" prefix if there is one. Otherwise, if it
* seems like the display device is a seat id, just use it wholesale.
* If there's no device at all, but $DISPLAY is set, just fall back to
* using that.
*/
if (display_device != NULL && g_str_has_prefix (display_device, "/dev/")) {
memccpy (u->ut_line,
display_device + strlen ("/dev/"),
'\0',
sizeof (u->ut_line));
} else if (display_device != NULL && g_str_has_prefix (display_device, "seat")) {
memccpy (u->ut_line,
display_device,
'\0',
sizeof (u->ut_line));
} else if (x11_display_name != NULL) {
memccpy (u->ut_line,
x11_display_name,
'\0',
sizeof (u->ut_line));
}
g_debug ("using ut_line %.*s", (int) sizeof (u->ut_line), u->ut_line);
}
void
gdm_session_record_login (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device)
{
UTMP session_record = { 0 };
if (x11_display_name == NULL)
x11_display_name = display_device;
record_set_username (&session_record, user_name);
g_debug ("Writing login record");
#if defined(HAVE_UT_UT_TYPE)
session_record.ut_type = USER_PROCESS;
g_debug ("using ut_type USER_PROCESS");
#endif
record_set_timestamp (&session_record);
record_set_pid (&session_record, session_pid);
record_set_host (&session_record, x11_display_name, host_name);
record_set_line (&session_record, display_device, x11_display_name);
/* Handle wtmp */
g_debug ("Writing wtmp session record to " GDM_NEW_SESSION_RECORDS_FILE);
#if defined(HAVE_UPDWTMPX)
updwtmpx (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
#elif defined(HAVE_UPDWTMP)
updwtmp (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
#elif defined(HAVE_LOGWTMP) && defined(HAVE_UT_UT_HOST)
#if defined(HAVE_UT_UT_USER)
logwtmp (session_record.ut_line, session_record.ut_user, session_record.ut_host);
#elif defined(HAVE_UT_UT_NAME)
logwtmp (session_record.ut_line, session_record.ut_name, session_record.ut_host);
#endif
#endif
/* Handle utmp */
#if defined(HAVE_GETUTXENT)
g_debug ("Adding or updating utmp record for login");
setutxent();
pututxline (&session_record);
endutxent();
#elif defined(HAVE_LOGIN)
login (&session_record);
#endif
}
void
gdm_session_record_logout (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device)
{
UTMP session_record = { 0 };
if (x11_display_name == NULL)
x11_display_name = display_device;
g_debug ("Writing logout record");
#if defined(HAVE_UT_UT_TYPE)
session_record.ut_type = DEAD_PROCESS;
g_debug ("using ut_type DEAD_PROCESS");
#endif
record_set_timestamp (&session_record);
record_set_pid (&session_record, session_pid);
record_set_host (&session_record, x11_display_name, host_name);
record_set_line (&session_record, display_device, x11_display_name);
/* Handle wtmp */
g_debug ("Writing wtmp logout record to " GDM_NEW_SESSION_RECORDS_FILE);
#if defined(HAVE_UPDWTMPX)
updwtmpx (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
#elif defined (HAVE_UPDWTMP)
updwtmp (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
#elif defined(HAVE_LOGWTMP)
logwtmp (session_record.ut_line, "", "");
#endif
/* Handle utmp */
#if defined(HAVE_GETUTXENT)
g_debug ("Adding or updating utmp record for logout");
setutxent();
pututxline (&session_record);
endutxent();
#elif defined(HAVE_LOGOUT)
logout (session_record.ut_line);
#endif
}
void
gdm_session_record_failed (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device)
{
UTMP session_record = { 0 };
if (x11_display_name == NULL)
x11_display_name = display_device;
record_set_username (&session_record, user_name);
g_debug ("Writing failed session attempt record");
#if defined(HAVE_UT_UT_TYPE)
session_record.ut_type = USER_PROCESS;
g_debug ("using ut_type USER_PROCESS");
#endif
record_set_timestamp (&session_record);
record_set_pid (&session_record, session_pid);
record_set_host (&session_record, x11_display_name, host_name);
record_set_line (&session_record, display_device, x11_display_name);
#if defined(HAVE_UPDWTMPX) || defined(HAVE_UPDWTMP)
/* Handle btmp */
g_debug ("Writing btmp failed session attempt record to "
GDM_BAD_SESSION_RECORDS_FILE);
#endif
#if defined(HAVE_UPDWTMPX)
updwtmpx (GDM_BAD_SESSION_RECORDS_FILE, &session_record);
#elif defined(HAVE_UPDWTMP)
updwtmp(GDM_BAD_SESSION_RECORDS_FILE, &session_record);
#endif
}

View file

@ -0,0 +1,50 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
*
* 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, 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.
*/
#ifndef __GDM_SESSION_RECORD_H
#define __GDM_SESSION_RECORD_H
#include <glib.h>
G_BEGIN_DECLS
void
gdm_session_record_login (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device);
void
gdm_session_record_logout (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device);
void
gdm_session_record_failed (GPid session_pid,
const char *user_name,
const char *host_name,
const char *x11_display_name,
const char *display_device);
G_END_DECLS
#endif /* GDM_SESSION_RECORD_H */

View file

@ -0,0 +1,410 @@
/* gdm-session-settings.c - Loads session and language from ~/.dmrc
*
* Copyright (C) 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Ray Strode <rstrode@redhat.com>
*/
#include "config.h"
#include "gdm-session-settings.h"
#include <errno.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gi18n.h>
#include <act/act-user-manager.h>
struct _GdmSessionSettings
{
GObject parent;
ActUserManager *user_manager;
ActUser *user;
char *session_name;
char *session_type;
char *language_name;
};
static void gdm_session_settings_finalize (GObject *object);
static void gdm_session_settings_class_install_properties (GdmSessionSettingsClass *
settings_class);
static void gdm_session_settings_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gdm_session_settings_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
enum {
PROP_0 = 0,
PROP_SESSION_NAME,
PROP_SESSION_TYPE,
PROP_LANGUAGE_NAME,
PROP_IS_LOADED
};
G_DEFINE_TYPE (GdmSessionSettings, gdm_session_settings, G_TYPE_OBJECT)
static void
gdm_session_settings_class_init (GdmSessionSettingsClass *settings_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (settings_class);
object_class->finalize = gdm_session_settings_finalize;
gdm_session_settings_class_install_properties (settings_class);
}
static void
gdm_session_settings_class_install_properties (GdmSessionSettingsClass *settings_class)
{
GObjectClass *object_class;
GParamSpec *param_spec;
object_class = G_OBJECT_CLASS (settings_class);
object_class->set_property = gdm_session_settings_set_property;
object_class->get_property = gdm_session_settings_get_property;
param_spec = g_param_spec_string ("session-name", "Session Name",
"The name of the session",
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_SESSION_NAME, param_spec);
param_spec = g_param_spec_string ("session-type", "Session Type",
"The type of the session",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_SESSION_TYPE, param_spec);
param_spec = g_param_spec_string ("language-name", "Language Name",
"The name of the language",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_LANGUAGE_NAME, param_spec);
param_spec = g_param_spec_boolean ("is-loaded", NULL, NULL,
FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_IS_LOADED, param_spec);
}
static void
gdm_session_settings_init (GdmSessionSettings *settings)
{
settings->user_manager = act_user_manager_get_default ();
}
static void
gdm_session_settings_finalize (GObject *object)
{
GdmSessionSettings *settings;
GObjectClass *parent_class;
settings = GDM_SESSION_SETTINGS (object);
if (settings->user != NULL) {
g_object_unref (settings->user);
}
g_free (settings->session_name);
g_free (settings->language_name);
parent_class = G_OBJECT_CLASS (gdm_session_settings_parent_class);
if (parent_class->finalize != NULL) {
parent_class->finalize (object);
}
}
void
gdm_session_settings_set_language_name (GdmSessionSettings *settings,
const char *language_name)
{
g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
if (settings->language_name == NULL ||
strcmp (settings->language_name, language_name) != 0) {
settings->language_name = g_strdup (language_name);
g_object_notify (G_OBJECT (settings), "language-name");
}
}
void
gdm_session_settings_set_session_name (GdmSessionSettings *settings,
const char *session_name)
{
g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
if (settings->session_name == NULL ||
strcmp (settings->session_name, session_name) != 0) {
settings->session_name = g_strdup (session_name);
g_object_notify (G_OBJECT (settings), "session-name");
}
}
void
gdm_session_settings_set_session_type (GdmSessionSettings *settings,
const char *session_type)
{
g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
if (settings->session_type == NULL ||
g_strcmp0 (settings->session_type, session_type) != 0) {
settings->session_type = g_strdup (session_type);
g_object_notify (G_OBJECT (settings), "session-type");
}
}
char *
gdm_session_settings_get_language_name (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
return g_strdup (settings->language_name);
}
char *
gdm_session_settings_get_session_name (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
return g_strdup (settings->session_name);
}
char *
gdm_session_settings_get_session_type (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
return g_strdup (settings->session_type);
}
static void
gdm_session_settings_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmSessionSettings *settings;
settings = GDM_SESSION_SETTINGS (object);
switch (prop_id) {
case PROP_LANGUAGE_NAME:
gdm_session_settings_set_language_name (settings, g_value_get_string (value));
break;
case PROP_SESSION_NAME:
gdm_session_settings_set_session_name (settings, g_value_get_string (value));
break;
case PROP_SESSION_TYPE:
gdm_session_settings_set_session_type (settings, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdm_session_settings_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmSessionSettings *settings;
settings = GDM_SESSION_SETTINGS (object);
switch (prop_id) {
case PROP_SESSION_NAME:
g_value_set_string (value, settings->session_name);
break;
case PROP_SESSION_TYPE:
g_value_set_string (value, settings->session_type);
break;
case PROP_LANGUAGE_NAME:
g_value_set_string (value, settings->language_name);
break;
case PROP_IS_LOADED:
g_value_set_boolean (value, gdm_session_settings_is_loaded (settings));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
GdmSessionSettings *
gdm_session_settings_new (void)
{
GdmSessionSettings *settings;
settings = g_object_new (GDM_TYPE_SESSION_SETTINGS,
NULL);
return settings;
}
gboolean
gdm_session_settings_is_loaded (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), FALSE);
if (settings->user == NULL) {
return FALSE;
}
return act_user_is_loaded (settings->user);
}
static void
load_settings_from_user (GdmSessionSettings *settings)
{
const char *session_name;
const char *session_type;
const char *language_name;
if (!act_user_is_loaded (settings->user)) {
g_warning ("GdmSessionSettings: trying to load user settings from unloaded user");
return;
}
/* Load settings even if the user doesn't have saved state, as they could have been
* configured in AccountsService by the administrator */
session_type = act_user_get_session_type (settings->user);
session_name = act_user_get_session (settings->user);
g_debug ("GdmSessionSettings: saved session is %s (type %s)", session_name, session_type);
if (session_type != NULL && session_type[0] != '\0') {
gdm_session_settings_set_session_type (settings, session_type);
}
if (session_name != NULL && session_name[0] != '\0') {
gdm_session_settings_set_session_name (settings, session_name);
}
language_name = act_user_get_language (settings->user);
g_debug ("GdmSessionSettings: saved language is %s", language_name);
if (language_name != NULL && language_name[0] != '\0') {
gdm_session_settings_set_language_name (settings, language_name);
}
g_object_notify (G_OBJECT (settings), "is-loaded");
}
static void
on_user_is_loaded_changed (ActUser *user,
GParamSpec *pspec,
GdmSessionSettings *settings)
{
if (act_user_is_loaded (settings->user)) {
load_settings_from_user (settings);
g_signal_handlers_disconnect_by_func (G_OBJECT (settings->user),
G_CALLBACK (on_user_is_loaded_changed),
settings);
}
}
gboolean
gdm_session_settings_load (GdmSessionSettings *settings,
const char *username)
{
g_autoptr(ActUser) old_user = NULL;
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), FALSE);
g_return_val_if_fail (username != NULL, FALSE);
g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE);
old_user = g_steal_pointer (&settings->user);
if (old_user != NULL) {
g_signal_handlers_disconnect_by_func (G_OBJECT (old_user),
G_CALLBACK (on_user_is_loaded_changed),
settings);
}
settings->user = act_user_manager_get_user (settings->user_manager,
username);
if (!act_user_is_loaded (settings->user)) {
g_signal_connect (settings->user,
"notify::is-loaded",
G_CALLBACK (on_user_is_loaded_changed),
settings);
return FALSE;
}
load_settings_from_user (settings);
return TRUE;
}
gboolean
gdm_session_settings_save (GdmSessionSettings *settings,
const char *username)
{
g_autoptr(ActUser) user = NULL;
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), FALSE);
g_return_val_if_fail (username != NULL, FALSE);
g_return_val_if_fail (gdm_session_settings_is_loaded (settings), FALSE);
user = act_user_manager_get_user (settings->user_manager,
username);
if (!act_user_is_loaded (user)) {
return FALSE;
}
if (settings->session_name != NULL) {
act_user_set_session (user, settings->session_name);
}
if (settings->session_type != NULL) {
act_user_set_session_type (user, settings->session_type);
}
if (settings->language_name != NULL) {
act_user_set_language (user, settings->language_name);
}
if (!act_user_is_local_account (user)) {
g_autoptr (GError) error = NULL;
act_user_manager_cache_user (settings->user_manager, username, &error);
if (error != NULL) {
g_debug ("GdmSessionSettings: Could not locally cache remote user: %s", error->message);
return FALSE;
}
}
return TRUE;
}

View file

@ -0,0 +1,51 @@
/* gdm-session-settings.h - Object for auditing session login/logout
*
* Copyright (C) 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Ray Strode <rstrode@redhat.com>
*/
#ifndef GDM_SESSION_SETTINGS_H
#define GDM_SESSION_SETTINGS_H
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_SETTINGS (gdm_session_settings_get_type ())
G_DECLARE_FINAL_TYPE (GdmSessionSettings, gdm_session_settings, GDM, SESSION_SETTINGS, GObject)
GdmSessionSettings *gdm_session_settings_new (void);
gboolean gdm_session_settings_load (GdmSessionSettings *settings,
const char *username);
gboolean gdm_session_settings_save (GdmSessionSettings *settings,
const char *username);
gboolean gdm_session_settings_is_loaded (GdmSessionSettings *settings);
char *gdm_session_settings_get_language_name (GdmSessionSettings *settings);
char *gdm_session_settings_get_session_name (GdmSessionSettings *settings);
char *gdm_session_settings_get_session_type (GdmSessionSettings *settings);
void gdm_session_settings_set_language_name (GdmSessionSettings *settings,
const char *language_name);
void gdm_session_settings_set_session_name (GdmSessionSettings *settings,
const char *session_name);
void gdm_session_settings_set_session_type (GdmSessionSettings *settings,
const char *session_type);
G_END_DECLS
#endif /* GDM_SESSION_SETTINGS_H */

View file

@ -0,0 +1,390 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#include "config.h"
#include "gdm-session-solaris-auditor.h"
#include "gdm-common.h"
#include <syslog.h>
#include <security/pam_appl.h>
#include <pwd.h>
#include <fcntl.h>
#include <bsm/adt.h>
#include <bsm/adt_event.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gi18n.h>
struct _GdmSessionSolarisAuditor
{
GdmSessionAuditor parent;
adt_session_data_t *audit_session_handle;
guint password_change_initiated : 1;
guint password_changed : 1;
guint user_accredited : 1;
/* cached values to prevent repeated calls
* to getpwnam
*/
char *username;
uid_t uid;
gid_t gid;
};
static void gdm_session_solaris_auditor_finalize (GObject *object);
G_DEFINE_TYPE (GdmSessionSolarisAuditor, gdm_session_solaris_auditor, GDM_TYPE_SESSION_AUDITOR)
static void
gdm_session_solaris_auditor_report_password_changed (GdmSessionAuditor *auditor)
{
GdmSessionSolarisAuditor *solaris_auditor;
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
solaris_auditor->password_change_initiated = TRUE;
solaris_auditor->password_changed = TRUE;
}
static void
gdm_session_solaris_auditor_report_password_change_failure (GdmSessionAuditor *auditor)
{
GdmSessionSolarisAuditor *solaris_auditor;
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
solaris_auditor->password_change_initiated = TRUE;
solaris_auditor->password_changed = FALSE;
}
static void
gdm_session_solaris_auditor_report_user_accredited (GdmSessionAuditor *auditor)
{
GdmSessionSolarisAuditor *solaris_auditor;
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
solaris_auditor->user_accredited = TRUE;
}
static void
gdm_session_solaris_auditor_report_login (GdmSessionAuditor *auditor)
{
GdmSessionSolarisAuditor *solaris_auditor;
adt_session_data_t *adt_ah; /* Audit session handle */
adt_event_data_t *event; /* Event to generate */
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
g_return_if_fail (solaris_auditor->username != NULL);
adt_ah = NULL;
if (adt_start_session (&adt_ah, NULL, ADT_USE_PROC_DATA) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_start_session (ADT_login): %m");
goto cleanup;
}
if (adt_set_user (adt_ah, solaris_auditor->uid,
solaris_auditor->gid, solaris_auditor->uid,
solaris_auditor->gid, NULL, ADT_USER) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_set_user (ADT_login, %s): %m",
solaris_auditor->username);
}
event = adt_alloc_event (adt_ah, ADT_login);
if (event == NULL) {
syslog (LOG_AUTH | LOG_ALERT, "adt_alloc_event (ADT_login): %m");
} else if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_login, ADT_SUCCESS): %m");
}
if (solaris_auditor->password_changed) {
g_assert (solaris_auditor->password_change_initiated);
/* Also audit password change */
adt_free_event (event);
event = adt_alloc_event (adt_ah, ADT_passwd);
if (event == NULL) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_alloc_event (ADT_passwd): %m");
} else if (adt_put_event (event, ADT_SUCCESS,
ADT_SUCCESS) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_passwd, ADT_SUCCESS): %m");
}
}
adt_free_event (event);
cleanup:
solaris_auditor->audit_session_handle = adt_ah;
}
static void
gdm_session_solaris_auditor_report_login_failure (GdmSessionAuditor *auditor,
int pam_error_code,
const char *pam_error_string)
{
GdmSessionSolarisAuditor *solaris_auditor;
char *hostname;
char *display_device;
adt_session_data_t *ah; /* Audit session handle */
adt_event_data_t *event; /* Event to generate */
adt_termid_t *tid; /* Terminal ID for failures */
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
g_object_get (G_OBJECT (auditor),
"hostname", &hostname,
"display-device", &display_device, NULL);
if (solaris_auditor->user_accredited) {
if (adt_start_session (&ah, NULL, ADT_USE_PROC_DATA) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_start_session (ADT_login, ADT_FAILURE): %m");
goto cleanup;
}
} else {
if (adt_start_session (&ah, NULL, 0) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_start_session (ADT_login, ADT_FAILURE): %m");
goto cleanup;
}
/* If display is on console or VT */
if (hostname != NULL && hostname[0] != '\0') {
/* Login from a remote host */
if (adt_load_hostname (hostname, &tid) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_loadhostname (%s): %m", hostname);
}
} else {
/* login from the local host */
if (adt_load_ttyname (display_device, &tid) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_loadhostname (localhost): %m");
}
}
if (adt_set_user (ah,
solaris_auditor->username != NULL ? solaris_auditor->uid : ADT_NO_ATTRIB,
solaris_auditor->username != NULL ? solaris_auditor->gid : ADT_NO_ATTRIB,
solaris_auditor->username != NULL ? solaris_auditor->uid : ADT_NO_ATTRIB,
solaris_auditor->username != NULL ? solaris_auditor->gid : ADT_NO_ATTRIB,
tid, ADT_NEW) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_set_user (%s): %m",
solaris_auditor->username != NULL ? solaris_auditor->username : "ADT_NO_ATTRIB");
}
}
event = adt_alloc_event (ah, ADT_login);
if (event == NULL) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_alloc_event (ADT_login, ADT_FAILURE): %m");
goto done;
} else if (adt_put_event (event, ADT_FAILURE,
ADT_FAIL_PAM + pam_error_code) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_login (ADT_FAIL, %s): %m",
pam_error_string);
}
if (solaris_auditor->password_change_initiated) {
/* Also audit password change */
adt_free_event (event);
event = adt_alloc_event (ah, ADT_passwd);
if (event == NULL) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_alloc_event (ADT_passwd): %m");
goto done;
}
if (solaris_auditor->password_changed) {
if (adt_put_event (event, ADT_SUCCESS,
ADT_SUCCESS) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_passwd, ADT_SUCCESS): "
"%m");
}
} else {
if (adt_put_event (event, ADT_FAILURE,
ADT_FAIL_PAM + pam_error_code) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_passwd, ADT_FAILURE): "
"%m");
}
}
}
adt_free_event (event);
done:
/* Reset process audit state. this process is being reused.*/
if ((adt_set_user (ah, ADT_NO_AUDIT, ADT_NO_AUDIT, ADT_NO_AUDIT,
ADT_NO_AUDIT, NULL, ADT_NEW) != 0) ||
(adt_set_proc (ah) != 0)) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_login (ADT_FAILURE reset, %m)");
}
(void) adt_end_session (ah);
cleanup:
g_free (hostname);
g_free (display_device);
}
static void
gdm_session_solaris_auditor_report_logout (GdmSessionAuditor *auditor)
{
GdmSessionSolarisAuditor *solaris_auditor;
adt_session_data_t *adt_ah; /* Audit session handle */
adt_event_data_t *event; /* Event to generate */
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (auditor);
adt_ah = solaris_auditor->audit_session_handle;
event = adt_alloc_event (adt_ah, ADT_logout);
if (event == NULL) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_alloc_event (ADT_logout): %m");
} else if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_put_event (ADT_logout, ADT_SUCCESS): %m");
}
adt_free_event (event);
/* Reset process audit state. this process is being reused. */
if ((adt_set_user (adt_ah, ADT_NO_AUDIT, ADT_NO_AUDIT, ADT_NO_AUDIT,
ADT_NO_AUDIT, NULL, ADT_NEW) != 0) ||
(adt_set_proc (adt_ah) != 0)) {
syslog (LOG_AUTH | LOG_ALERT,
"adt_set_proc (ADT_logout reset): %m");
}
(void) adt_end_session (adt_ah);
solaris_auditor->audit_session_handle = NULL;
}
static void
gdm_session_solaris_auditor_class_init (GdmSessionSolarisAuditorClass *klass)
{
GObjectClass *object_class;
GdmSessionAuditorClass *auditor_class;
object_class = G_OBJECT_CLASS (klass);
auditor_class = GDM_SESSION_AUDITOR_CLASS (klass);
object_class->finalize = gdm_session_solaris_auditor_finalize;
auditor_class->report_password_changed = gdm_session_solaris_auditor_report_password_changed;
auditor_class->report_password_change_failure = gdm_session_solaris_auditor_report_password_change_failure;
auditor_class->report_user_accredited = gdm_session_solaris_auditor_report_user_accredited;
auditor_class->report_login = gdm_session_solaris_auditor_report_login;
auditor_class->report_login_failure = gdm_session_solaris_auditor_report_login_failure;
auditor_class->report_logout = gdm_session_solaris_auditor_report_logout;
}
static void
on_username_set (GdmSessionSolarisAuditor *auditor)
{
char *username;
struct passwd *passwd_entry = NULL;
g_object_get (G_OBJECT (auditor), "username", &username, NULL);
if (username != NULL) {
gdm_get_pwent_for_name (username, &passwd_entry);
}
if (passwd_entry != NULL) {
auditor->uid = passwd_entry->pw_uid;
auditor->gid = passwd_entry->pw_gid;
auditor->username = g_strdup (passwd_entry->pw_name);
} else {
g_free (auditor->username);
auditor->username = NULL;
auditor->uid = (uid_t) -1;
auditor->gid = (gid_t) -1;
}
g_free (username);
}
static void
gdm_session_solaris_auditor_init (GdmSessionSolarisAuditor *auditor)
{
g_signal_connect (G_OBJECT (auditor), "notify::username",
G_CALLBACK (on_username_set), NULL);
auditor->uid = (uid_t) -1;
auditor->gid = (gid_t) -1;
}
static void
gdm_session_solaris_auditor_finalize (GObject *object)
{
GdmSessionSolarisAuditor *solaris_auditor;
GObjectClass *parent_class;
solaris_auditor = GDM_SESSION_SOLARIS_AUDITOR (object);
g_free (solaris_auditor->username);
solaris_auditor->username = NULL;
parent_class = G_OBJECT_CLASS (gdm_session_solaris_auditor_parent_class);
if (parent_class->finalize != NULL) {
parent_class->finalize (object);
}
}
GdmSessionAuditor *
gdm_session_solaris_auditor_new (const char *hostname,
const char *display_device)
{
GObject *auditor;
auditor = g_object_new (GDM_TYPE_SESSION_SOLARIS_AUDITOR,
"hostname", hostname,
"display-device", display_device,
NULL);
return GDM_SESSION_AUDITOR (auditor);
}

View file

@ -0,0 +1,42 @@
/* gdm-solaris-session-auditor.h - Object for solaris auditing of session login/logout
*
* Copyright (C) 2004, 2008 Sun Microsystems, Inc.
* Copyright (C) 2005, 2008 Red Hat, Inc.
*
* 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, 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.
*
* Written by: Brian A. Cameron <Brian.Cameron@sun.com>
* Gary Winiger <Gary.Winiger@sun.com>
* Ray Strode <rstrode@redhat.com>
* Steve Grubb <sgrubb@redhat.com>
*/
#ifndef GDM_SESSION_SOLARIS_AUDITOR_H
#define GDM_SESSION_SOLARIS_AUDITOR_H
#include <glib.h>
#include <glib-object.h>
#include "gdm-session-auditor.h"
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_SOLARIS_AUDITOR (gdm_session_solaris_auditor_get_type ())
G_DECLARE_FINAL_TYPE (GdmSessionSolarisAuditor, gdm_session_solaris_auditor, GDM, SESSION_SOLARIS_AUDITOR, GdmSessionAuditor)
GdmSessionAuditor *gdm_session_solaris_auditor_new (const char *hostname,
const char *display_device);
G_END_DECLS
#endif /* GDM_SESSION_SOLARIS_AUDITOR_H */

View file

@ -0,0 +1,57 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
* Copyright (C) 2012 Jasper St. Pierre <jstpierre@mecheye.net>
*
* 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, 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.
*/
#include "config.h"
#include <gio/gio.h>
#include "gdm-session-worker-common.h"
static const GDBusErrorEntry gdm_session_worker_error_entries[] = {
{ GDM_SESSION_WORKER_ERROR_GENERIC , "org.gnome.DisplayManager.SessionWorker.Error.Generic", },
{ GDM_SESSION_WORKER_ERROR_WITH_SESSION_COMMAND , "org.gnome.DisplayManager.SessionWorker.Error.WithSessionCommand" },
{ GDM_SESSION_WORKER_ERROR_FORKING , "org.gnome.DisplayManager.SessionWorker.Error.Forking" },
{ GDM_SESSION_WORKER_ERROR_OPENING_MESSAGE_PIPE , "org.gnome.DisplayManager.SessionWorker.Error.OpeningMessagePipe" },
{ GDM_SESSION_WORKER_ERROR_COMMUNICATING , "org.gnome.DisplayManager.SessionWorker.Error.Communicating" },
{ GDM_SESSION_WORKER_ERROR_WORKER_DIED , "org.gnome.DisplayManager.SessionWorker.Error.WorkerDied" },
{ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE , "org.gnome.DisplayManager.SessionWorker.Error.ServiceUnavailable" },
{ GDM_SESSION_WORKER_ERROR_AUTHENTICATING , "org.gnome.DisplayManager.SessionWorker.Error.Authenticating" },
{ GDM_SESSION_WORKER_ERROR_AUTHORIZING , "org.gnome.DisplayManager.SessionWorker.Error.Authorizing" },
{ GDM_SESSION_WORKER_ERROR_OPENING_LOG_FILE , "org.gnome.DisplayManager.SessionWorker.Error.OpeningLogFile" },
{ GDM_SESSION_WORKER_ERROR_OPENING_SESSION , "org.gnome.DisplayManager.SessionWorker.Error.OpeningSession" },
{ GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS , "org.gnome.DisplayManager.SessionWorker.Error.GivingCredentials" },
{ GDM_SESSION_WORKER_ERROR_WRONG_STATE , "org.gnome.DisplayManager.SessionWorker.Error.WrongState" },
{ GDM_SESSION_WORKER_ERROR_OUTSTANDING_REQUEST , "org.gnome.DisplayManager.SessionWorker.Error.OutstandingRequest" },
{ GDM_SESSION_WORKER_ERROR_IN_REAUTH_SESSION , "org.gnome.DisplayManager.SessionWorker.Error.InReauthSession" }
};
GQuark
gdm_session_worker_error_quark (void)
{
static volatile gsize error_quark = 0;
g_dbus_error_register_error_domain ("gdm-session-worker-error-quark",
&error_quark,
gdm_session_worker_error_entries,
G_N_ELEMENTS (gdm_session_worker_error_entries));
return (GQuark) error_quark;
}

View file

@ -0,0 +1,50 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
* Copyright (C) 2012 Jasper St. Pierre <jstpierre@mecheye.net>
*
* 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, 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.
*/
#ifndef __GDM_SESSION_WORKER_COMMON_H
#define __GDM_SESSION_WORKER_COMMON_H
#include <glib-object.h>
#define GDM_SESSION_WORKER_ERROR (gdm_session_worker_error_quark ())
GQuark gdm_session_worker_error_quark (void);
typedef enum _GdmSessionWorkerError {
GDM_SESSION_WORKER_ERROR_GENERIC = 0,
GDM_SESSION_WORKER_ERROR_WITH_SESSION_COMMAND,
GDM_SESSION_WORKER_ERROR_FORKING,
GDM_SESSION_WORKER_ERROR_OPENING_MESSAGE_PIPE,
GDM_SESSION_WORKER_ERROR_COMMUNICATING,
GDM_SESSION_WORKER_ERROR_WORKER_DIED,
GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
GDM_SESSION_WORKER_ERROR_TOO_MANY_RETRIES,
GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
GDM_SESSION_WORKER_ERROR_AUTHORIZING,
GDM_SESSION_WORKER_ERROR_OPENING_LOG_FILE,
GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
GDM_SESSION_WORKER_ERROR_WRONG_STATE,
GDM_SESSION_WORKER_ERROR_OUTSTANDING_REQUEST,
GDM_SESSION_WORKER_ERROR_IN_REAUTH_SESSION,
} GdmSessionWorkerError;
#endif /* GDM_SESSION_WORKER_COMMON_H */

View file

@ -0,0 +1,42 @@
/*** BEGIN file-header ***/
#include <glib-object.h>
/*** END file-header ***/
/*** BEGIN file-production ***/
#include "@filename@"
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
GType
@enum_name@_get_type (void)
{
static GType etype = 0;
if (G_UNLIKELY(etype == 0)) {
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
}
return etype;
}
/*** END value-tail ***/
/*** BEGIN file-tail ***/
/**/
/*** END file-tail ***/

View file

@ -0,0 +1,24 @@
/*** BEGIN file-header ***/
#ifndef GDM_SESSION_WORKER_ENUM_TYPES_H
#define GDM_SESSION_WORKER_ENUM_TYPES_H
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* GDM_SESSION_WORKER_ENUM_TYPES_H */
/*** END file-tail ***/

View file

@ -0,0 +1,556 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#include <systemd/sd-daemon.h>
#ifdef ENABLE_SYSTEMD_JOURNAL
#include <systemd/sd-journal.h>
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "gdm-common.h"
#include "gdm-session-worker-job.h"
extern char **environ;
struct _GdmSessionWorkerJob
{
GObject parent;
char *command;
GPid pid;
gboolean for_reauth;
guint child_watch_id;
char *server_address;
char **environment;
};
enum {
PROP_0,
PROP_SERVER_ADDRESS,
PROP_ENVIRONMENT,
PROP_FOR_REAUTH,
};
enum {
STARTED,
EXITED,
DIED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (GdmSessionWorkerJob, gdm_session_worker_job, G_TYPE_OBJECT)
static void
session_worker_job_setup_journal_fds (void)
{
#ifdef ENABLE_SYSTEMD_JOURNAL
if (sd_booted () > 0) {
const char *identifier = "gdm-session-worker";
int out, err;
out = sd_journal_stream_fd (identifier, LOG_INFO, FALSE);
if (out < 0)
return;
err = sd_journal_stream_fd (identifier, LOG_WARNING, FALSE);
if (err < 0) {
close (out);
return;
}
VE_IGNORE_EINTR (dup2 (out, 1));
VE_IGNORE_EINTR (dup2 (err, 2));
return;
}
#endif
return;
}
static void
session_worker_job_child_setup (GdmSessionWorkerJob *session_worker_job)
{
sigset_t mask;
session_worker_job_setup_journal_fds ();
/* Terminate the process when the parent dies */
#ifdef HAVE_SYS_PRCTL_H
prctl (PR_SET_PDEATHSIG, SIGTERM);
#endif
/*
* Reset signal mask to default since it was altered by the
* manager process
*/
sigemptyset (&mask);
sigprocmask (SIG_SETMASK, &mask, NULL);
}
static void
session_worker_job_child_watch (GPid pid,
int status,
GdmSessionWorkerJob *job)
{
g_debug ("GdmSessionWorkerJob: child (pid:%d) done (%s:%d)",
(int) pid,
WIFEXITED (status) ? "status"
: WIFSIGNALED (status) ? "signal"
: "unknown",
WIFEXITED (status) ? WEXITSTATUS (status)
: WIFSIGNALED (status) ? WTERMSIG (status)
: -1);
g_spawn_close_pid (job->pid);
job->pid = -1;
if (WIFEXITED (status)) {
int code = WEXITSTATUS (status);
g_signal_emit (job, signals [EXITED], 0, code);
} else if (WIFSIGNALED (status)) {
int num = WTERMSIG (status);
g_signal_emit (job, signals [DIED], 0, num);
}
}
static void
listify_hash (const char *key,
const char *value,
GPtrArray *env)
{
char *str;
if (value == NULL)
value = "";
str = g_strdup_printf ("%s=%s", key, value);
g_ptr_array_add (env, str);
}
static void
copy_environment_to_hash (GdmSessionWorkerJob *job,
GHashTable *hash)
{
g_auto(GStrv) environment = NULL;
gint i;
if (job->environment != NULL) {
environment = g_strdupv (job->environment);
} else {
environment = g_get_environ ();
}
for (i = 0; environment[i]; i++) {
g_auto(GStrv) parts = NULL;
parts = g_strsplit (environment[i], "=", 2);
if (parts[0] != NULL && parts[1] != NULL) {
g_hash_table_insert (hash, g_strdup (parts[0]), g_strdup (parts[1]));
}
}
}
static GPtrArray *
get_job_arguments (GdmSessionWorkerJob *job,
const char *name)
{
g_autoptr(GPtrArray) args = NULL;
g_autoptr(GError) error = NULL;
g_auto(GStrv) argv = NULL;
int i;
args = NULL;
if (!g_shell_parse_argv (job->command, NULL, &argv, &error)) {
g_warning ("Could not parse command: %s", error->message);
return NULL;
}
args = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (args, g_strdup (argv[0]));
g_ptr_array_add (args, g_strdup (name));
for (i = 1; argv[i] != NULL; i++) {
g_ptr_array_add (args, g_strdup (argv[i]));
}
g_ptr_array_add (args, NULL);
return g_steal_pointer (&args);
}
static GPtrArray *
get_job_environment (GdmSessionWorkerJob *job)
{
g_autoptr(GPtrArray) env = NULL;
g_autoptr(GHashTable) hash = NULL;
env = g_ptr_array_new_with_free_func (g_free);
/* create a hash table of current environment, then update keys has necessary */
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
copy_environment_to_hash (job, hash);
g_hash_table_insert (hash, g_strdup ("GDM_SESSION_DBUS_ADDRESS"), g_strdup (job->server_address));
if (job->for_reauth) {
g_hash_table_insert (hash, g_strdup ("GDM_SESSION_FOR_REAUTH"), g_strdup ("1"));
}
g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
g_ptr_array_add (env, NULL);
return g_steal_pointer (&env);
}
static gboolean
gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job,
const char *name)
{
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) args = NULL;
g_autoptr(GPtrArray) env = NULL;
gboolean ret;
g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s %s",
name != NULL? name : "", session_worker_job->command);
args = get_job_arguments (session_worker_job, name);
if (args == NULL) {
return FALSE;
}
env = get_job_environment (session_worker_job);
ret = g_spawn_async_with_pipes (NULL,
(char **) args->pdata,
(char **)env->pdata,
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_FILE_AND_ARGV_ZERO,
(GSpawnChildSetupFunc)session_worker_job_child_setup,
session_worker_job,
&session_worker_job->pid,
NULL,
NULL,
NULL,
&error);
if (! ret) {
g_warning ("Could not start command '%s': %s",
session_worker_job->command,
error->message);
} else {
g_debug ("GdmSessionWorkerJob: : SessionWorkerJob on pid %d", (int)session_worker_job->pid);
}
session_worker_job->child_watch_id = g_child_watch_add (session_worker_job->pid,
(GChildWatchFunc)session_worker_job_child_watch,
session_worker_job);
return ret;
}
/**
* gdm_session_worker_job_start:
* @disp: Pointer to a GdmDisplay structure
*
* Starts a local X session_worker_job. Handles retries and fatal errors properly.
*/
gboolean
gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job,
const char *name)
{
gboolean res;
g_return_val_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job), FALSE);
g_debug ("GdmSessionWorkerJob: Starting worker...");
res = gdm_session_worker_job_spawn (session_worker_job, name);
return res;
}
static void
handle_session_worker_job_death (GdmSessionWorkerJob *session_worker_job)
{
int exit_status;
g_debug ("GdmSessionWorkerJob: Waiting on process %d", session_worker_job->pid);
exit_status = gdm_wait_on_and_disown_pid (session_worker_job->pid, 5);
if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
g_debug ("GdmSessionWorkerJob: Wait on child process failed");
} else {
/* exited normally */
}
g_spawn_close_pid (session_worker_job->pid);
session_worker_job->pid = -1;
g_debug ("GdmSessionWorkerJob: SessionWorkerJob died");
}
void
gdm_session_worker_job_stop_now (GdmSessionWorkerJob *session_worker_job)
{
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
if (session_worker_job->pid <= 1) {
return;
}
/* remove watch source before we can wait on child */
g_clear_handle_id (&session_worker_job->child_watch_id, g_source_remove);
gdm_session_worker_job_stop (session_worker_job);
handle_session_worker_job_death (session_worker_job);
}
void
gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
{
int res;
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
if (session_worker_job->pid <= 1) {
return;
}
g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->pid);
res = gdm_signal_pid (session_worker_job->pid, SIGTERM);
if (res < 0) {
g_warning ("Unable to kill session worker process");
}
}
GPid
gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job)
{
g_return_val_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job), 0);
return session_worker_job->pid;
}
void
gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
const char *address)
{
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
g_free (session_worker_job->server_address);
session_worker_job->server_address = g_strdup (address);
}
void
gdm_session_worker_job_set_for_reauth (GdmSessionWorkerJob *session_worker_job,
gboolean for_reauth)
{
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
session_worker_job->for_reauth = for_reauth;
}
void
gdm_session_worker_job_set_environment (GdmSessionWorkerJob *session_worker_job,
const char * const *environment)
{
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
session_worker_job->environment = g_strdupv ((char **) environment);
}
static void
gdm_session_worker_job_finalize (GObject *object)
{
GdmSessionWorkerJob *session_worker_job;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (object));
session_worker_job = GDM_SESSION_WORKER_JOB (object);
gdm_session_worker_job_stop (session_worker_job);
g_free (session_worker_job->command);
g_free (session_worker_job->server_address);
G_OBJECT_CLASS (gdm_session_worker_job_parent_class)->finalize (object);
}
static void
gdm_session_worker_job_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmSessionWorkerJob *self;
self = GDM_SESSION_WORKER_JOB (object);
switch (prop_id) {
case PROP_SERVER_ADDRESS:
gdm_session_worker_job_set_server_address (self, g_value_get_string (value));
break;
case PROP_FOR_REAUTH:
gdm_session_worker_job_set_for_reauth (self, g_value_get_boolean (value));
break;
case PROP_ENVIRONMENT:
gdm_session_worker_job_set_environment (self, g_value_get_pointer (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_session_worker_job_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmSessionWorkerJob *self;
self = GDM_SESSION_WORKER_JOB (object);
switch (prop_id) {
case PROP_SERVER_ADDRESS:
g_value_set_string (value, self->server_address);
break;
case PROP_FOR_REAUTH:
g_value_set_boolean (value, self->for_reauth);
break;
case PROP_ENVIRONMENT:
g_value_set_pointer (value, self->environment);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_session_worker_job_init (GdmSessionWorkerJob *session_worker_job)
{
session_worker_job->pid = -1;
session_worker_job->command = g_strdup (LIBEXECDIR "/gdm-session-worker");
}
static void
gdm_session_worker_job_class_init (GdmSessionWorkerJobClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_session_worker_job_get_property;
object_class->set_property = gdm_session_worker_job_set_property;
object_class->finalize = gdm_session_worker_job_finalize;
g_object_class_install_property (object_class,
PROP_SERVER_ADDRESS,
g_param_spec_string ("server-address",
"server address",
"server address",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_FOR_REAUTH,
g_param_spec_boolean ("for-reauth",
"for reauth",
"for reauth",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_ENVIRONMENT,
g_param_spec_pointer ("environment",
"environment",
"environment",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
signals [STARTED] =
g_signal_new ("started",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
signals [EXITED] =
g_signal_new ("exited",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
signals [DIED] =
g_signal_new ("died",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
}
GdmSessionWorkerJob *
gdm_session_worker_job_new (void)
{
GObject *object;
object = g_object_new (GDM_TYPE_SESSION_WORKER_JOB,
NULL);
return GDM_SESSION_WORKER_JOB (object);
}

View file

@ -0,0 +1,48 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#ifndef __GDM_SESSION_WORKER_JOB_H
#define __GDM_SESSION_WORKER_JOB_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_WORKER_JOB (gdm_session_worker_job_get_type ())
G_DECLARE_FINAL_TYPE (GdmSessionWorkerJob, gdm_session_worker_job, GDM, SESSION_WORKER_JOB, GObject)
GdmSessionWorkerJob * gdm_session_worker_job_new (void);
void gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
const char *server_address);
void gdm_session_worker_job_set_for_reauth (GdmSessionWorkerJob *session_worker_job,
gboolean for_reauth);
void gdm_session_worker_job_set_environment (GdmSessionWorkerJob *session_worker_job,
const char * const *environment);
gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job,
const char *name);
void gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job);
void gdm_session_worker_job_stop_now (GdmSessionWorkerJob *session_worker_job);
GPid gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job);
G_END_DECLS
#endif /* __GDM_SESSION_WORKER_JOB_H */

3660
daemon/gdm-session-worker.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
*
* 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, 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.
*/
#ifndef __GDM_SESSION_WORKER_H
#define __GDM_SESSION_WORKER_H
#include <glib-object.h>
#include "gdm-session-worker-glue.h"
#include "gdm-session-worker-common.h"
#include "gdm-session-worker-enum-types.h"
G_BEGIN_DECLS
#define GDM_TYPE_SESSION_WORKER (gdm_session_worker_get_type ())
G_DECLARE_FINAL_TYPE (GdmSessionWorker, gdm_session_worker, GDM, SESSION_WORKER, GdmDBusWorkerSkeleton)
typedef enum {
GDM_SESSION_WORKER_STATE_NONE = 0,
GDM_SESSION_WORKER_STATE_SETUP_COMPLETE,
GDM_SESSION_WORKER_STATE_AUTHENTICATED,
GDM_SESSION_WORKER_STATE_AUTHORIZED,
GDM_SESSION_WORKER_STATE_ACCREDITED,
GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED,
GDM_SESSION_WORKER_STATE_SESSION_OPENED,
GDM_SESSION_WORKER_STATE_SESSION_STARTED
} GdmSessionWorkerState;
GdmSessionWorker * gdm_session_worker_new (const char *server_address,
gboolean is_for_reauth) G_GNUC_MALLOC;
G_END_DECLS
#endif /* GDM_SESSION_WORKER_H */

View file

@ -0,0 +1,94 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/Worker">
<interface name="org.gnome.DisplayManager.Worker">
<method name="Authenticate" />
<method name="Authorize" />
<method name="EstablishCredentials" />
<method name="Open">
<arg name="session_id" direction="out" type="s"/>
</method>
<method name="SetLanguageName">
<arg name="language" direction="in" type="s"/>
</method>
<method name="SetSessionName">
<arg name="session_name" direction="in" type="s" />
</method>
<method name="SetSessionDisplayMode">
<arg name="mode" direction="in" type="s"/>
</method>
<method name="SetEnvironmentVariable">
<arg name="name" direction="in" type="s"/>
<arg name="value" direction="in" type="s"/>
</method>
<method name="StartProgram">
<arg name="command" direction="in" type="s"/>
<arg name="child_pid" direction="out" type="i"/>
</method>
<method name="Initialize">
<arg name="details" direction="in" type="a{sv}"/>
</method>
<method name="Setup">
<arg name="service_name" direction="in" type="s"/>
<arg name="x11_display_name" direction="in" type="s"/>
<arg name="x11_authority_file" direction="in" type="s"/>
<arg name="display_device" direction="in" type="s"/>
<arg name="display_seat" direction="in" type="s"/>
<arg name="hostname" direction="in" type="s"/>
<arg name="display_is_local" direction="in" type="b"/>
<arg name="display_is_initial" direction="in" type="b"/>
</method>
<method name="SetupForUser">
<arg name="service_name" direction="in" type="s"/>
<arg name="user_name" direction="in" type="s"/>
<arg name="x11_display_name" direction="in" type="s"/>
<arg name="x11_authority_file" direction="in" type="s"/>
<arg name="display_device" direction="in" type="s"/>
<arg name="display_seat" direction="in" type="s"/>
<arg name="hostname" direction="in" type="s"/>
<arg name="display_is_local" direction="in" type="b"/>
<arg name="display_is_initial" direction="in" type="b"/>
</method>
<method name="SetupForProgram">
<arg name="service_name" direction="in" type="s"/>
<arg name="user_name" direction="in" type="s"/>
<arg name="x11_display_name" direction="in" type="s"/>
<arg name="x11_authority_file" direction="in" type="s"/>
<arg name="display_device" direction="in" type="s"/>
<arg name="display_seat" direction="in" type="s"/>
<arg name="hostname" direction="in" type="s"/>
<arg name="display_is_local" direction="in" type="b"/>
<arg name="display_is_initial" direction="in" type="b"/>
<arg name="log_file" direction="in" type="s"/>
</method>
<method name="StartReauthentication">
<arg name="pid_of_caller" direction="in" type="i"/>
<arg name="uid_of_caller" direction="in" type="i"/>
<arg name="address" direction="out" type="s"/>
</method>
<signal name="SessionExited">
<arg name="service_name" type="s" />
<!-- This is a combination of exit code and exit
signal. Use macros in sys/wait.h to handle it. -->
<arg name="status" type="i" />
</signal>
<signal name="SavedLanguageNameRead">
<arg name="language_name" type="s"/>
</signal>
<signal name="SavedSessionNameRead">
<arg name="session_name" type="s"/>
</signal>
<signal name="SavedSessionTypeRead">
<arg name="session_type" type="s"/>
</signal>
<signal name="UsernameChanged">
<arg name="new_username" type="s"/>
</signal>
<signal name="Reauthenticated">
<arg name="service_name" type="s"/>
<arg name="pid_of_caller" type="i"/>
</signal>
<signal name="CancelPendingQuery">
</signal>
</interface>
</node>

4505
daemon/gdm-session.c Normal file

File diff suppressed because it is too large Load diff

139
daemon/gdm-session.h Normal file
View file

@ -0,0 +1,139 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
*
* 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, 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.
*/
#ifndef __GDM_SESSION_H
#define __GDM_SESSION_H
#include <glib-object.h>
#include <gio/gio.h>
#include <sys/types.h>
G_BEGIN_DECLS
#define GDM_TYPE_SESSION (gdm_session_get_type ())
G_DECLARE_FINAL_TYPE (GdmSession, gdm_session, GDM, SESSION, GObject)
typedef enum
{
GDM_SESSION_VERIFICATION_MODE_LOGIN,
GDM_SESSION_VERIFICATION_MODE_CHOOSER,
GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE
} GdmSessionVerificationMode;
typedef enum {
/* We reuse the existing display server, e.g. X server
* in "classic" mode from the greeter for the first seat. */
GDM_SESSION_DISPLAY_MODE_REUSE_VT,
/* Doesn't know anything about VTs. Tries to set DRM
* master and will throw a tantrum if something bad
* happens. e.g. weston-launch or mutter-launch. */
GDM_SESSION_DISPLAY_MODE_NEW_VT,
/* Uses logind sessions to manage itself. We need to set an
* XDG_VTNR and it will switch to the correct VT on startup.
* e.g. mutter-wayland with logind integration, X server with
* logind integration. */
GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED,
} GdmSessionDisplayMode;
GdmSessionDisplayMode gdm_session_display_mode_from_string (const char *str);
const char * gdm_session_display_mode_to_string (GdmSessionDisplayMode mode);
GdmSession *gdm_session_new (GdmSessionVerificationMode verification_mode,
uid_t allowed_user,
const char *display_name,
const char *display_hostname,
const char *display_device,
const char *display_seat_id,
const char *display_x11_authority_file,
gboolean display_is_local,
const char * const *environment);
uid_t gdm_session_get_allowed_user (GdmSession *session);
void gdm_session_start_reauthentication (GdmSession *session,
GPid pid_of_caller,
uid_t uid_of_caller);
const char *gdm_session_get_server_address (GdmSession *session);
const char *gdm_session_get_username (GdmSession *session);
const char *gdm_session_get_display_device (GdmSession *session);
const char *gdm_session_get_display_seat_id (GdmSession *session);
const char *gdm_session_get_session_id (GdmSession *session);
gboolean gdm_session_bypasses_xsession (GdmSession *session);
gboolean gdm_session_session_registers (GdmSession *session);
GdmSessionDisplayMode gdm_session_get_display_mode (GdmSession *session);
gboolean gdm_session_start_conversation (GdmSession *session,
const char *service_name);
void gdm_session_stop_conversation (GdmSession *session,
const char *service_name);
const char *gdm_session_get_conversation_session_id (GdmSession *session,
const char *service_name);
void gdm_session_setup (GdmSession *session,
const char *service_name);
void gdm_session_setup_for_user (GdmSession *session,
const char *service_name,
const char *username);
void gdm_session_setup_for_program (GdmSession *session,
const char *service_name,
const char *username,
const char *log_file);
void gdm_session_set_environment_variable (GdmSession *session,
const char *key,
const char *value);
void gdm_session_send_environment (GdmSession *self,
const char *service_name);
void gdm_session_reset (GdmSession *session);
void gdm_session_cancel (GdmSession *session);
void gdm_session_authenticate (GdmSession *session,
const char *service_name);
void gdm_session_authorize (GdmSession *session,
const char *service_name);
void gdm_session_accredit (GdmSession *session,
const char *service_name);
void gdm_session_open_session (GdmSession *session,
const char *service_name);
void gdm_session_start_session (GdmSession *session,
const char *service_name);
void gdm_session_close (GdmSession *session);
void gdm_session_answer_query (GdmSession *session,
const char *service_name,
const char *text);
void gdm_session_report_error (GdmSession *session,
const char *service_name,
GDBusError code,
const char *message);
void gdm_session_select_program (GdmSession *session,
const char *command_line);
void gdm_session_select_session (GdmSession *session,
const char *session_name);
void gdm_session_select_user (GdmSession *session,
const char *username);
void gdm_session_set_timed_login_details (GdmSession *session,
const char *username,
int delay);
gboolean gdm_session_client_is_connected (GdmSession *session);
gboolean gdm_session_is_running (GdmSession *session);
gboolean gdm_session_is_frozen (GdmSession *session);
GPid gdm_session_get_pid (GdmSession *session);
G_END_DECLS
#endif /* GDM_SESSION_H */

173
daemon/gdm-session.xml Normal file
View file

@ -0,0 +1,173 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/Session">
<!-- methods are called by the session worker,
signals are emitted by the main daemon -->
<interface name="org.gnome.DisplayManager.WorkerManager">
<method name="Hello" />
<method name="InfoQuery">
<arg name="service_name" direction="in" type="s"/>
<arg name="query" direction="in" type="s"/>
<arg name="answer" direction="out" type="s"/>
</method>
<method name="SecretInfoQuery">
<arg name="service_name" direction="in" type="s"/>
<arg name="query" direction="in" type="s"/>
<arg name="answer" direction="out" type="s"/>
</method>
<method name="Info">
<arg name="service_name" direction="in" type="s"/>
<arg name="info" direction="in" type="s"/>
</method>
<method name="Problem">
<arg name="service_name" direction="in" type="s"/>
<arg name="problem" direction="in" type="s"/>
</method>
<method name="ChoiceListQuery">
<arg name="service_name" direction="in" type="s"/>
<arg name="prompt_message" direction="in" type="s"/>
<arg name="query" direction="in" type="a{ss}"/>
<arg name="answer" direction="out" type="s"/>
</method>
<method name="CustomJSONRequest">
<annotation name="org.gtk.GDBus.C.Name" value="CustomJsonRequest" />
<arg name="service_name" direction="in" type="s"/>
<arg name="protocol" direction="in" type="s"/>
<arg name="version" direction="in" type="u"/>
<arg name="request" direction="in" type="s"/>
<arg name="response" direction="out" type="s"/>
</method>
</interface>
<interface name="org.gnome.DisplayManager.UserVerifier">
<method name="EnableExtensions">
<arg name="extensions" direction="in" type="as"/>
</method>
<method name="BeginVerification">
<arg name="service_name" direction="in" type="s"/>
</method>
<method name="BeginVerificationForUser">
<arg name="service_name" direction="in" type="s"/>
<arg name="username" direction="in" type="s"/>
</method>
<method name="AnswerQuery">
<arg name="service_name" direction="in" type="s"/>
<arg name="answer" direction="in" type="s"/>
</method>
<method name="Cancel">
</method>
<signal name="ConversationStarted">
<arg name="service_name" type="s"/>
</signal>
<signal name="ConversationStopped">
<arg name="service_name" type="s"/>
</signal>
<signal name="ReauthenticationStarted">
<arg name="pid_of_caller" type="i"/>
</signal>
<signal name="Info">
<arg name="service_name" type="s"/>
<arg name="info" type="s"/>
</signal>
<signal name="Problem">
<arg name="service_name" type="s"/>
<arg name="problem" type="s"/>
</signal>
<signal name="InfoQuery">
<arg name="service_name" type="s"/>
<arg name="query" type="s"/>
</signal>
<signal name="SecretInfoQuery">
<arg name="service_name" type="s"/>
<arg name="query" type="s"/>
</signal>
<signal name="Reset">
</signal>
<signal name="ServiceUnavailable">
<arg name="service_name" type="s"/>
<arg name="message" type="s"/>
</signal>
<signal name="VerificationFailed">
<arg name="service_name" type="s"/>
</signal>
<signal name="VerificationComplete">
<arg name="service_name" type="s"/>
</signal>
</interface>
<interface name="org.gnome.DisplayManager.UserVerifier.ChoiceList">
<method name="SelectChoice">
<arg name="service_name" direction="in" type="s"/>
<arg name="choice" direction="in" type="s"/>
</method>
<signal name="ChoiceQuery">
<arg name="service_name" type="s"/>
<arg name="prompt_message" type="s"/>
<arg name="list" type="a{ss}"/>
</signal>
</interface>
<interface name="org.gnome.DisplayManager.UserVerifier.CustomJSON">
<method name="Reply">
<arg name="service_name" direction="in" type="s"/>
<arg name="reply" direction="in" type="s"/>
</method>
<method name="ReportError">
<arg name="service_name" direction="in" type="s"/>
<arg name="error" direction="in" type="s"/>
</method>
<signal name="Request">
<arg name="service_name" type="s"/>
<arg name="protocol" type="s"/>
<arg name="version" type="u"/>
<arg name="request" type="s"/>
</signal>
</interface>
<interface name="org.gnome.DisplayManager.Greeter">
<method name="SelectSession">
<arg name="session" direction="in" type="s"/>
</method>
<method name="SelectUser">
<arg name="username" direction="in" type="s"/>
</method>
<method name="BeginAutoLogin">
<arg name="username" direction="in" type="s"/>
</method>
<method name="GetTimedLoginDetails">
<arg name="enabled" direction="out" type="b"/>
<arg name="username" direction="out" type="s"/>
<arg name="delay" direction="out" type="i"/>
</method>
<method name="StartSessionWhenReady">
<arg name="service_name" direction="in" type="s"/>
<arg name="should_start_session" direction="in" type="b"/>
</method>
<method name="StopConflictingSession">
</method>
<signal name="SelectedUserChanged">
<arg name="username" type="s"/>
</signal>
<signal name="DefaultLanguageNameChanged">
<arg name="language_name" type="s"/>
</signal>
<signal name="DefaultSessionNameChanged">
<arg name="session_name" type="s"/>
</signal>
<signal name="TimedLoginRequested">
<arg name="username" type="s"/>
<arg name="delay" type="i"/>
</signal>
<signal name="SessionOpened">
<arg name="service_name" type="s"/>
<arg name="session_id" type="s"/>
</signal>
<signal name="Reauthenticated">
<arg name="service_name" type="s"/>
</signal>
</interface>
<interface name="org.gnome.DisplayManager.RemoteGreeter">
<method name="Disconnect" />
</interface>
<interface name="org.gnome.DisplayManager.Chooser">
<method name="SelectHostname">
<arg name="hostname" direction="in" type="s"/>
</method>
<method name="Disconnect" />
</interface>
</node>

View file

@ -0,0 +1,620 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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, 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.
*/
#include "config.h"
#include <locale.h>
#include <sysexits.h>
#include "gdm-common.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-log.h"
#include "gdm-manager-glue.h"
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-unix.h>
#include <glib.h>
#include <gio/gunixinputstream.h>
#define BUS_ADDRESS_FILENO (STDERR_FILENO + 1)
typedef struct
{
GdmSettings *settings;
GCancellable *cancellable;
GSubprocess *bus_subprocess;
GDBusConnection *bus_connection;
GdmDBusManager *display_manager_proxy;
char *bus_address;
char **environment;
GSubprocess *session_subprocess;
char *session_command;
int session_exit_status;
guint register_session_id;
GMainLoop *main_loop;
guint32 debug_enabled : 1;
} State;
static void
on_bus_finished (GSubprocess *subprocess,
GAsyncResult *result,
State *state)
{
gboolean cancelled;
cancelled = !g_subprocess_wait_finish (subprocess, result, NULL);
if (cancelled) {
goto out;
}
if (g_subprocess_get_if_exited (subprocess)) {
int exit_status;
exit_status = g_subprocess_get_exit_status (subprocess);
g_debug ("message bus exited with status %d", exit_status);
} else {
int signal_number;
signal_number = g_subprocess_get_term_sig (subprocess);
g_debug ("message bus was killed with status %d", signal_number);
}
g_clear_object (&state->bus_subprocess);
out:
g_main_loop_quit (state->main_loop);
}
static gboolean
spawn_bus (State *state,
GCancellable *cancellable)
{
GDBusConnection *bus_connection = NULL;
GPtrArray *arguments = NULL;
GSubprocessLauncher *launcher = NULL;
GSubprocess *subprocess = NULL;
GInputStream *input_stream = NULL;
GDataInputStream *data_stream = NULL;
GError *error = NULL;
char *bus_address_fd_string = NULL;
char *bus_address = NULL;
gsize bus_address_size;
gboolean is_running = FALSE;
int ret;
int pipe_fds[2];
g_debug ("Running session message bus");
bus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
cancellable,
NULL);
if (bus_connection != NULL) {
g_debug ("session message bus already running, not starting another one");
state->bus_connection = bus_connection;
return TRUE;
}
ret = g_unix_open_pipe (pipe_fds, FD_CLOEXEC, &error);
if (!ret) {
g_debug ("could not open pipe: %s", error->message);
goto out;
}
arguments = g_ptr_array_new ();
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
g_subprocess_launcher_take_fd (launcher, pipe_fds[1], BUS_ADDRESS_FILENO);
bus_address_fd_string = g_strdup_printf ("%d", BUS_ADDRESS_FILENO);
g_ptr_array_add (arguments, "dbus-daemon");
g_ptr_array_add (arguments, "--print-address");
g_ptr_array_add (arguments, bus_address_fd_string);
g_ptr_array_add (arguments, "--session");
g_ptr_array_add (arguments, NULL);
subprocess = g_subprocess_launcher_spawnv (launcher,
(const char * const *) arguments->pdata,
&error);
g_free (bus_address_fd_string);
g_clear_object (&launcher);
g_ptr_array_free (arguments, TRUE);
if (subprocess == NULL) {
g_debug ("could not start dbus-daemon: %s", error->message);
goto out;
}
input_stream = g_unix_input_stream_new (pipe_fds[0], TRUE);
data_stream = g_data_input_stream_new (input_stream);
g_clear_object (&input_stream);
bus_address = g_data_input_stream_read_line (data_stream,
&bus_address_size,
cancellable,
&error);
if (error != NULL) {
g_debug ("could not read address from session message bus: %s", error->message);
goto out;
}
if (bus_address == NULL) {
g_debug ("session message bus did not write address");
goto out;
}
state->bus_address = bus_address;
state->bus_subprocess = g_object_ref (subprocess);
g_subprocess_wait_async (state->bus_subprocess,
cancellable,
(GAsyncReadyCallback)
on_bus_finished,
state);
bus_connection = g_dbus_connection_new_for_address_sync (state->bus_address,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
NULL,
cancellable,
&error);
if (bus_connection == NULL) {
g_debug ("could not open connection to session bus: %s",
error->message);
goto out;
}
state->bus_connection = bus_connection;
is_running = TRUE;
out:
g_clear_object (&data_stream);
g_clear_object (&subprocess);
g_clear_object (&launcher);
g_clear_error (&error);
return is_running;
}
static gboolean
import_environment (State *state,
GCancellable *cancellable)
{
g_autoptr(GVariant) reply = NULL;
g_autoptr(GVariant) environment_variant = NULL;
g_autoptr(GError) error = NULL;
reply = g_dbus_connection_call_sync (state->bus_connection,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new ("(ss)",
"org.freedesktop.systemd1.Manager",
"Environment"),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, cancellable, &error);
if (reply == NULL) {
g_debug ("could not fetch environment: %s", error->message);
return FALSE;
}
g_variant_get (reply, "(v)", &environment_variant);
state->environment = g_variant_dup_strv (environment_variant, NULL);
return TRUE;
}
static void
on_session_finished (GSubprocess *subprocess,
GAsyncResult *result,
State *state)
{
gboolean cancelled;
cancelled = !g_subprocess_wait_finish (subprocess, result, NULL);
if (cancelled) {
goto out;
}
if (g_subprocess_get_if_exited (subprocess)) {
int exit_status;
exit_status = g_subprocess_get_exit_status (subprocess);
g_debug ("session exited with status %d", exit_status);
state->session_exit_status = exit_status;
} else {
int signal_number;
signal_number = g_subprocess_get_term_sig (subprocess);
g_debug ("session was killed with status %d", signal_number);
}
g_clear_object (&state->session_subprocess);
out:
g_main_loop_quit (state->main_loop);
}
static gboolean
spawn_session (State *state,
GCancellable *cancellable)
{
GSubprocessLauncher *launcher = NULL;
GSubprocess *subprocess = NULL;
GError *error = NULL;
gboolean is_running = FALSE;
int ret;
char **argv = NULL;
static const char *session_variables[] = { "DISPLAY",
"XAUTHORITY",
"WAYLAND_DISPLAY",
"WAYLAND_SOCKET",
"GNOME_SHELL_SESSION_MODE",
NULL };
/* The environment variables listed below are those we have set (or
* received from our own execution environment) only as a fallback to
* make things work, as opposed to a information directly pertaining to
* the session about to be started. Variables listed here will not
* overwrite the existing environment (possibly) imported from the
* systemd --user instance.
* As an example: We need a PATH for some of the launched subprocesses
* to work, but if the user (or the distributor) has customized the PATH
* via one of systemds user-environment-generators, that version should
* be preferred. */
static const char *fallback_variables[] = { "PATH", NULL };
g_debug ("Running wayland session");
ret = g_shell_parse_argv (state->session_command,
NULL,
&argv,
&error);
if (!ret) {
g_debug ("could not parse session arguments: %s", error->message);
goto out;
}
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
if (state->environment != NULL) {
size_t i;
for (i = 0; state->environment[i] != NULL; i++) {
g_auto(GStrv) environment_entry = NULL;
if (state->environment[i][0] == '\0') {
continue;
}
environment_entry = g_strsplit (state->environment[i], "=", 2);
if (environment_entry[0] == NULL || environment_entry[1] == NULL) {
continue;
}
/* Merge the environment block imported from systemd --user with the
* environment we have set for ourselves (and thus pass on to the
* launcher process). Variables we have set have precedence, as to not
* import stale data from prior user sessions, with the exception of
* those listed in fallback_variables. See the comment there for more
* explanations. */
g_subprocess_launcher_setenv (launcher,
environment_entry[0],
environment_entry[1],
g_strv_contains (fallback_variables, environment_entry[0]));
}
/* Don't allow session specific environment variables from earlier sessions to
* leak through */
for (i = 0; session_variables[i] != NULL; i++) {
if (g_getenv (session_variables[i]) == NULL) {
g_subprocess_launcher_unsetenv (launcher, session_variables[i]);
}
}
}
if (state->bus_address != NULL) {
g_subprocess_launcher_setenv (launcher, "DBUS_SESSION_BUS_ADDRESS", state->bus_address, TRUE);
}
subprocess = g_subprocess_launcher_spawnv (launcher,
(const char * const *) argv,
&error);
g_strfreev (argv);
if (subprocess == NULL) {
g_debug ("could not start session: %s", error->message);
goto out;
}
state->session_subprocess = g_object_ref (subprocess);
g_subprocess_wait_async (state->session_subprocess,
cancellable,
(GAsyncReadyCallback)
on_session_finished,
state);
is_running = TRUE;
out:
g_clear_object (&subprocess);
return is_running;
}
static void
signal_subprocesses (State *state)
{
if (state->session_subprocess != NULL) {
g_subprocess_send_signal (state->session_subprocess, SIGTERM);
}
if (state->bus_subprocess != NULL) {
g_subprocess_send_signal (state->bus_subprocess, SIGTERM);
}
}
static void
wait_on_subprocesses (State *state)
{
if (state->bus_subprocess != NULL) {
g_subprocess_wait (state->bus_subprocess, NULL, NULL);
}
if (state->session_subprocess != NULL) {
g_subprocess_wait (state->session_subprocess, NULL, NULL);
}
}
static gboolean
register_display (State *state,
GCancellable *cancellable)
{
GError *error = NULL;
gboolean registered = FALSE;
GVariantBuilder details;
g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
g_variant_builder_add (&details, "{ss}", "session-type", "wayland");
registered = gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy,
g_variant_builder_end (&details),
cancellable,
&error);
if (error != NULL) {
g_debug ("Could not register display: %s", error->message);
g_error_free (error);
}
return registered;
}
static void
init_state (State **state)
{
static State state_allocation;
*state = &state_allocation;
}
static void
clear_state (State **out_state)
{
State *state = *out_state;
g_clear_object (&state->cancellable);
g_clear_object (&state->bus_connection);
g_clear_object (&state->session_subprocess);
g_clear_pointer (&state->environment, g_strfreev);
g_clear_pointer (&state->main_loop, g_main_loop_unref);
g_clear_handle_id (&state->register_session_id, g_source_remove);
*out_state = NULL;
}
static gboolean
on_sigterm (State *state)
{
g_cancellable_cancel (state->cancellable);
if (g_main_loop_is_running (state->main_loop)) {
g_main_loop_quit (state->main_loop);
}
return G_SOURCE_CONTINUE;
}
static gboolean
register_session_timeout_cb (gpointer user_data)
{
State *state;
GError *error = NULL;
state = (State *) user_data;
gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy,
g_variant_new ("a{sv}", NULL),
state->cancellable,
&error);
if (error != NULL) {
g_warning ("Could not register session: %s", error->message);
g_error_free (error);
}
return G_SOURCE_REMOVE;
}
static gboolean
connect_to_display_manager (State *state)
{
g_autoptr (GError) error = NULL;
state->display_manager_proxy = gdm_dbus_manager_proxy_new_for_bus_sync (
G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
"org.gnome.DisplayManager",
"/org/gnome/DisplayManager/Manager",
state->cancellable,
&error);
if (state->display_manager_proxy == NULL) {
g_printerr ("gdm-wayland-session: could not contact display manager: %s\n",
error->message);
return FALSE;
}
return TRUE;
}
int
main (int argc,
char **argv)
{
State *state = NULL;
GOptionContext *context = NULL;
static char **args = NULL;
gboolean debug = FALSE;
gboolean ret;
int exit_status = EX_OK;
static gboolean register_session = FALSE;
static GOptionEntry entries [] = {
{ "register-session", 0, 0, G_OPTION_ARG_NONE, &register_session, "Register session after a delay", NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
context = g_option_context_new (_("GNOME Display Manager Wayland Session Launcher"));
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
if (args == NULL || args[0] == NULL || args[1] != NULL) {
g_warning ("gdm-wayland-session takes one argument (the session)");
exit_status = EX_USAGE;
goto out;
}
init_state (&state);
state->session_command = args[0];
state->settings = gdm_settings_new ();
ret = gdm_settings_direct_init (state->settings, DATADIR "/gdm/gdm.schemas", "/");
if (!ret) {
g_printerr ("Unable to initialize settings\n");
exit_status = EX_DATAERR;
goto out;
}
gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
state->debug_enabled = debug;
gdm_log_set_debug (debug);
state->main_loop = g_main_loop_new (NULL, FALSE);
state->cancellable = g_cancellable_new ();
g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
ret = spawn_bus (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session message bus\n");
exit_status = EX_SOFTWARE;
goto out;
}
import_environment (state, state->cancellable);
ret = spawn_session (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session\n");
exit_status = EX_SOFTWARE;
goto out;
}
if (!connect_to_display_manager (state))
goto out;
ret = register_display (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to register display with display manager\n");
exit_status = EX_SOFTWARE;
goto out;
}
if (register_session) {
g_debug ("gdm-wayland-session: Will register session in %d seconds", REGISTER_SESSION_TIMEOUT);
state->register_session_id = g_timeout_add_seconds (REGISTER_SESSION_TIMEOUT,
register_session_timeout_cb,
state);
} else {
g_debug ("gdm-wayland-session: Session will register itself");
}
g_main_loop_run (state->main_loop);
/* Only use exit status of session if we're here because it exit */
if (state->session_subprocess == NULL) {
exit_status = state->session_exit_status;
}
out:
if (state != NULL) {
signal_subprocesses (state);
wait_on_subprocesses (state);
clear_state (&state);
}
return exit_status;
}

1000
daemon/gdm-x-session.c Normal file

File diff suppressed because it is too large Load diff

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