diff options
Diffstat (limited to 'src/VBox/Additions/linux')
47 files changed, 7242 insertions, 1315 deletions
diff --git a/src/VBox/Additions/linux/Makefile b/src/VBox/Additions/linux/Makefile index c5beef41..2154b24f 100644 --- a/src/VBox/Additions/linux/Makefile +++ b/src/VBox/Additions/linux/Makefile @@ -4,7 +4,7 @@ # # -# Copyright (C) 2009-2010 Oracle Corporation +# Copyright (C) 2009-2012 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/Makefile.kmk b/src/VBox/Additions/linux/Makefile.kmk index 28f77ffa..1fd3c814 100644 --- a/src/VBox/Additions/linux/Makefile.kmk +++ b/src/VBox/Additions/linux/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2006-2012 Oracle Corporation +# Copyright (C) 2006-2013 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -23,6 +23,9 @@ include $(KBUILD_PATH)/subheader.kmk # include $(PATH_SUB_CURRENT)/sharedfolders/Makefile.kmk include $(PATH_SUB_CURRENT)/drm/Makefile.kmk +ifdef VBOX_WITH_LIGHTDM_GREETER + include $(PATH_SUB_CURRENT)/lightdm-greeter/Makefile.kmk +endif # # Globals @@ -84,10 +87,10 @@ VBOX_LNX_ADD_INST_DEP_ON_MAKEFILE := $(MAKEFILE_CURRENT) # Targets # VBOX_SELINUX_CMPLD := $(PATH_SUB_CURRENT)/selinux-fedora/vbox_x11.pp -VBOX_LNX_ADD_ARCHIVE.x86 := $(PATH_OUT_BASE)/linux.x86/$(KBUILD_TYPE)/bin/additions/VBoxGuestAdditions-x86-r$(VBOX_SVN_REV).tar.bz2 -VBOX_LNX_ADD_ARCHIVE.amd64 := $(PATH_OUT_BASE)/linux.amd64/$(KBUILD_TYPE)/bin/additions/VBoxGuestAdditions-amd64-r$(VBOX_SVN_REV).tar.bz2 +VBOX_LNX_ADD_ARCHIVE.x86 := $(PATH_OUT_BASE)/linux.x86/$(KBUILD_TYPE)/bin/additions/VBoxGuestAdditions-x86.tar.bz2 +VBOX_LNX_ADD_ARCHIVE.amd64 := $(PATH_OUT_BASE)/linux.amd64/$(KBUILD_TYPE)/bin/additions/VBoxGuestAdditions-amd64.tar.bz2 ifndef VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE - VBOX_LNX_ADD_ARCHIVES := $(PATH_STAGE_BIN)/additions/VBoxGuestAdditions-$(KBUILD_TARGET_ARCH)-r$(VBOX_SVN_REV).tar.bz2 + VBOX_LNX_ADD_ARCHIVES := $(PATH_STAGE_BIN)/additions/VBoxGuestAdditions-$(KBUILD_TARGET_ARCH).tar.bz2 else VBOX_LNX_ADD_ARCHIVES := \ $(VBOX_LNX_ADD_ARCHIVE.x86) \ @@ -122,7 +125,8 @@ VBOX_ADD_BIN.linux += \ VBoxClient-all VBOX_ADD_STRIP_SBIN += \ - VBoxService + VBoxService \ + $(if $(VBOX_WITH_LIGHTDM_GREETER),vbox-greeter) VBOX_ADD_STRIP_LIB += \ VBoxOGLarrayspu.so \ @@ -140,19 +144,7 @@ VBOX_ADD_STRIP_MOD.linux = \ vboxmouse_drv_14.so \ vboxmouse_drv_15.so \ vboxmouse_drv_16.so \ - vboxvideo_drv_70.so \ - vboxvideo_drv_71.so \ - vboxvideo_drv_13.so \ - vboxvideo_drv_14.so \ - vboxvideo_drv_15.so \ - vboxvideo_drv_16.so \ - vboxvideo_drv_17.so \ - vboxvideo_drv_18.so \ - vboxvideo_drv_19.so \ - vboxvideo_drv_110.so \ - vboxvideo_drv_111.so \ - vboxvideo_drv_112.so \ - vboxvideo_drv_113.so \ + $(addsuffix .so,$(filter-out %_32,$(filter vboxvideo_drv_%,$(DLLS)))) \ $(if $(VBOX_WITH_PAM),pam_vbox.so,) \ mount.vboxsf @@ -208,6 +200,11 @@ VBOX_LNX_ADD_DBG_FILES := \ $(addprefix $(VBOX_LNX_ADD_DBG_LIB_DIR),$(VBOX_LNX_ADD_STRIP_LIB)) \ $(addprefix $(VBOX_LNX_ADD_DBG_MOD_DIR),$(VBOX_LNX_ADD_STRIP_MOD)) +ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING +VBOX_LNX_ADD_INST_FILES += \ + $(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),vbox-greeter) +endif + # Cleanup of the the installer directory files OTHER_CLEAN += $(VBOX_LNX_ADD_INST_FILES) $(VBOX_LNX_ADD_DBG_FILES) @@ -242,7 +239,8 @@ $(addprefix $(VBOX_LNX_ADD_INST_BIN_DIR),$(VBOX_LNX_ADD_STRIP_BIN)): \ $(QUIET)objcopy --add-gnu-debuglink=$@ $@ # pattern rule for stripping and copying the VBOX_LNX_ADD_STRIP_SBIN files to the installation directory -$(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),$(VBOX_LNX_ADD_STRIP_SBIN)): \ +$(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),\ + $(filter-out vbox-greeter,$(VBOX_LNX_ADD_STRIP_SBIN))): \ $(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(PATH_STAGE_BIN)/additions/% \ $(VBOX_LNX_ADD_DBG_SBIN_DIR)% \ | $$(dir $$@) @@ -250,6 +248,13 @@ $(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),$(VBOX_LNX_ADD_STRIP_SBIN)): \ $(QUIET)$(INSTALL) -m 0755 $(if $(VBOX_DO_STRIP),-s,) $< $@ $(QUIET)objcopy --add-gnu-debuglink=$@ $@ +# pattern rule for stripping and copying vbox-greeter to the installation directory +$(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),vbox-greeter): \ + $(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(subst linux,linux2,$(PATH_STAGE_BIN))/additions/% \ + | $$(dir $$@) + $(call MSG_INST_FILE,$<,$@) + $(QUIET)$(INSTALL) -m 0755 $< $@ + # pattern rule for stripping and copying the VBOX_LNX_ADD_STRIP_LIB files to the installation directory $(addprefix $(VBOX_LNX_ADD_INST_LIB_DIR),$(VBOX_LNX_ADD_STRIP_LIB)): \ $(VBOX_LNX_ADD_INST_LIB_DIR)% : $(PATH_STAGE_BIN)/additions/% \ @@ -320,7 +325,6 @@ $(addprefix $(VBOX_LNX_ADD_INST_MOD_DIR),$(VBOX_LNX_ADD_INIT)): \ $(QUIET)$(RM) -Rf $@ $(QUIET)$(CP) -RPf -- $< $@ - INSTALLS += GuestDrivers-src GuestDrivers-src_INST = $(INST_ADDITIONS)src/ GuestDrivers-src_MODE = a+r,u+w @@ -341,6 +345,7 @@ lnx_add_inst-noexec_INSTTYPE = stage lnx_add_inst-noexec_SOURCES = \ $(VBOX_REL_X11_ADD_INST)vboxclient.desktop \ $(VBOX_REL_X11_ADD_INST)vboxvideo.ids \ + $(if $(VBOX_WITH_LIGHTDM_GREETER_PACKING),lightdm-greeter/vbox-greeter.desktop,) \ selinux-fedora/vbox_x11.pp \ selinux-fedora/vbox_accel.pp @@ -365,8 +370,12 @@ LnxAdd-scripts_EXEC_SOURCES = \ $(VBOX_REL_LNX_INST_SRC)routines.sh \ $(VBOX_REL_LNX_ADD_INST)vboxadd.sh=>vboxadd \ $(VBOX_REL_LNX_ADD_INST)vboxadd-service.sh=>vboxadd-service \ - $(VBOX_REL_LNX_ADD_INST)vboxadd-x11.sh=>vboxadd-x11 \ + $(VBOX_REL_LNX_ADD_INST)vboxadd-x11.sh=>vboxadd-x11 +ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING + LnxAdd-scripts_EXEC_SOURCES += \ + $(VBOX_REL_LNX_ADD_INST)module-autologon.sh=>installer/module-autologon +endif # # VBoxClient-all diff --git a/src/VBox/Additions/linux/drm/Makefile.kmk b/src/VBox/Additions/linux/drm/Makefile.kmk index 4b1da745..e95b0f7b 100644 --- a/src/VBox/Additions/linux/drm/Makefile.kmk +++ b/src/VBox/Additions/linux/drm/Makefile.kmk @@ -39,46 +39,57 @@ vboxvideo_drm-mod_EXEC_SOURCES = \ # The kernel module. # # Note! Syntax checking only. Don't bother if drmP.h is missing (introduced -# in 2.6.27). +# in 2.6.27). For the mode-setting driver make sure this is supported. # Note! The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels. # -if defined(VBOX_WITH_ADDITION_DRIVERS) \ - && "$(strip $(foreach inc,$(VBOX_LINUX_INCS),$(wildcard $(inc)/drm/drmP.h)))" != "" - SYSMODS += vboxvideo_drm - vboxvideo_drm_TEMPLATE = VBOXGUESTR0 - vboxvideo_drm_CFLAGS = -fshort-wchar - vboxvideo_drm_DEFS = \ - MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \ - KBUILD_MODNAME=KBUILD_STR\(vboxvideo\) \ - KBUILD_BASENAME=KBUILD_STR\(vboxvideo\) \ - DEBUG_HASH=2 DEBUG_HASH2=3 - # detect fc6 2.6.18 - vboxvideo_drm_DEFS += \ - $(foreach inc,$(VBOX_LINUX_INCS),\ - $(if $(wildcard $(inc)/linux/utsrelease.h),\ - $(if $(shell if grep -q '"2.6.18.*fc6.*"' $(inc)/linux/utsrelease.h;\ - then echo yes; fi),KERNEL_FC6,),)) - # detect rhel5 2.6.18 - vboxvideo_drm_DEFS += \ - $(foreach inc,$(VBOX_LINUX_INCS),\ - $(if $(wildcard $(inc)/linux/utsrelease.h),\ - $(if $(shell if grep -q '"2.6.18.*el5.*"' $(inc)/linux/utsrelease.h;\ - then echo yes; fi),KERNEL_FC6,),)) +if defined(VBOX_WITH_ADDITION_DRIVERS) if !defined(VBOX_WITH_GUEST_KMS_DRIVER) - vboxvideo_drm_SOURCES = vboxvideo_drm.c + if "$(strip $(foreach inc,$(VBOX_LINUX_INCS),$(wildcard $(inc)/drm/drmP.h)))" != "" + SYSMODS += vboxvideo_drm + endif else - vboxvideo_drm_INCS += ../../../Runtime/r0drv/linux - vboxvideo_drm_SOURCES = \ - ../../common/VBoxVideo/Modesetting.cpp \ - vboxvideo_crtc.c \ - vboxvideo_dac.c \ - vboxvideo_device.c \ - vboxvideo_display.c \ - vboxvideo_drv.c \ - vboxvideo_kms.c \ - vboxvideo_vga.c + if "$(shell grep -s 'DRIVER_MODESET' $(foreach inc,$(VBOX_LINUX_INCS),$(inc)/drm/drmP.h))" != "" + SYSMODS += vboxvideo_drm + endif endif +endif +vboxvideo_drm_TEMPLATE = VBOXGUESTR0 +vboxvideo_drm_CFLAGS = -fshort-wchar +vboxvideo_drm_DEFS = \ + MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \ + KBUILD_MODNAME=KBUILD_STR\(vboxvideo\) \ + KBUILD_BASENAME=KBUILD_STR\(vboxvideo\) \ + DEBUG_HASH=2 DEBUG_HASH2=3 +# detect fc6 2.6.18 +vboxvideo_drm_DEFS += \ + $(foreach inc,$(VBOX_LINUX_INCS),\ + $(if $(wildcard $(inc)/linux/utsrelease.h),\ + $(if $(shell if grep -q '"2.6.18.*fc6.*"' $(inc)/linux/utsrelease.h;\ + then echo yes; fi),KERNEL_FC6,),)) +# detect rhel5 2.6.18 +vboxvideo_drm_DEFS += \ + $(foreach inc,$(VBOX_LINUX_INCS),\ + $(if $(wildcard $(inc)/linux/utsrelease.h),\ + $(if $(shell if grep -q '"2.6.18.*el5.*"' $(inc)/linux/utsrelease.h;\ + then echo yes; fi),KERNEL_FC6,),)) +if !defined(VBOX_WITH_GUEST_KMS_DRIVER) + vboxvideo_drm_SOURCES = vboxvideo_drm.c +else + vboxvideo_drm_INCS += \ + ../../../Runtime/include \ + ../../../Runtime/r0drv/linux + vboxvideo_drm_SOURCES = \ + ../../common/VBoxVideo/HGSMIBase.cpp \ + ../../common/VBoxVideo/Modesetting.cpp \ + ../../common/VBoxVideo/VBVABase.cpp \ + ../../../GuestHost/HGSMI/HGSMICommon.cpp \ + ../../../Runtime/common/alloc/heapoffset.cpp \ + vbox_drv.c \ + vbox_fb.c \ + vbox_main.c \ + vbox_mode.c \ + vbox_ttm.c endif include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/Additions/linux/drm/Makefile.module b/src/VBox/Additions/linux/drm/Makefile.module index c382be7b..58daaefa 100644 --- a/src/VBox/Additions/linux/drm/Makefile.module +++ b/src/VBox/Additions/linux/drm/Makefile.module @@ -3,7 +3,7 @@ # # (For 2.6.x this file must be 'Makefile'!) # -# Copyright (C) 2006-2010 Oracle Corporation +# Copyright (C) 2006-2011 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -31,6 +31,12 @@ MOD_CFLAGS = -fshort-wchar -include $(MANGLING) MOD_INCL = $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux) # What on earth is this? MOD_INCL += $(addprefix -I$(KBUILD_EXTMOD)/vboxvideo,/ /include /r0drv/linux) +# Enterprise Linux 6.5 does not include the drm user API headers with the kernel +# headers. +MOD_INCL += $(foreach inc,$(KERN_INCL) include,\ + $(if $(wildcard $(inc)/linux/utsrelease.h),\ + $(if $(shell grep '"2.6.32.*el6.*"' $(inc)/linux/utsrelease.h),\ + -I/usr/include,),)) MOD_DEFS := -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 \ -DIN_SUP_R0 -DVBOX -DVBOX_WITH_HGCM -DLOG_TO_BACKDOOR -DIN_MODULE \ -DIN_GUEST_R0 diff --git a/src/VBox/Additions/linux/drm/Makefile.module.kms b/src/VBox/Additions/linux/drm/Makefile.module.kms index 8d0a3628..80cbd984 100644 --- a/src/VBox/Additions/linux/drm/Makefile.module.kms +++ b/src/VBox/Additions/linux/drm/Makefile.module.kms @@ -20,8 +20,8 @@ include $(obj)/Makefile.include.header MOD_NAME = vboxvideo -MOD_OBJS = Modesetting.o vboxvideo_crtc.o vboxvideo_dac.o vboxvideo_device.o \ - vboxvideo_display.o vboxvideo_drv.o vboxvideo_kms.o vboxvideo_vga.o +MOD_OBJS = HGSMIBase.o HGSMICommon.o heapoffset.o Modesetting.o vbox_drv.o \ + vbox_fb.o vbox_main.o vbox_mode.o vbox_ttm.o VBVABase.o ifneq ($(wildcard $(KBUILD_EXTMOD)/vboxvideo),) MANGLING := $(KBUILD_EXTMOD)/vboxvideo/include/VBox/VBoxGuestMangling.h @@ -29,9 +29,10 @@ else MANGLING := $(KBUILD_EXTMOD)/include/VBox/VBoxGuestMangling.h endif MOD_CFLAGS = -fshort-wchar -include $(MANGLING) -MOD_INCL = $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux) +MOD_INCL = $(addprefix -I$(KBUILD_EXTMOD),/ /include) # What on earth is this? -MOD_INCL += $(addprefix -I$(KBUILD_EXTMOD)/vboxvideo,/ /include /r0drv/linux) +MOD_INCL += $(addprefix -I$(KBUILD_EXTMOD)/vboxvideo,/ /include) +MOD_INCL += -Iinclude/drm MOD_DEFS := -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 \ -DIN_SUP_R0 -DVBOX -DVBOX_WITH_HGCM -DLOG_TO_BACKDOOR -DIN_MODULE \ -DIN_GUEST_R0 diff --git a/src/VBox/Additions/linux/drm/files_vboxvideo_drm b/src/VBox/Additions/linux/drm/files_vboxvideo_drm index 9f18c86f..2a652de4 100755 --- a/src/VBox/Additions/linux/drm/files_vboxvideo_drm +++ b/src/VBox/Additions/linux/drm/files_vboxvideo_drm @@ -5,7 +5,7 @@ # # -# Copyright (C) 2007-2010 Oracle Corporation +# Copyright (C) 2007-2011 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/drm/files_vboxvideo_drv b/src/VBox/Additions/linux/drm/files_vboxvideo_drv index 181d1148..67b6c4e0 100755 --- a/src/VBox/Additions/linux/drm/files_vboxvideo_drv +++ b/src/VBox/Additions/linux/drm/files_vboxvideo_drv @@ -24,14 +24,17 @@ FILES_VBOXVIDEO_DRM_NOBIN=" \ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \ + ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \ + ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \ ${PATH_ROOT}/include/iprt/mangling.h=>include/iprt/mangling.h \ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \ + ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \ ${PATH_ROOT}/include/VBox/ostypes.h=>include/VBox/ostypes.h \ ${PATH_ROOT}/include/VBox/param.h=>include/VBox/param.h \ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \ @@ -46,18 +49,20 @@ FILES_VBOXVIDEO_DRM_NOBIN=" \ ${PATH_ROOT}/include/VBox/HGSMI/HGSMIChannels.h=>include/VBox/HGSMI/HGSMIChannels.h \ ${PATH_ROOT}/include/VBox/HGSMI/HGSMIChSetup.h=>include/VBox/HGSMI/HGSMIChSetup.h \ ${PATH_ROOT}/include/VBox/Hardware/VBoxVideoVBE.h=>include/VBox/Hardware/VBoxVideoVBE.h \ + ${PATH_ROOT}/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp=>HGSMIBase.c \ ${PATH_ROOT}/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp=>Modesetting.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo.h=>vboxvideo.h \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_crtc.c=>vboxvideo_crtc.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_dac.c=>vboxvideo_dac.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_device.c=>vboxvideo_device.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_display.c=>vboxvideo_display.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_drv.c=>vboxvideo_drv.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_drv.h=>vboxvideo_drv.h \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_kms.c=>vboxvideo_kms.c \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_mode.h=>vboxvideo_mode.h \ - ${PATH_ROOT}/src/VBox/Additions/linux/drm/vboxvideo_vga.c=>vboxvideo_vga.c \ - ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \ + ${PATH_ROOT}/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp=>VBVABase.c \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_drv.c=>vbox_drv.c \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_drv.h=>vbox_drv.h \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_fb.c=>vbox_fb.c \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_main.c=>vbox_main.c \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_mode.c=>vbox_mode.c \ + ${PATH_ROOT}/src/VBox/Additions/linux/drm/vbox_ttm.c=>vbox_ttm.c \ + ${PATH_ROOT}/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp=>HGSMICommon.c \ + ${PATH_ROOT}/src/VBox/Runtime/common/alloc/heapoffset.cpp=>heapoffset.c \ + ${PATH_ROOT}/src/VBox/Runtime/include/internal/iprt.h=>include/internal/iprt.h \ + ${PATH_ROOT}/src/VBox/Runtime/include/internal/magics.h=>include/internal/magics.h \ + ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>include/the-linux-kernel.h \ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile.include.header=>Makefile.include.header \ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile.include.footer=>Makefile.include.footer \ ${PATH_ROOT}/src/VBox/Additions/linux/drm/Makefile.module.kms=>Makefile \ diff --git a/src/VBox/Additions/linux/drm/vbox_drv.c b/src/VBox/Additions/linux/drm/vbox_drv.c new file mode 100644 index 00000000..df7997f0 --- /dev/null +++ b/src/VBox/Additions/linux/drm/vbox_drv.c @@ -0,0 +1,151 @@ +/** @file $Id: vbox_drv.c $ + * + * VirtualBox Additions Linux kernel video driver + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * -------------------------------------------------------------------- + * + * This code is based on + * ast_drv.c + * with the following copyright and permission notice: + * + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: Dave Airlie <airlied@redhat.com> + */ +#include "vbox_drv.h" + +#include <linux/module.h> +#include <linux/console.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> + +int vbox_modeset = -1; + +MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); +module_param_named(modeset, vbox_modeset, int, 0400); + +static struct drm_driver driver; + +static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { + {0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0, 0, 0}, +}; + +MODULE_DEVICE_TABLE(pci, pciidlist); + +static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_pci_dev(pdev, ent, &driver); +} + + +static void +vbox_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_put_dev(dev); +} + + +static struct pci_driver vbox_pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = vbox_pci_probe, + .remove = vbox_pci_remove, +}; + +static const struct file_operations vbox_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = vbox_mmap, + .poll = drm_poll, + .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .read = drm_read, +}; + +static struct drm_driver driver = { + .driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM, + .dev_priv_size = 0, + + .load = vbox_driver_load, + .unload = vbox_driver_unload, + + .fops = &vbox_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, + + .gem_init_object = vbox_gem_init_object, + .gem_free_object = vbox_gem_free_object, + .dumb_create = vbox_dumb_create, + .dumb_map_offset = vbox_dumb_mmap_offset, + .dumb_destroy = vbox_dumb_destroy, + +}; + +static int __init vbox_init(void) +{ +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force() && vbox_modeset == -1) + return -EINVAL; +#endif + + if (vbox_modeset == 0) + return -EINVAL; + return drm_pci_init(&driver, &vbox_pci_driver); +} +static void __exit vbox_exit(void) +{ + drm_pci_exit(&driver, &vbox_pci_driver); +} + +module_init(vbox_init); +module_exit(vbox_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); + diff --git a/src/VBox/Additions/linux/drm/vbox_drv.h b/src/VBox/Additions/linux/drm/vbox_drv.h new file mode 100644 index 00000000..523710c5 --- /dev/null +++ b/src/VBox/Additions/linux/drm/vbox_drv.h @@ -0,0 +1,226 @@ +/** @file $Id: vbox_drv.h $ + * + * VirtualBox Additions Linux kernel video driver + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * -------------------------------------------------------------------- + * + * This code is based on + * ast_drv.h + * with the following copyright and permission notice: + * + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: Dave Airlie <airlied@redhat.com> + */ +#ifndef __VBOX_DRV_H__ +#define __VBOX_DRV_H__ + +#include <VBox/VBoxVideoGuest.h> + +#include "the-linux-kernel.h" + +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> + +#include <drm/ttm/ttm_bo_api.h> +#include <drm/ttm/ttm_bo_driver.h> +#include <drm/ttm/ttm_placement.h> +#include <drm/ttm/ttm_memory.h> +#include <drm/ttm/ttm_module.h> + +/* #include "vboxvideo.h" */ + +#include "product-generated.h" + +#define DRIVER_AUTHOR VBOX_VENDOR + +#define DRIVER_NAME "vboxvideo" +#define DRIVER_DESC VBOX_PRODUCT " Graphics Card" +#define DRIVER_DATE "20130823" + +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +struct vbox_fbdev; + +struct vbox_private { + struct drm_device *dev; + + void __iomem *vram; + HGSMIGUESTCOMMANDCONTEXT Ctx; + struct VBVABUFFERCONTEXT *paVBVACtx; + bool fAnyX; + unsigned cCrtcs; + bool vga2_clone; + uint32_t vram_size; + + struct vbox_fbdev *fbdev; + + int fb_mtrr; + + struct { + struct drm_global_reference mem_global_ref; + struct ttm_bo_global_ref bo_global_ref; + struct ttm_bo_device bdev; + } ttm; + + struct drm_gem_object *cursor_cache; + uint64_t cursor_cache_gpu_addr; + struct ttm_bo_kmap_obj cache_kmap; + int next_cursor; +}; + +int vbox_driver_load(struct drm_device *dev, unsigned long flags); +int vbox_driver_unload(struct drm_device *dev); + +struct vbox_gem_object; + +struct vbox_connector { + struct drm_connector base; +}; + +struct vbox_crtc { + struct drm_crtc base; + bool fBlanked; + unsigned crtc_id; + struct drm_gem_object *cursor_bo; + uint64_t cursor_addr; + int cursor_width, cursor_height; + u8 offset_x, offset_y; +}; + +struct vbox_encoder { + struct drm_encoder base; +}; + +struct vbox_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; + uint64_t offBase; +}; + +struct vbox_fbdev { + struct drm_fb_helper helper; + struct vbox_framebuffer afb; + struct list_head fbdev_list; + void *sysram; + int size; + struct ttm_bo_kmap_obj mapping; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; +}; + +#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base) +#define to_vbox_connector(x) container_of(x, struct vbox_connector, base) +#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base) +#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base) + +extern int vbox_mode_init(struct drm_device *dev); +extern void vbox_mode_fini(struct drm_device *dev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) +# define DRM_MODE_FB_CMD drm_mode_fb_cmd +#else +# define DRM_MODE_FB_CMD drm_mode_fb_cmd2 +#endif + +int vbox_framebuffer_init(struct drm_device *dev, + struct vbox_framebuffer *vbox_fb, + struct DRM_MODE_FB_CMD *mode_cmd, + struct drm_gem_object *obj); + +int vbox_fbdev_init(struct drm_device *dev); +void vbox_fbdev_fini(struct drm_device *dev); +void vbox_fbdev_set_suspend(struct drm_device *dev, int state); + +struct vbox_bo { + struct ttm_buffer_object bo; + struct ttm_placement placement; + struct ttm_bo_kmap_obj kmap; + struct drm_gem_object gem; + u32 placements[3]; + int pin_count; +}; +#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem) + +static inline struct vbox_bo * +vbox_bo(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct vbox_bo, bo); +} + + +#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base) + +extern int vbox_dumb_create(struct drm_file *file, + struct drm_device *dev, + struct drm_mode_create_dumb *args); +extern int vbox_dumb_destroy(struct drm_file *file, + struct drm_device *dev, + uint32_t handle); + +extern int vbox_gem_init_object(struct drm_gem_object *obj); +extern void vbox_gem_free_object(struct drm_gem_object *obj); +extern int vbox_dumb_mmap_offset(struct drm_file *file, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset); + +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + +int vbox_mm_init(struct vbox_private *vbox); +void vbox_mm_fini(struct vbox_private *vbox); + +int vbox_bo_create(struct drm_device *dev, int size, int align, + uint32_t flags, struct vbox_bo **pvboxbo); + +int vbox_gem_create(struct drm_device *dev, + u32 size, bool iskernel, + struct drm_gem_object **obj); + +int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr); +int vbox_bo_unpin(struct vbox_bo *bo); + +int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait); +void vbox_bo_unreserve(struct vbox_bo *bo); +void vbox_ttm_placement(struct vbox_bo *bo, int domain); +int vbox_bo_push_sysram(struct vbox_bo *bo); +int vbox_mmap(struct file *filp, struct vm_area_struct *vma); + +/* vbox post */ +void vbox_post_gpu(struct drm_device *dev); +#endif diff --git a/src/VBox/Additions/linux/drm/vboxvideo.h b/src/VBox/Additions/linux/drm/vboxvideo.h deleted file mode 100644 index 907b70e7..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo.h +++ /dev/null @@ -1,73 +0,0 @@ -/** @file $Id: vboxvideo.h $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint.h - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#ifndef __DRM_VBOXVIDEO_H__ -#define __DRM_VBOXVIDEO_H__ - -#include "vboxvideo_mode.h" -#include "drm/drmP.h" - -struct vboxvideo_mc -{ - resource_size_t aper_size; - resource_size_t aper_base; - u32 vram_size; -}; - -struct vboxvideo_device -{ - struct device *dev; - struct drm_device *ddev; - struct pci_dev *pdev; - unsigned long flags; - /** @todo move this into flags */ - bool fAnyX; - - struct vboxvideo_mc mc; - struct vboxvideo_mode_info mode_info; - - int num_crtc; -}; - -#endif /* __DRM_VBOXVIDEO_H__ */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_crtc.c b/src/VBox/Additions/linux/drm/vboxvideo_crtc.c deleted file mode 100644 index aa4c2742..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_crtc.c +++ /dev/null @@ -1,188 +0,0 @@ -/** @file $Id: vboxvideo_crtc.c $ - * - * VirtualBox Additions Linux kernel video driver, KMS support - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_crtc.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - -#include <VBox/VBoxVideoGuest.h> - -#include "vboxvideo_drv.h" - -#include "drm/drm_crtc_helper.h" - -static void vboxvideo_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct vboxvideo_crtc *vboxvideo_crtc = to_vboxvideo_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct vboxvideo_device *gdev = dev->dev_private; - - if (mode == vboxvideo_crtc->last_dpms) /* Don't do unnecesary mode changes. */ - return; - - vboxvideo_crtc->last_dpms = mode; - - switch (mode) { - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - vboxvideo_crtc->enabled = false; - break; - case DRM_MODE_DPMS_ON: - vboxvideo_crtc->enabled = true; - break; - } -} - -static bool vboxvideo_crtc_mode_fixup(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static int vboxvideo_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, struct drm_framebuffer *old_fb) -{ - /* - struct vboxvideo_crtc *vboxvideo_crtc = to_vboxvideo_crtc(crtc); - - vboxvideo_crtc_set_base(crtc, x, y, old_fb); - vboxvideo_set_crtc_timing(crtc, adjusted_mode); - vboxvideo_set_pll(crtc, adjusted_mode); - */ - return 0; -} - -static void vboxvideo_crtc_prepare(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_crtc *crtci; - - /* - list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) - vboxvideo_crtc_dpms(crtci, DRM_MODE_DPMS_OFF); - */ -} - -static void vboxvideo_crtc_commit(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_crtc *crtci; - - /* - list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) { - if (crtci->enabled) - vboxvideo_crtc_dpms(crtci, DRM_MODE_DPMS_ON); - } - */ -} - -static void vboxvideo_crtc_load_lut(struct drm_crtc *crtc) -{ - /* Dummy */ -} - -static void vboxvideo_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, - u16 *green, u16 *blue, uint32_t size) -{ - /* Dummy */ -} - -static void vboxvideo_crtc_destroy(struct drm_crtc *crtc) -{ - struct vboxvideo_crtc *vboxvideo_crtc = to_vboxvideo_crtc(crtc); - - drm_crtc_cleanup(crtc); - kfree(vboxvideo_crtc); -} - -static const struct drm_crtc_funcs vboxvideo_crtc_funcs = { - /* - .cursor_set = vboxvideo_crtc_cursor_set, - .cursor_move = vboxvideo_crtc_cursor_move, - */ - .cursor_set = NULL, - .cursor_move = NULL, - .gamma_set = vboxvideo_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = vboxvideo_crtc_destroy, -}; - -static const struct drm_crtc_helper_funcs vboxvideo_helper_funcs = { - .dpms = vboxvideo_crtc_dpms, - .mode_fixup = vboxvideo_crtc_mode_fixup, - .mode_set = vboxvideo_crtc_mode_set, - /* - .mode_set_base = vboxvideo_crtc_set_base, - */ - .prepare = vboxvideo_crtc_prepare, - .commit = vboxvideo_crtc_commit, - .load_lut = vboxvideo_crtc_load_lut, -}; - -void vboxvideo_crtc_init(struct drm_device *dev, int index) -{ - struct vboxvideo_device *gdev = dev->dev_private; - struct vboxvideo_crtc *vboxvideo_crtc; - int i; - - vboxvideo_crtc = kzalloc( sizeof(struct vboxvideo_crtc) - + (VBOXVIDEOFB_CONN_LIMIT - * sizeof(struct drm_connector *)), - GFP_KERNEL); - if (vboxvideo_crtc == NULL) - return; - - drm_crtc_init(dev, &vboxvideo_crtc->base, &vboxvideo_crtc_funcs); - - vboxvideo_crtc->crtc_id = index; - vboxvideo_crtc->last_dpms = VBOXVIDEO_DPMS_CLEARED; - gdev->mode_info.crtcs[index] = vboxvideo_crtc; - - drm_crtc_helper_add(&vboxvideo_crtc->base, &vboxvideo_helper_funcs); -} - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_dac.c b/src/VBox/Additions/linux/drm/vboxvideo_dac.c deleted file mode 100644 index 94e1e700..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_dac.c +++ /dev/null @@ -1,137 +0,0 @@ -/** @file $Id: vboxvideo_dac.c $ - * - * VirtualBox Additions Linux kernel video driver, DAC functions - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_dac.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - -#include "vboxvideo_drv.h" - -#include "drm/drm_crtc_helper.h" - -static void vboxvideo_dac_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct vboxvideo_device *gdev = dev->dev_private; - struct vboxvideo_encoder *vboxvideo_encoder = to_vboxvideo_encoder(encoder); - - if (mode == vboxvideo_encoder->last_dpms) /* Don't do unnecesary mode changes. */ - return; - - vboxvideo_encoder->last_dpms = mode; - - switch (mode) { - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - /* Do nothing for now */ - break; - case DRM_MODE_DPMS_ON: - /* Do nothing for now */ - break; - } -} - -static bool vboxvideo_dac_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static void vboxvideo_dac_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - -} - -static void vboxvideo_dac_prepare(struct drm_encoder *encoder) -{ - -} - -static void vboxvideo_dac_commit(struct drm_encoder *encoder) -{ - -} - -void vboxvideo_encoder_destroy(struct drm_encoder *encoder) -{ - struct vboxvideo_encoder *vboxvideo_encoder = to_vboxvideo_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(vboxvideo_encoder); -} - -static const struct drm_encoder_helper_funcs vboxvideo_dac_helper_funcs = { - .dpms = vboxvideo_dac_dpms, - .mode_fixup = vboxvideo_dac_mode_fixup, - .mode_set = vboxvideo_dac_mode_set, - .prepare = vboxvideo_dac_prepare, - .commit = vboxvideo_dac_commit, -}; - -static const struct drm_encoder_funcs vboxvideo_dac_encoder_funcs = { - .destroy = vboxvideo_encoder_destroy, -}; - -struct drm_encoder *vboxvideo_dac_init(struct drm_device *dev) -{ - struct drm_encoder *encoder; - struct vboxvideo_encoder *vboxvideo_encoder; - - vboxvideo_encoder = kzalloc(sizeof(struct vboxvideo_encoder), GFP_KERNEL); - if (!vboxvideo_encoder) - return NULL; - - vboxvideo_encoder->last_dpms = VBOXVIDEO_DPMS_CLEARED; - encoder = &vboxvideo_encoder->base; - encoder->possible_crtcs = 0x1; - - drm_encoder_init(dev, encoder, &vboxvideo_dac_encoder_funcs, DRM_MODE_ENCODER_DAC); - drm_encoder_helper_add(encoder, &vboxvideo_dac_helper_funcs); - - return encoder; -} - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_device.c b/src/VBox/Additions/linux/drm/vboxvideo_device.c deleted file mode 100644 index e23d4774..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_device.c +++ /dev/null @@ -1,79 +0,0 @@ -/** @file $Id: vboxvideo_device.c $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * vboxvideo_device.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - -#include "the-linux-kernel.h" - -#include "vboxvideo_drv.h" - -#include <VBox/VBoxVideoGuest.h> - -int vboxvideo_device_init(struct vboxvideo_device *gdev, - struct drm_device *ddev, - struct pci_dev *pdev, - uint32_t flags) -{ - gdev->dev = &pdev->dev; - gdev->ddev = ddev; - gdev->pdev = pdev; - gdev->flags = flags; - gdev->num_crtc = 1; - - /** @todo hardware initialisation goes here once we start doing more complex - * stuff. - */ - gdev->fAnyX = VBoxVideoAnyWidthAllowed(); - gdev->mc.vram_size = VBoxVideoGetVRAMSize(); - - return 0; -} - -void vboxvideo_device_fini(struct vboxvideo_device *gdev) -{ - -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_display.c b/src/VBox/Additions/linux/drm/vboxvideo_display.c deleted file mode 100644 index 16294aba..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_display.c +++ /dev/null @@ -1,93 +0,0 @@ -/** @file $Id: vboxvideo_display.c $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * vboxvideo_device.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - -#include "vboxvideo_drv.h" - -int vboxvideo_modeset_init(struct vboxvideo_device *gdev) -{ - struct drm_encoder *encoder; - struct drm_connector *connector; - int i; - - drm_mode_config_init(gdev->ddev); - gdev->mode_info.mode_config_initialized = true; - - gdev->ddev->mode_config.max_width = VBOXVIDEO_MAX_FB_WIDTH; - gdev->ddev->mode_config.max_height = VBOXVIDEO_MAX_FB_HEIGHT; - - gdev->ddev->mode_config.fb_base = gdev->mc.aper_base; - - /* allocate crtcs */ - for (i = 0; i < gdev->num_crtc; i++) - { - vboxvideo_crtc_init(gdev->ddev, i); - } - - encoder = vboxvideo_dac_init(gdev->ddev); - if (!encoder) { - VBOXVIDEO_ERROR("vboxvideo_dac_init failed\n"); - return -1; - } - - connector = vboxvideo_vga_init(gdev->ddev); - if (!connector) { - VBOXVIDEO_ERROR("vboxvideo_vga_init failed\n"); - return -1; - } - return 0; -} - -void vboxvideo_modeset_fini(struct vboxvideo_device *gdev) -{ - if (gdev->mode_info.mode_config_initialized) - { - drm_mode_config_cleanup(gdev->ddev); - gdev->mode_info.mode_config_initialized = false; - } -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_drm.c b/src/VBox/Additions/linux/drm/vboxvideo_drm.c index 02c23183..37b9df7e 100644 --- a/src/VBox/Additions/linux/drm/vboxvideo_drm.c +++ b/src/VBox/Additions/linux/drm/vboxvideo_drm.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -64,11 +64,14 @@ # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) # ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1) +# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 1) # define DRM_RHEL61 # endif -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,3) -# define DRM_RHEL63 +# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 3) +# define DRM_FOPS_AS_POINTER +# endif +# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 4) +# define DRM_NO_RECLAIM_BUFFERS # endif # endif # endif @@ -76,10 +79,30 @@ #include "drm/drmP.h" #include "vboxvideo_drm.h" +# ifndef RHEL_RELEASE_CODE +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 39) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) +# if defined(DRM_MODE_OBJECT_PLANE) && defined(DRM_IOCTL_MODE_ADDFB2) +# define DRM_FOPS_AS_POINTER +# endif +# endif +# endif + +#ifdef CONFIG_SUSE_KERNEL +/* This is to cover the SLES 11 SP3 kernel back-ports. */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,61) +# if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) +# define DRM_FOPS_AS_POINTER +# define DRM_NO_RECLAIM_BUFFERS +# endif +# endif +#endif + static struct pci_device_id pciidlist[] = { vboxvideo_PCI_IDS }; +MODULE_DEVICE_TABLE(pci, pciidlist); + int vboxvideo_driver_load(struct drm_device * dev, unsigned long flags) { # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) @@ -88,7 +111,7 @@ int vboxvideo_driver_load(struct drm_device * dev, unsigned long flags) return 0; #endif } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) || defined(DRM_RHEL63) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) || defined(DRM_FOPS_AS_POINTER) /* since linux-3.3.0-rc1 drm_driver::fops is pointer */ static struct file_operations driver_fops = { @@ -98,7 +121,6 @@ static struct file_operations driver_fops = .unlocked_ioctl = drm_ioctl, .mmap = drm_mmap, .poll = drm_poll, - .fasync = drm_fasync, }; #endif @@ -106,7 +128,7 @@ static struct drm_driver driver = { /* .driver_features = DRIVER_USE_MTRR, */ .load = vboxvideo_driver_load, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) && !defined(DRM_NO_RECLAIM_BUFFERS) .reclaim_buffers = drm_core_reclaim_buffers, #endif /* As of Linux 2.6.37, always the internal functions are used. */ @@ -114,7 +136,7 @@ static struct drm_driver driver = .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, #endif -# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) && !defined(DRM_RHEL63) +# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) && !defined(DRM_FOPS_AS_POINTER) .fops = { .owner = THIS_MODULE, @@ -129,12 +151,11 @@ static struct drm_driver driver = #endif .mmap = drm_mmap, .poll = drm_poll, - .fasync = drm_fasync, }, -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) || defined(DRM_RHEL63) */ +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) || defined(DRM_FOPS_AS_POINTER) */ .fops = &driver_fops, #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(DRM_RHEL61) +#ifndef DRIVER_BUS_PCI .pci_driver = { .name = DRIVER_NAME, @@ -149,7 +170,7 @@ static struct drm_driver driver = .patchlevel = DRIVER_PATCHLEVEL, }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) || defined(DRM_RHEL61) +#ifdef DRIVER_BUS_PCI static struct pci_driver pci_driver = { .name = DRIVER_NAME, @@ -159,7 +180,7 @@ static struct pci_driver pci_driver = static int __init vboxvideo_init(void) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(DRM_RHEL61) +#ifndef DRIVER_BUS_PCI return drm_init(&driver); #else return drm_pci_init(&driver, &pci_driver); @@ -168,7 +189,7 @@ static int __init vboxvideo_init(void) static void __exit vboxvideo_exit(void) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(DRM_RHEL61) +#ifndef DRIVER_BUS_PCI drm_exit(&driver); #else drm_pci_exit(&driver, &pci_driver); diff --git a/src/VBox/Additions/linux/drm/vboxvideo_drm.h b/src/VBox/Additions/linux/drm/vboxvideo_drm.h index 0613a9d2..11407e94 100644 --- a/src/VBox/Additions/linux/drm/vboxvideo_drm.h +++ b/src/VBox/Additions/linux/drm/vboxvideo_drm.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/drm/vboxvideo_drv.c b/src/VBox/Additions/linux/drm/vboxvideo_drv.c deleted file mode 100644 index c5df61ce..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_drv.c +++ /dev/null @@ -1,148 +0,0 @@ -/** @file $Id: vboxvideo_drv.c $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_drv.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> -#include <linux/module.h> -#include "version-generated.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) -# ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1) -# define DRM_RHEL61 -# endif -# endif -# endif - -#include "vboxvideo_drv.h" - -static struct pci_device_id pciidlist[] = { - vboxvideo_PCI_IDS -}; - -static struct drm_driver driver = -{ - .driver_features = 0, - .load = vboxvideo_driver_load, - .unload = vboxvideo_driver_unload, - .reclaim_buffers = drm_core_reclaim_buffers, - /* As of Linux 2.6.37, always the internal functions are used. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) && !defined(DRM_RHEL61) - .get_map_ofs = drm_core_get_map_ofs, - .get_reg_ofs = drm_core_get_reg_ofs, -#endif - .ioctls = vboxvideo_ioctls, - .fops = - { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - /* This was changed with Linux 2.6.33 but Fedora backported this - * change to their 2.6.32 kernel. */ -#if defined(DRM_UNLOCKED) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - .unlocked_ioctl = drm_ioctl, -#else - .ioctl = drm_ioctl, -#endif - .mmap = drm_mmap, - .poll = drm_poll, - .fasync = drm_fasync, - }, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) - .pci_driver = - { - .name = DRIVER_NAME, - .id_table = pciidlist, - }, -#endif - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) -static struct pci_driver pci_driver = -{ - .name = DRIVER_NAME, - .id_table = pciidlist, -}; -#endif - -static int __init vboxvideo_init(void) -{ - printk(KERN_INFO "vboxvideo initializing\n"); - driver.num_ioctls = vboxvideo_max_ioctl; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) - return drm_init(&driver); -#else - return drm_pci_init(&driver, &pci_driver); -#endif -} - -static void __exit vboxvideo_exit(void) -{ - printk(KERN_INFO "vboxvideo exiting\n"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) - drm_exit(&driver); -#else - drm_pci_exit(&driver, &pci_driver); -#endif -} - -module_init(vboxvideo_init); -module_exit(vboxvideo_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - -#ifdef MODULE_VERSION -MODULE_VERSION(VBOX_VERSION_STRING); -#endif -MODULE_LICENSE("GPL and additional rights"); diff --git a/src/VBox/Additions/linux/drm/vboxvideo_drv.h b/src/VBox/Additions/linux/drm/vboxvideo_drv.h deleted file mode 100644 index 7cbd5f5a..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_drv.h +++ /dev/null @@ -1,101 +0,0 @@ -/** @file $Id: vboxvideo_drv.h $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_drv.h - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#ifndef __DRM_VBOXVIDEO_DRV_H__ -#define __DRM_VBOXVIDEO_DRV_H__ - -/* General customization: - */ - -#include "vboxvideo.h" - -#include "product-generated.h" - -#define DRIVER_AUTHOR VBOX_VENDOR - -#define DRIVER_NAME "vboxvideo" -#define DRIVER_DESC VBOX_PRODUCT " Graphics Card" -#define DRIVER_DATE "20090303" - -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 0 - -#define VBOXVIDEO_INFO(fmt, arg...) DRM_INFO(DRIVER_NAME ": " fmt, ##arg) -#define VBOXVIDEO_ERROR(fmt, arg...) DRM_ERROR(DRIVER_NAME ": " fmt, ##arg) - -/** @todo does this make sense? What exactly is this connector? */ -#define VBOXVIDEOFB_CONN_LIMIT VBOX_VIDEO_MAX_SCREENS - -/* vboxvideo_crtc.c */ -void vboxvideo_crtc_init(struct drm_device *dev, int index); - -/* vboxvideo_dac.c */ -struct drm_encoder *vboxvideo_dac_init(struct drm_device *dev); - -/* vboxvideo_device.c */ -int vboxvideo_device_init(struct vboxvideo_device *gdev, - struct drm_device *ddev, - struct pci_dev *pdev, - uint32_t flags); -void vboxvideo_device_fini(struct vboxvideo_device *gdev); - -/* vboxvideo_display.c */ -int vboxvideo_modeset_init(struct vboxvideo_device *gdev); -void vboxvideo_modeset_fini(struct vboxvideo_device *gdev); - -/* vboxvideo_kms.c */ -int vboxvideo_driver_load(struct drm_device *dev, unsigned long flags); -int vboxvideo_driver_unload(struct drm_device *dev); -extern struct drm_ioctl_desc vboxvideo_ioctls[]; -extern int vboxvideo_max_ioctl; - -/* vboxvideo_vga.c */ -struct drm_connector *vboxvideo_vga_init(struct drm_device *dev); - -#define vboxvideo_PCI_IDS \ - {0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} - -#endif /* __DRM_VBOXVIDEO_DRV_H__ */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_kms.c b/src/VBox/Additions/linux/drm/vboxvideo_kms.c deleted file mode 100644 index 1fe68efe..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_kms.c +++ /dev/null @@ -1,100 +0,0 @@ -/** @file $Id: vboxvideo_kms.c $ - * - * VirtualBox Additions Linux kernel video driver, KMS support - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_kms.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - -#include "vboxvideo_drv.h" - -int vboxvideo_driver_load(struct drm_device * dev, unsigned long flags) -{ - struct vboxvideo_device *gdev; - int r; - - gdev = kzalloc(sizeof(struct vboxvideo_device), GFP_KERNEL); - if (gdev == NULL) { - return -ENOMEM; - } - dev->dev_private = (void *)gdev; - - r = vboxvideo_device_init(gdev, dev, dev->pdev, flags); - if (r) { - dev_err(&dev->pdev->dev, "Fatal error during GPU init\n"); - goto out; - } - - r = vboxvideo_modeset_init(gdev); - if (r) { - dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); - goto out; - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) - r = drm_vblank_init(dev, 1); - if (r) - dev_err(&dev->pdev->dev, "Fatal error during vblank init\n"); -#endif -out: - if (r) - vboxvideo_driver_unload(dev); - return r; -} - -int vboxvideo_driver_unload(struct drm_device * dev) -{ - struct vboxvideo_device *gdev = dev->dev_private; - - if (gdev == NULL) - return 0; - vboxvideo_modeset_fini(gdev); - vboxvideo_device_fini(gdev); - kfree(gdev); - dev->dev_private = NULL; - return 0; -} - -struct drm_ioctl_desc vboxvideo_ioctls[] = { -}; -int vboxvideo_max_ioctl = DRM_ARRAY_SIZE(vboxvideo_ioctls); - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_mode.h b/src/VBox/Additions/linux/drm/vboxvideo_mode.h deleted file mode 100644 index 5480a4c4..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_mode.h +++ /dev/null @@ -1,83 +0,0 @@ -/** @file $Id: vboxvideo_mode.h $ - * - * VirtualBox Additions Linux kernel video driver - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_mode.h - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#ifndef __DRM_VBOXVIDEO_MODE_H__ -#define __DRM_VBOXVIDEO_MODE_H__ - -#include <VBox/Hardware/VBoxVideoVBE.h> -#include "drm/drmP.h" - -#define VBOXVIDEO_MAX_FB_HEIGHT VBE_DISPI_MAX_YRES -#define VBOXVIDEO_MAX_FB_WIDTH VBE_DISPI_MAX_XRES - -#define to_vboxvideo_crtc(x) container_of(x, struct vboxvideo_crtc, base) -#define to_vboxvideo_encoder(x) container_of(x, struct vboxvideo_encoder, base) - -#define VBOXVIDEO_DPMS_CLEARED (-1) - -struct vboxvideo_crtc -{ - struct drm_crtc base; - int crtc_id; - int last_dpms; - bool enabled; -}; - -struct vboxvideo_mode_info -{ - bool mode_config_initialized; - struct vboxvideo_crtc *crtcs[VBOX_VIDEO_MAX_SCREENS]; -}; - -struct vboxvideo_encoder -{ - struct drm_encoder base; - int last_dpms; -}; - -struct vboxvideo_connector { - struct drm_connector base; -}; - -#endif /* __DRM_VBOXVIDEO_H__ */ diff --git a/src/VBox/Additions/linux/drm/vboxvideo_vga.c b/src/VBox/Additions/linux/drm/vboxvideo_vga.c deleted file mode 100644 index a8717b2f..00000000 --- a/src/VBox/Additions/linux/drm/vboxvideo_vga.c +++ /dev/null @@ -1,130 +0,0 @@ -/** @file $Id: vboxvideo_vga.c $ - * - * VirtualBox Additions Linux kernel video driver, VGA functions - */ - -/* - * Copyright (C) 2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - * -------------------------------------------------------------------- - * - * This code is based on - * glint_vga.c - * with the following copyright and permission notice: - * - * Copyright 2010 Matt Turner. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Matt Turner - */ - -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - -#include "vboxvideo_drv.h" -#include "drm/drm_crtc_helper.h" - -static int vboxvideo_vga_get_modes(struct drm_connector *connector) -{ - /* return 0 modes, so that we don't have to implement DDC/I2C yet. */ - return 0; -} - -static int vboxvideo_vga_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* XXX check mode bandwidth */ - /* XXX verify against max DAC output frequency */ - return MODE_OK; -} - -struct drm_encoder *vboxvideo_connector_best_encoder(struct drm_connector - *connector) -{ - int enc_id = connector->encoder_ids[0]; - struct drm_mode_object *obj; - struct drm_encoder *encoder; - - /* pick the encoder ids */ - if (enc_id) { - obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); - if (!obj) - return NULL; - encoder = obj_to_encoder(obj); - return encoder; - } - return NULL; -} - -static enum drm_connector_status vboxvideo_vga_detect(struct drm_connector - *connector) -{ - return connector_status_connected; -} - -static void vboxvideo_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); - kfree(connector); -} - -struct drm_connector_helper_funcs vboxvideo_vga_connector_helper_funcs = -{ - .get_modes = vboxvideo_vga_get_modes, - .mode_valid = vboxvideo_vga_mode_valid, - .best_encoder = vboxvideo_connector_best_encoder, -}; - -struct drm_connector_funcs vboxvideo_vga_connector_funcs = -{ - .dpms = drm_helper_connector_dpms, - .detect = vboxvideo_vga_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vboxvideo_connector_destroy, -}; - -struct drm_connector *vboxvideo_vga_init(struct drm_device *dev) -{ - struct drm_connector *connector; - struct vboxvideo_connector *vboxvideo_connector; - - vboxvideo_connector = kzalloc(sizeof(struct vboxvideo_connector), - GFP_KERNEL); - if (!vboxvideo_connector) - return NULL; - - connector = &vboxvideo_connector->base; - - drm_connector_init(dev, connector, - &vboxvideo_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); - - drm_connector_helper_add(connector, &vboxvideo_vga_connector_helper_funcs); - - return connector; -} - -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ diff --git a/src/VBox/Additions/linux/export_modules b/src/VBox/Additions/linux/export_modules index a8c929ed..9df93899 100755 --- a/src/VBox/Additions/linux/export_modules +++ b/src/VBox/Additions/linux/export_modules @@ -4,7 +4,7 @@ # Create a tar archive containing the sources of the Linux guest kernel # modules # -# Copyright (C) 2006-2007 Oracle Corporation +# Copyright (C) 2006-2010 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/installer/deffiles b/src/VBox/Additions/linux/installer/deffiles index 074ab224..02d54663 100644 --- a/src/VBox/Additions/linux/installer/deffiles +++ b/src/VBox/Additions/linux/installer/deffiles @@ -25,6 +25,7 @@ DEFAULT_FILE_NAMES=" \ /usr/bin/vboxadd-xclient \ /usr/bin/VBoxClient \ /usr/bin/VBoxControl \ + /usr/sbin/vbox-greeter \ /usr/sbin/vboxadd-timesync \ /usr/sbin/vboxadd-service \ /usr/sbin/VBoxService \ @@ -43,6 +44,7 @@ DEFAULT_FILE_NAMES=" \ /usr/lib64/VBoxOGLpassthroughspu.so \ /usr/lib/VBoxOGL.so \ /usr/lib64/VBoxOGL.so \ + /usr/share/xgreeters/vbox-greeter.desktop \ /etc/X11/Xsession.d/98vboxadd-xclient \ /etc/X11/xinit.d/98vboxadd-xclient \ /etc/X11/xinit/xinitrc.d/98vboxadd-xclient.sh \ diff --git a/src/VBox/Additions/linux/installer/module-autologon.sh b/src/VBox/Additions/linux/installer/module-autologon.sh new file mode 100644 index 00000000..f7262f33 --- /dev/null +++ b/src/VBox/Additions/linux/installer/module-autologon.sh @@ -0,0 +1,169 @@ +# Oracle VM VirtualBox +# VirtualBox Linux Guest Additions installer - autologon module +# + +# Copyright (C) 2012 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +# @todo Document functions and their usage! + +MOD_AUTOLOGON_DEFAULT_LIGHTDM_CONFIG="/etc/lightdm/lightdm.conf" +MOD_AUTOLOGON_DEFAULT_LIGHTDM_GREETER_DIR="/usr/share/xgreeters" + +mod_autologon_init() +{ + echo "Initializing auto-logon support ..." + return 0 +} + +mod_autologon_install_ex() +{ + info "Installing auto-logon support ..." + + ## Parameters: + # Greeter directory. Defaults to /usr/share/xgreeters. + greeter_dir="$1" + # LightDM config. Defaults to /etc/lightdm/lightdm.conf. + lightdm_config="$2" + # Whether to force installation if non-compatible distribution + # is detected. + force="$3" + + # Check for Ubuntu and derivates. @todo Debian? + distros="Ubuntu UbuntuStudio Edubuntu Kubuntu Lubuntu Mythbuntu Xubuntu" + ## @todo Map Linux Mint versions to Ubuntu ones. + + ## @todo Move the distro check to a routine / globals as soon as + ## we have other distribution-dependent stuff. + which lsb_release &>/dev/null + if test "$?" -ne "0"; then + info "Error: lsb_release not found (path set?), skipping auto-logon installation" + return 1 + fi + distro_name=$(lsb_release -si) + distro_ver=$(lsb_release -sr) + + for distro_cur in ${distros}; do + if test "$distro_name" = "$distro_cur"; then + distro_found="true" + break + fi + done + + if test -z "$distro_found"; then + if ! test "$force" = "force"; then + info "Error: Unsupported distribution \"$distro_name\" found, skipping auto-logon installation" + return 1 + fi + info "Warning: Unsupported distribution \"$distro_name\" found" + else + # Do we have Ubuntu 11.10 or greater? + # Use AWK for comparison since we run on plan sh. + echo | awk 'END { exit ( !('"$distro_ver >= 11.10"') ); }' + if test "$?" -ne "0"; then + if ! test "$force" = "force"; then + info "Error: Version $distro_ver of \"$distro_name\" not supported, skipping auto-logon installation" + return 1 + fi + info "Warning: Unsupported \"$distro_name\" version $distro_ver found" + fi + fi + + # Install dependencies (lightdm and FLTK 1.3+) using apt-get. + which apt-get &>/dev/null + if test "$?" -ne "0"; then + info "Error: apt-get not found (path set?), skipping auto-logon installation" + return 1 + fi + info "Checking and installing necessary dependencies ..." + apt-get -qqq -y install libfltk1.3 libfltk-images1.3 || return 1 + apt-get -qqq -y install lightdm || return 1 + + # Check for LightDM config. + if ! test -f "$lightdm_config"; then + info "Error: LightDM config \"$lightdm_config\" not found (LightDM installed?), skipping auto-logon installation" + return 1 + fi + + # Check for /usr/share/xgreeters. + if ! test -d "$greeter_dir"; then + if ! test "$force" = "force"; then + info "Error: Directory \"$greeter_dir\" does not exist, skipping auto-logon installation" + return 1 + fi + info "Warning: Directory \"$greeter_dir\" does not exist, creating it" + mkdir -p -m 755 "$greeter_dir" || return 1 + fi + + # Link to required greeter files into $greeter_dir. + add_symlink "$INSTALLATION_DIR/share/VBoxGuestAdditions/vbox-greeter.desktop" "$greeter_dir/vbox-greeter.desktop" + + # Backup and activate greeter config. + if ! test -f "$lightdm_config.vbox-backup"; then + info "Backing up LightDM configuration file ..." + cp "$lightdm_config" "$lightdm_config.vbox-backup" || return 1 + chmod 644 "$lightdm_config.vbox-backup" || return 1 + fi + sed -i -e 's/^\s*greeter-session\s*=.*/greeter-session=vbox-greeter/g' "$lightdm_config" || return 1 + chmod 644 "$lightdm_config" || return 1 + + info "Auto-logon installation successful" + return 0 +} + +mod_autologon_install() +{ + if [ -z "$MOD_AUTOLOGON_LIGHTDM_GREETER_DIR" ]; then + MOD_AUTOLOGON_LIGHTDM_GREETER_DIR=$MOD_AUTOLOGON_DEFAULT_LIGHTDM_GREETER_DIR + fi + if [ -z "$MOD_AUTOLOGON_LIGHTDM_CONFIG" ]; then + MOD_AUTOLOGON_LIGHTDM_CONFIG=$MOD_AUTOLOGON_DEFAULT_LIGHTDM_CONFIG + fi + + mod_autologon_install_ex "$MOD_AUTOLOGON_LIGHTDM_GREETER_DIR" "$MOD_AUTOLOGON_LIGHTDM_CONFIG" "$MOD_AUTOLOGON_FORCE" + return $? +} + +mod_autologon_pre_uninstall() +{ + echo "Preparing to uninstall auto-logon support ..." + return 0 +} + +mod_autologon_uninstall() +{ + if test -z "$MOD_AUTOLOGON_LIGHTDM_CONFIG"; then + return 0 + fi + info "Un-installing auto-logon support ..." + + # Switch back to original greeter. + if test -f "$MOD_AUTOLOGON_LIGHTDM_CONFIG.vbox-backup"; then + mv "$MOD_AUTOLOGON_LIGHTDM_CONFIG.vbox-backup" "$MOD_AUTOLOGON_LIGHTDM_CONFIG" + if test "$?" -ne "0"; then + info "Warning: Could not restore original LightDM config \"$MOD_AUTOLOGON_LIGHTDM_CONFIG\"" + fi + fi + + # Remove greeter directory (if not empty). + rm "$MOD_AUTOLOGON_LIGHTDM_GREETER_DIR" 2>/dev/null + + info "Auto-logon uninstallation successful" + return 0 +} + +mod_autologon_config_save() +{ + echo " +MOD_AUTOLOGON_LIGHTDM_CONFIG='$MOD_AUTOLOGON_LIGHTDM_CONFIG' +MOD_AUTOLOGON_LIGHTDM_GREETER_DIR='$MOD_AUTOLOGON_LIGHTDM_GREETER_DIR'" +} + diff --git a/src/VBox/Additions/linux/installer/vboxadd-service.sh b/src/VBox/Additions/linux/installer/vboxadd-service.sh index caec2111..cf30b9e4 100755 --- a/src/VBox/Additions/linux/installer/vboxadd-service.sh +++ b/src/VBox/Additions/linux/installer/vboxadd-service.sh @@ -2,7 +2,7 @@ # # Linux Additions Guest Additions service daemon init script. # -# Copyright (C) 2006-2010 Oracle Corporation +# Copyright (C) 2006-2012 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/installer/vboxadd-x11.sh b/src/VBox/Additions/linux/installer/vboxadd-x11.sh index ffa1e16d..7188e4f8 100755 --- a/src/VBox/Additions/linux/installer/vboxadd-x11.sh +++ b/src/VBox/Additions/linux/installer/vboxadd-x11.sh @@ -1,10 +1,10 @@ #! /bin/sh # -# Linux Additions X11 setup init script ($Revision: 80787 $) +# Linux Additions X11 setup init script ($Revision: 92745 $) # # -# Copyright (C) 2006-2010 Oracle Corporation +# Copyright (C) 2006-2012 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -38,22 +38,25 @@ cpu=`uname -m`; case "$cpu" in i[3456789]86|x86) cpu="x86" - LIB="/usr/lib" + lib_candidates="/usr/lib/i386-linux-gnu /usr/lib /lib" ;; x86_64|amd64) cpu="amd64" - if test -d "/usr/lib64"; then - LIB="/usr/lib64" - else - LIB="/usr/lib" - fi + lib_candidates="/usr/lib/x86_64-linux-gnu /usr/lib64 /usr/lib /lib64 /lib" ;; esac +for i in $lib_candidates; do + if test -d "$i/VBoxGuestAdditions"; then + LIB=$i + break + fi +done # Find the version of X installed # The last of the three is for the X.org 6.7 included in Fedora Core 2 xver=`X -version 2>&1` x_version=`echo "$xver" | sed -n 's/^X Window System Version \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^XFree86 Version \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^X Protocol Version 11, Revision 0, Release \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^X.Org X Server \([0-9.]\+\)/\1/p'` +x_version_short=`echo "${x_version}" | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/'` # Version of Redhat or Fedora installed. Needed for setting up selinux policy. redhat_release=`cat /etc/redhat-release 2> /dev/null` # All the different possible locations for XFree86/X.Org configuration files @@ -283,9 +286,9 @@ setup() dox11config="true" # By default, we want to run our xorg.conf setup script setupxorgconf="true" - # On all but the oldest X servers we want to use our new mouse - # driver. - newmouse="--newMouse" + # All but the oldest supported X servers can automatically set up the + # keyboard driver. + autokeyboard="--autoKeyboard" # On more recent servers our kernel mouse driver will be used # automatically automouse="--autoMouse" @@ -300,6 +303,9 @@ setup() vboxmouse_src= # The driver extension driver_ext=".so" + # The configuration file we generate if no original was found but we need + # one. + main_cfg="/etc/X11/xorg.conf" modules_dir=`X -showDefaultModulePath 2>&1` || modules_dir= if [ -z "$modules_dir" ]; then @@ -312,7 +318,11 @@ setup() fi test -z "$x_version" -o -z "$modules_dir" && - fail "Could not find the X.Org or XFree86 Window System." + { + echo + echo "Could not find the X.Org or XFree86 Window System, skipping." + exit 0 + } echo # openSUSE 10.3 shipped X.Org 7.2 with X.Org Server 1.3, but didn't @@ -328,16 +338,6 @@ setup() echo "installing the X.Org drivers." dox11config="" ;; - 1.13.* ) - xserver_version="X.Org Server 1.13" - vboxvideo_src=vboxvideo_drv_113.so - test "$system" = "redhat" || setupxorgconf="" - ;; - 1.12.* ) - xserver_version="X.Org Server 1.12" - vboxvideo_src=vboxvideo_drv_112.so - test "$system" = "redhat" || setupxorgconf="" - ;; 1.11.* ) xserver_version="X.Org Server 1.11" vboxvideo_src=vboxvideo_drv_111.so @@ -351,7 +351,7 @@ setup() 1.9.* ) xserver_version="X.Org Server 1.9" vboxvideo_src=vboxvideo_drv_19.so - # Fedora 14 and later patched out vboxvideo detection + # Fedora 14 to 16 patched out vboxvideo detection test "$system" = "redhat" || setupxorgconf="" ;; 1.8.* ) @@ -412,20 +412,39 @@ setup() automouse="" ;; 6.7* | 6.8.* | 4.2.* | 4.3.* ) - # Assume X.Org post-fork or XFree86 + # As the module binaries are the same we use one text for these + # four server versions. xserver_version="XFree86 4.2/4.3 and X.Org 6.7/6.8" driver_ext=.o vboxvideo_src=vboxvideo_drv.o vboxmouse_src=vboxmouse_drv.o automouse="" + autokeyboard="" + case $x_version in + 6.8.* ) + autokeyboard="true" + ;; + 4.2.* | 4.3.* ) + main_cfg="/etc/X11/XF86Config" + ;; + esac ;; * ) - echo "Warning: unknown version of the X Window System installed. Not installing" - echo "X Window System drivers." - dox11config="" + # Anything else, including all X server versions as of 1.12. + xserver_version="X.Org Server ${x_version_short}" + vboxvideo_src=vboxvideo_drv_`echo ${x_version_short} | sed 's/\.//'`.so + setupxorgconf="" + test -f "${lib_dir}/${vboxvideo_src}" || + { + echo "Warning: unknown version of the X Window System installed. Not installing" + echo "X Window System drivers." + dox11config="" + vboxvideo_src="" + } ;; esac - begin "Installing $xserver_version modules" + test -n "${dox11config}" && + begin "Installing $xserver_version modules" rm "$modules_dir/drivers/vboxvideo_drv$driver_ext" 2>/dev/null rm "$modules_dir/input/vboxmouse_drv$driver_ext" 2>/dev/null case "$vboxvideo_src" in ?*) @@ -458,7 +477,7 @@ setup() if grep -q "VirtualBox generated" "$i"; then generated="$generated `printf "$i\n"`" else - "$lib_dir/x11config.sh" $newmouse $automouse $nopsaux "$i" + "$lib_dir/x11config.sh" $autokeyboard $automouse $nopsaux "$i" fi configured="true" fi @@ -468,12 +487,11 @@ setup() done # X.Org Server 1.5 and 1.6 can detect hardware they know, but they # need a configuration file for VBoxVideo. - main_cfg="/etc/X11/xorg.conf" - nobak="/etc/X11/xorg.vbox.nobak" + nobak_cfg="`expr "${main_cfg}" : '\([^.]*\)'`.vbox.nobak" if test -z "$configured"; then touch "$main_cfg" - "$lib_dir/x11config.sh" $newmouse $automouse $nopsaux --noBak "$main_cfg" - touch "$nobak" + "$lib_dir/x11config.sh" $autokeyboard $automouse $nopsaux --noBak "$main_cfg" + touch "${nobak_cfg}" fi fi succ_msg @@ -540,24 +558,30 @@ EOF cleanup() { # Restore xorg.conf files as far as possible - ## List of generated files which have been changed since we generated them + # List of generated files which have been changed since we generated them newer="" - ## Are we dealing with a legacy information which didn't support + # Are we dealing with a legacy information which didn't support # uninstallation? legacy="" - ## Do any of the restored configuration files still reference our drivers? + # Do any of the restored configuration files still reference our drivers? failed="" + # Have we encountered a "nobak" configuration file which means that there + # is no original file to restore? + nobak="" test -r "$CONFIG_DIR/$CONFIG" || legacy="true" - main_cfg="/etc/X11/xorg.conf" - nobak="/etc/X11/xorg.vbox.nobak" - if test -r "$nobak"; then - test -r "$main_cfg" && - if test -n "$legacy" -o ! "$nobak" -ot "$main_cfg"; then - rm -f "$nobak" "$main_cfg" + for main_cfg in "/etc/X11/xorg.conf" "/etc/X11/XF86Config"; do + nobak_cfg="`expr "${main_cfg}" : '\([^.]*\)'`.vbox.nobak" + if test -r "${nobak_cfg}"; then + test -r "${main_cfg}" && + if test -n "${legacy}" -o ! "${nobak_cfg}" -ot "${main_cfg}"; then + rm -f "${nobak_cfg}" "${main_cfg}" else - newer="$newer`printf " $main_cfg (no original)\n"`" + newer="${newer}`printf " ${main_cfg} (no original)\n"`" fi - else + nobak="true" + fi + done + if test -n "${nobak}"; then for i in $x11conf_files; do if test -r "$i.vbox"; then if test ! "$i" -nt "$i.vbox" -o -n "$legacy"; then diff --git a/src/VBox/Additions/linux/installer/vboxadd.sh b/src/VBox/Additions/linux/installer/vboxadd.sh index 5112da1e..1eb00146 100755 --- a/src/VBox/Additions/linux/installer/vboxadd.sh +++ b/src/VBox/Additions/linux/installer/vboxadd.sh @@ -1,10 +1,10 @@ #! /bin/sh # -# Linux Additions kernel module init script ($Revision: 81678 $) +# Linux Additions kernel module init script ($Revision: 90030 $) # # -# Copyright (C) 2006-2010 Oracle Corporation +# Copyright (C) 2006-2012 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -228,6 +228,11 @@ running_vboxsf() lsmod | grep -q "vboxsf[^_-]" } +running_vboxvideo() +{ + lsmod | grep -q "vboxvideo[^_-]" +} + do_vboxguest_non_udev() { if [ ! -c $dev ]; then @@ -279,7 +284,7 @@ do_vboxguest_non_udev() start() { begin "Starting the VirtualBox Guest Additions "; - uname -r | grep -q '^2\.6' 2>/dev/null && + uname -r | grep -q -E '^2\.6|^3' 2>/dev/null && ps -A -o comm | grep -q '/*udevd$' 2>/dev/null || no_udev=1 running_vboxguest || { @@ -314,6 +319,9 @@ start() } } + # This is needed as X.Org Server 1.13 does not auto-load the module. + running_vboxvideo || $MODPROBE vboxvideo > /dev/null 2>&1 + # Mount all shared folders from /etc/fstab. Normally this is done by some # other startup script but this requires the vboxdrv kernel module loaded. # This isn't necessary anymore as the vboxsf module is autoloaded. @@ -432,7 +440,7 @@ extra_setup() # Add a group "vboxsf" for Shared Folders access # All users which want to access the auto-mounted Shared Folders have to # be added to this group. - groupadd -f vboxsf >/dev/null 2>&1 + groupadd -r -f vboxsf >/dev/null 2>&1 # Create udev description file if [ -d /etc/udev/rules.d ]; then diff --git a/src/VBox/Additions/linux/lightdm-greeter/Makefile.kmk b/src/VBox/Additions/linux/lightdm-greeter/Makefile.kmk new file mode 100644 index 00000000..79c96d89 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/Makefile.kmk @@ -0,0 +1,83 @@ +# $Id: Makefile.kmk $ +## @file +# Makefile for VBox LightDM greeter for providing automated logons. +# + +# +# Copyright (C) 2012 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +ifndef VBOX_OSE + include $(PATH_SUB_CURRENT)/liblightdm-gobject-1.5.0/Makefile.kmk +endif + +# Enable building with FLTK UI + PNG support. +VBOX_WITH_FLTK := 1 +VBOX_GREETER_WITH_PNG_SUPPORT := 1 + +# The greeter module. +PROGRAMS += vbox-greeter + +vbox-greeter_TEMPLATE = VBOXGUESTR3EXE +vbox-greeter_DEFS = LOG_TO_BACKDOOR VBOX_WITH_HGCM +vbox-greeter_DEFS += \ + VBOX_BUILD_TARGET=\"$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)\" +vbox-greeter_DEFS += \ + $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \ + $(if $(VBOX_WITH_FLTK),VBOX_WITH_FLTK,) \ + $(if $(VBOX_GREETER_WITH_PNG_SUPPORT),VBOX_GREETER_WITH_PNG_SUPPORT,) + +ifndef VBOX_WITH_FLTK + vbox-greeter_DEFS += \ + GTK_DISABLE_SINGLE_INCLUDES \ + GDK_DISABLE_DEPRECATED +endif +vbox-greeter_SOURCES = vbox-greeter.cpp +### todo: define some _INCS in Config.kmk and use 'pkg-config glib-2.0 --cflags' in configure to override +vbox-greeter_INCS = \ + /usr/lib/i386-linux-gnu/glib-2.0/include \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include \ + /usr/include/glib-2.0 \ + /usr/include/lightdm-gobject-1 +ifndef VBOX_WITH_FLTK + vbox-greeter_INCS += \ + /usr/include/glib-2.0 \ + /usr/include/gtk-3.0 \ + /usr/include/pango-1.0 \ + /usr/include/cairo \ + /usr/include/gdk-pixbuf-2.0 \ + /usr/include/atk-1.0 +endif +### todo: define some _LIBS in Config.kmk and use 'pkg-config glib-2.0 --libs' in configure to override +vbox-greeter_LIBS = \ + $(if $(VBOX_OSE),lightdm-gobject-1,$(VBOX_PATH_ADDITIONS_LIB)/VBox-liblightdm-gobject$(VBOX_SUFF_LIB)) \ + glib-2.0 \ + gio-2.0 \ + gobject-2.0 \ + $(VBOX_LIB_IPRT_GUEST_R3_SHARED) \ + $(VBOX_LIB_VBGL_R3_SHARED) \ + $(VBOX_LIB_IPRT_GUEST_R3_SHARED) +ifndef VBOX_WITH_FLTK + vbox-greeter_LIBS += gtk-3 +endif +ifdef VBOX_WITH_FLTK + #vbox-greeter_LDFLAGS = -Wl,-Bsymbolic-functions -Wl,-z,relro /usr/lib/i386-linux-gnu/libfltk.a -lXext -lXft -lfontconfig -lfontconfig -lXinerama -ldl -lm -lX11 + vbox-greeter_LDFLAGS += -s + vbox-greeter_LIBS += fltk + ifdef VBOX_GREETER_WITH_PNG_SUPPORT + vbox-greeter_LIBS += fltk_images + endif +endif + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/Additions/linux/lightdm-greeter/banner-dummy.png b/src/VBox/Additions/linux/lightdm-greeter/banner-dummy.png Binary files differnew file mode 100644 index 00000000..d74e9c1a --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/banner-dummy.png diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk new file mode 100644 index 00000000..76c0396f --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk @@ -0,0 +1,43 @@ +# $Id: Makefile.kmk $ +## @file +# Makefile for liblighdm-gobject 1.5.0 +# + +# +# Copyright (C) 2013 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +SUB_DEPTH = ../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# The greeter module. +LIBRARIES += VBox-liblightdm-gobject + +VBox-liblightdm-gobject_TEMPLATE = VBOXGUESTR3NPLIB +VBox-liblightdm-gobject_INCS = \ + /usr/include/glib-2.0 \ + /usr/lib/i386-linux-gnu/glib-2.0/include \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include \ + /usr/include/gio-unix-2.0 +VBox-liblightdm-gobject_DEFS = \ + CONFIG_DIR=\"/etc/lightdm\" \ + XSESSIONS_DIR=\"/usr/share/xsessions\" \ + REMOTE_SESSIONS_DIR=\"/usr/share/lightdm/remote-sessions\" +VBox-liblightdm-gobject_SOURCES = \ + greeter.c \ + language.c \ + layout.c \ + power.c \ + session.c \ + system.c \ + user.c + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h new file mode 100644 index 00000000..c06fc08d --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h @@ -0,0 +1,90 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Gettext package */ +#define GETTEXT_PACKAGE "lightdm" + +/* Greeter session */ +#define GREETER_SESSION "default" + +/* User to run greeter as */ +#define GREETER_USER "lightdm" + +/* Define to 1 if you have the `clearenv' function. */ +#define HAVE_CLEARENV 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the <security/pam_appl.h> header file. */ +#define HAVE_SECURITY_PAM_APPL_H 1 + +/* Define to 1 if you have the `setresgid' function. */ +#define HAVE_SETRESGID 1 + +/* Define to 1 if you have the `setresuid' function. */ +#define HAVE_SETRESUID 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "lightdm" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "lightdm" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "lightdm 1.5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "lightdm" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.5.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* User session */ +#define USER_SESSION "default" + +/* Version number of package */ +#define VERSION "1.5.0" diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c new file mode 100644 index 00000000..7964f986 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c @@ -0,0 +1,1433 @@ +/* + * Copyright (C) 2010 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <security/pam_appl.h> + +#include "lightdm/greeter.h" + +enum { + PROP_0, + PROP_DEFAULT_SESSION_HINT, + PROP_HIDE_USERS_HINT, + PROP_SHOW_MANUAL_LOGIN_HINT, + PROP_SHOW_REMOTE_LOGIN_HINT, + PROP_LOCK_HINT, + PROP_HAS_GUEST_ACCOUNT_HINT, + PROP_SELECT_USER_HINT, + PROP_SELECT_GUEST_HINT, + PROP_AUTOLOGIN_USER_HINT, + PROP_AUTOLOGIN_GUEST_HINT, + PROP_AUTOLOGIN_TIMEOUT_HINT, + PROP_AUTHENTICATION_USER, + PROP_IN_AUTHENTICATION, + PROP_IS_AUTHENTICATED, +}; + +enum { + SHOW_PROMPT, + SHOW_MESSAGE, + AUTHENTICATION_COMPLETE, + AUTOLOGIN_TIMER_EXPIRED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct +{ + gboolean connected; + + GIOChannel *to_server_channel, *from_server_channel; + guint8 *read_buffer; + gsize n_read; + + gsize n_responses_waiting; + GList *responses_received; + + GHashTable *hints; + guint autologin_timeout; + + gchar *authentication_user; + gboolean in_authentication; + gboolean is_authenticated; + guint32 authenticate_sequence_number; + gboolean cancelling_authentication; +} LightDMGreeterPrivate; + +G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT); + +#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate) + +#define HEADER_SIZE 8 +#define MAX_MESSAGE_LENGTH 1024 + +/* Messages from the greeter to the server */ +typedef enum +{ + GREETER_MESSAGE_CONNECT = 0, + GREETER_MESSAGE_AUTHENTICATE, + GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, + GREETER_MESSAGE_CONTINUE_AUTHENTICATION, + GREETER_MESSAGE_START_SESSION, + GREETER_MESSAGE_CANCEL_AUTHENTICATION, + GREETER_MESSAGE_SET_LANGUAGE, + GREETER_MESSAGE_AUTHENTICATE_REMOTE +} GreeterMessage; + +/* Messages from the server to the greeter */ +typedef enum +{ + SERVER_MESSAGE_CONNECTED = 0, + SERVER_MESSAGE_PROMPT_AUTHENTICATION, + SERVER_MESSAGE_END_AUTHENTICATION, + SERVER_MESSAGE_SESSION_RESULT +} ServerMessage; + +/** + * lightdm_greeter_new: + * + * Create a new greeter. + * + * Return value: the new #LightDMGreeter + **/ +LightDMGreeter * +lightdm_greeter_new () +{ + return g_object_new (LIGHTDM_TYPE_GREETER, NULL); +} + +static gboolean +timed_login_cb (gpointer data) +{ + LightDMGreeter *greeter = data; + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + + priv->autologin_timeout = 0; + g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0); + + return FALSE; +} + +static guint32 +int_length () +{ + return 4; +} + +static void +write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset) +{ + if (*offset + 4 >= buffer_length) + return; + buffer[*offset] = value >> 24; + buffer[*offset+1] = (value >> 16) & 0xFF; + buffer[*offset+2] = (value >> 8) & 0xFF; + buffer[*offset+3] = value & 0xFF; + *offset += 4; +} + +static void +write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset) +{ + gint length = 0; + + if (value) + length = strlen (value); + write_int (buffer, buffer_length, length, offset); + if (*offset + length >= buffer_length) + return; + memcpy (buffer + *offset, value, length); + *offset += length; +} + +static guint32 +read_int (guint8 *message, gsize message_length, gsize *offset) +{ + guint32 value; + guint8 *buffer; + + if (message_length - *offset < int_length ()) + { + g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset); + return 0; + } + + buffer = message + *offset; + value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; + *offset += int_length (); + + return value; +} + +static gchar * +read_string (guint8 *message, gsize message_length, gsize *offset) +{ + guint32 length; + gchar *value; + + length = read_int (message, message_length, offset); + if (message_length - *offset < length) + { + g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset); + return g_strdup (""); + } + + value = g_malloc (sizeof (gchar) * (length + 1)); + memcpy (value, message + *offset, length); + value[length] = '\0'; + *offset += length; + + return value; +} + +static guint32 +string_length (const gchar *value) +{ + if (value) + return int_length () + strlen (value); + else + return int_length (); +} + +static void +write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset) +{ + write_int (buffer, buffer_length, id, offset); + write_int (buffer, buffer_length, length, offset); +} + +static guint32 +get_message_length (guint8 *message, gsize message_length) +{ + gsize offset = 4; + return read_int (message, message_length, &offset); +} + +static void +write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + GIOStatus status; + GError *error = NULL; + guint32 stated_length; + + /* Double check that we're sending well-formed messages. If we say we're + sending more than we do, we end up DOS'ing lightdm as it waits for the + rest. If we say we're sending less than we do, we confuse the heck out + of lightdm, as it starts reading headers from the middle of our + messages. */ + stated_length = HEADER_SIZE + get_message_length (message, message_length); + if (stated_length != message_length) + { + g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length); + return; + } + + status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error); + if (error) + g_warning ("Error writing to daemon: %s", error->message); + g_clear_error (&error); + if (status == G_IO_STATUS_NORMAL) + g_debug ("Wrote %zi bytes to daemon", message_length); + g_io_channel_flush (priv->to_server_channel, NULL); +} + +static void +handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + gchar *version; + GString *hint_string; + int timeout; + + version = read_string (message, message_length, offset); + hint_string = g_string_new (""); + while (*offset < message_length) + { + gchar *name, *value; + + name = read_string (message, message_length, offset); + value = read_string (message, message_length, offset); + g_hash_table_insert (priv->hints, name, value); + g_string_append_printf (hint_string, " %s=%s", name, value); + } + + g_debug ("Connected version=%s%s", version, hint_string->str); + g_free (version); + g_string_free (hint_string, TRUE); + + /* Set timeout for default login */ + timeout = lightdm_greeter_get_autologin_timeout_hint (greeter); + if (timeout) + { + g_debug ("Setting autologin timer for %d seconds", timeout); + priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter); + } +} + +static void +handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + guint32 sequence_number, n_messages, i; + gchar *username; + + sequence_number = read_int (message, message_length, offset); + if (sequence_number != priv->authenticate_sequence_number) + { + g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number); + return; + } + + if (priv->cancelling_authentication) + { + g_debug ("Ignoring prompt authentication as waiting for it to cancel"); + return; + } + + /* Update username */ + username = read_string (message, message_length, offset); + if (strcmp (username, "") == 0) + { + g_free (username); + username = NULL; + } + g_free (priv->authentication_user); + priv->authentication_user = username; + + g_list_free_full (priv->responses_received, g_free); + priv->responses_received = NULL; + priv->n_responses_waiting = 0; + + n_messages = read_int (message, message_length, offset); + g_debug ("Prompt user with %d message(s)", n_messages); + + for (i = 0; i < n_messages; i++) + { + int style; + gchar *text; + + style = read_int (message, message_length, offset); + text = read_string (message, message_length, offset); + + // FIXME: Should stop on prompts? + switch (style) + { + case PAM_PROMPT_ECHO_OFF: + priv->n_responses_waiting++; + g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET); + break; + case PAM_PROMPT_ECHO_ON: + priv->n_responses_waiting++; + g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION); + break; + case PAM_ERROR_MSG: + g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR); + break; + case PAM_TEXT_INFO: + g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO); + break; + } + + g_free (text); + } +} + +static void +handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + guint32 sequence_number, return_code; + gchar *username; + + sequence_number = read_int (message, message_length, offset); + + if (sequence_number != priv->authenticate_sequence_number) + { + g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number); + return; + } + + username = read_string (message, message_length, offset); + return_code = read_int (message, message_length, offset); + + g_debug ("Authentication complete for user %s with return code %d", username, return_code); + + /* Update username */ + if (strcmp (username, "") == 0) + { + g_free (username); + username = NULL; + } + g_free (priv->authentication_user); + priv->authentication_user = username; + + priv->cancelling_authentication = FALSE; + priv->is_authenticated = (return_code == 0); + + priv->in_authentication = FALSE; + g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0); +} + +static guint8 * +read_message (LightDMGreeter *greeter, gsize *length, gboolean block) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + gsize n_to_read, n_read; + guint8 *buffer; + GError *error = NULL; + + /* Read the header, or the whole message if we already have that */ + n_to_read = HEADER_SIZE; + if (priv->n_read >= HEADER_SIZE) + n_to_read += get_message_length (priv->read_buffer, priv->n_read); + + do + { + GIOStatus status; + status = g_io_channel_read_chars (priv->from_server_channel, + (gchar *) priv->read_buffer + priv->n_read, + n_to_read - priv->n_read, + &n_read, + &error); + if (error) + g_warning ("Error reading from server: %s", error->message); + g_clear_error (&error); + if (status != G_IO_STATUS_NORMAL) + break; + + g_debug ("Read %zi bytes from daemon", n_read); + + priv->n_read += n_read; + } while (priv->n_read < n_to_read && block); + + /* Stop if haven't got all the data we want */ + if (priv->n_read != n_to_read) + return FALSE; + + /* If have header, rerun for content */ + if (priv->n_read == HEADER_SIZE) + { + n_to_read = get_message_length (priv->read_buffer, priv->n_read); + if (n_to_read > 0) + { + priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read); + return read_message (greeter, length, block); + } + } + + buffer = priv->read_buffer; + *length = priv->n_read; + + priv->read_buffer = g_malloc (priv->n_read); + priv->n_read = 0; + + return buffer; +} + +static gboolean +from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) +{ + LightDMGreeter *greeter = data; + guint8 *message; + gsize message_length, offset; + guint32 id; + + message = read_message (greeter, &message_length, FALSE); + if (!message) + return TRUE; + + offset = 0; + id = read_int (message, message_length, &offset); + read_int (message, message_length, &offset); + switch (id) + { + case SERVER_MESSAGE_PROMPT_AUTHENTICATION: + handle_prompt_authentication (greeter, message, message_length, &offset); + break; + case SERVER_MESSAGE_END_AUTHENTICATION: + handle_end_authentication (greeter, message, message_length, &offset); + break; + default: + g_warning ("Unknown message from server: %d", id); + break; + } + g_free (message); + + return TRUE; +} + +/** + * lightdm_greeter_connect_sync: + * @greeter: The greeter to connect + * @error: return location for a #GError, or %NULL + * + * Connects the greeter to the display manager. Will block until connected. + * + * Return value: #TRUE if successfully connected + **/ +gboolean +lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error) +{ + LightDMGreeterPrivate *priv; + const gchar *fd; + guint8 message[MAX_MESSAGE_LENGTH]; + guint8 *response; + gsize response_length, offset = 0; + guint32 id; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + + priv = GET_PRIVATE (greeter); + + fd = g_getenv ("LIGHTDM_TO_SERVER_FD"); + if (!fd) + { + g_warning ("No LIGHTDM_TO_SERVER_FD environment variable"); + return FALSE; + } + priv->to_server_channel = g_io_channel_unix_new (atoi (fd)); + g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL); + + fd = g_getenv ("LIGHTDM_FROM_SERVER_FD"); + if (!fd) + { + g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable"); + return FALSE; + } + priv->from_server_channel = g_io_channel_unix_new (atoi (fd)); + g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL); + g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter); + + g_debug ("Connecting to display manager..."); + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset); + write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset); + write_message (greeter, message, offset); + + response = read_message (greeter, &response_length, TRUE); + if (!response) + return FALSE; + + offset = 0; + id = read_int (response, response_length, &offset); + read_int (response, response_length, &offset); + if (id == SERVER_MESSAGE_CONNECTED) + handle_connected (greeter, response, response_length, &offset); + g_free (response); + if (id != SERVER_MESSAGE_CONNECTED) + { + g_warning ("Expected CONNECTED message, got %d", id); + return FALSE; + } + + priv->connected = TRUE; + + return TRUE; +} + +/** + * lightdm_greeter_get_hint: + * @greeter: A #LightDMGreeter + * @name: The hint name to query. + * + * Get a hint. + * + * Return value: The value for this hint or #NULL if not set. + **/ +const gchar * +lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); + return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name); +} + +/** + * lightdm_greeter_get_default_session_hint: + * @greeter: A #LightDMGreeter + * + * Get the default session to use. + * + * Return value: The session name + **/ +const gchar * +lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); + return lightdm_greeter_get_hint (greeter, "default-session"); +} + +/** + * lightdm_greeter_get_hide_users_hint: + * @greeter: A #LightDMGreeter + * + * Check if user accounts should be shown. If this is TRUE then the list of + * accounts should be taken from #LightDMUserList and displayed in the greeter + * for the user to choose from. Note that this list can be empty and it is + * recommended you show a method for the user to enter a username manually. + * + * If this option is shown the greeter should only allow these users to be + * chosen for login unless the manual login hint is set. + * + * Return value: #TRUE if the available users should not be shown. + */ +gboolean +lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "hide-users"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_show_manual_login_hint: + * @greeter: A #LightDMGreeter + * + * Check if a manual login option should be shown. If set the GUI + * should provide a way for a username to be entered manually. + * Without this hint a greeter which is showing a user list can + * limit logins to only those users. + * + * Return value: #TRUE if a manual login option should be shown. + */ +gboolean +lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "show-manual-login"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_show_remote_login_hint: + * @greeter: A #LightDMGreeter + * + * Check if a remote login option should be shown. If set the GUI + * should provide a way for a user to log into a remote desktop server. + * + * Return value: #TRUE if a remote login option should be shown. + */ +gboolean +lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "show-remote-login"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_lock_hint: + * @greeter: A #LightDMGreeter + * + * Check if the greeter is acting as a lock screen. + * + * Return value: #TRUE if the greeter was triggered by locking the seat. + */ +gboolean +lightdm_greeter_get_lock_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "lock-screen"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_has_guest_account_hint: + * @greeter: A #LightDMGreeter + * + * Check if guest sessions are supported. + * + * Return value: #TRUE if guest sessions are supported. + */ +gboolean +lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "has-guest-account"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_select_user_hint: + * @greeter: A #LightDMGreeter + * + * Get the user to select by default. + * + * Return value: A username + */ +const gchar * +lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); + return lightdm_greeter_get_hint (greeter, "select-user"); +} + +/** + * lightdm_greeter_get_select_guest_hint: + * @greeter: A #LightDMGreeter + * + * Check if the guest account should be selected by default. + * + * Return value: #TRUE if the guest account should be selected by default. + */ +gboolean +lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "select-guest"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_autologin_user_hint: + * @greeter: A #LightDMGreeter + * + * Get the user account to automatically logg into when the timer expires. + * + * Return value: The user account to automatically log into. + */ +const gchar * +lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); + return lightdm_greeter_get_hint (greeter, "autologin-user"); +} + +/** + * lightdm_greeter_get_autologin_guest_hint: + * @greeter: A #LightDMGreeter + * + * Check if the guest account should be automatically logged into when the timer expires. + * + * Return value: #TRUE if the guest account should be automatically logged into. + */ +gboolean +lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter) +{ + const gchar *value; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "autologin-guest"); + + return g_strcmp0 (value, "true") == 0; +} + +/** + * lightdm_greeter_get_autologin_timeout_hint: + * @greeter: A #LightDMGreeter + * + * Get the number of seconds to wait before automaitcally logging in. + * + * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout. + */ +gint +lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter) +{ + const gchar *value; + gint timeout = 0; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + value = lightdm_greeter_get_hint (greeter, "autologin-timeout"); + if (value) + timeout = atoi (value); + if (timeout < 0) + timeout = 0; + + return timeout; +} + +/** + * lightdm_greeter_cancel_autologin: + * @greeter: A #LightDMGreeter + * + * Cancel the automatic login. + */ +void +lightdm_greeter_cancel_autologin (LightDMGreeter *greeter) +{ + LightDMGreeterPrivate *priv; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + if (priv->autologin_timeout) + g_source_remove (priv->autologin_timeout); + priv->autologin_timeout = 0; +} + +/** + * lightdm_greeter_authenticate: + * @greeter: A #LightDMGreeter + * @username: (allow-none): A username or #NULL to prompt for a username. + * + * Starts the authentication procedure for a user. + **/ +void +lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + priv->cancelling_authentication = FALSE; + priv->authenticate_sequence_number++; + priv->in_authentication = TRUE; + priv->is_authenticated = FALSE; + if (username != priv->authentication_user) + { + g_free (priv->authentication_user); + priv->authentication_user = g_strdup (username); + } + + g_debug ("Starting authentication for user %s...", username); + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset); + write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); + write_string (message, MAX_MESSAGE_LENGTH, username, &offset); + write_message (greeter, message, offset); +} + +/** + * lightdm_greeter_authenticate_as_guest: + * @greeter: A #LightDMGreeter + * + * Starts the authentication procedure for the guest user. + **/ +void +lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + priv->cancelling_authentication = FALSE; + priv->authenticate_sequence_number++; + priv->in_authentication = TRUE; + priv->is_authenticated = FALSE; + g_free (priv->authentication_user); + priv->authentication_user = NULL; + + g_debug ("Starting authentication for guest account..."); + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset); + write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); + write_message (greeter, message, offset); +} + +/** + * lightdm_greeter_authenticate_autologin: + * @greeter: A #LightDMGreeter + * + * Starts the authentication procedure for the automatic login user. + **/ +void +lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter) +{ + const gchar *user; + + user = lightdm_greeter_get_autologin_user_hint (greeter); + if (lightdm_greeter_get_autologin_guest_hint (greeter)) + lightdm_greeter_authenticate_as_guest (greeter); + else if (user) + lightdm_greeter_authenticate (greeter, user); +} + +/** + * lightdm_greeter_authenticate_remote: + * @greeter: A #LightDMGreeter + * @session: The name of a remote session + * @username: (allow-none): A username of #NULL to prompt for a username. + * + * Start authentication for a remote session type. + **/ +void +lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + priv->cancelling_authentication = FALSE; + priv->authenticate_sequence_number++; + priv->in_authentication = TRUE; + priv->is_authenticated = FALSE; + g_free (priv->authentication_user); + priv->authentication_user = NULL; + + if (username) + g_debug ("Starting authentication for remote session %s as user %s...", session, username); + else + g_debug ("Starting authentication for remote session %s...", session); + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset); + write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); + write_string (message, MAX_MESSAGE_LENGTH, session, &offset); + write_string (message, MAX_MESSAGE_LENGTH, username, &offset); + write_message (greeter, message, offset); +} + +/** + * lightdm_greeter_respond: + * @greeter: A #LightDMGreeter + * @response: Response to a prompt + * + * Provide response to a prompt. May be one in a series. + **/ +void +lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + g_return_if_fail (response != NULL); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + g_return_if_fail (priv->n_responses_waiting > 0); + + priv->n_responses_waiting--; + priv->responses_received = g_list_append (priv->responses_received, g_strdup (response)); + + if (priv->n_responses_waiting == 0) + { + guint32 msg_length; + GList *iter; + + g_debug ("Providing response to display manager"); + + msg_length = int_length (); + for (iter = priv->responses_received; iter; iter = iter->next) + { + msg_length += string_length ((gchar *)iter->data); + } + + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset); + write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset); + for (iter = priv->responses_received; iter; iter = iter->next) + { + write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset); + } + write_message (greeter, message, offset); + + g_list_free_full (priv->responses_received, g_free); + priv->responses_received = NULL; + } +} + +/** + * lightdm_greeter_cancel_authentication: + * @greeter: A #LightDMGreeter + * + * Cancel the current user authentication. + **/ +void +lightdm_greeter_cancel_authentication (LightDMGreeter *greeter) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + priv->cancelling_authentication = TRUE; + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset); + write_message (greeter, message, offset); +} + +/** + * lightdm_greeter_get_in_authentication: + * @greeter: A #LightDMGreeter + * + * Checks if the greeter is in the process of authenticating. + * + * Return value: #TRUE if the greeter is authenticating a user. + **/ +gboolean +lightdm_greeter_get_in_authentication (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + return GET_PRIVATE (greeter)->in_authentication; +} + +/** + * lightdm_greeter_get_is_authenticated: + * @greeter: A #LightDMGreeter + * + * Checks if the greeter has successfully authenticated. + * + * Return value: #TRUE if the greeter is authenticated for login. + **/ +gboolean +lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + return GET_PRIVATE (greeter)->is_authenticated; +} + +/** + * lightdm_greeter_get_authentication_user: + * @greeter: A #LightDMGreeter + * + * Get the user that is being authenticated. + * + * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress. + */ +const gchar * +lightdm_greeter_get_authentication_user (LightDMGreeter *greeter) +{ + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); + return GET_PRIVATE (greeter)->authentication_user; +} + +/** + * lightdm_greeter_set_language: + * @greeter: A #LightDMGreeter + * @language: The language to use for this user. + * + * Set the language for the currently authenticated user. + **/ +void +lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset); + write_string (message, MAX_MESSAGE_LENGTH, language, &offset); + write_message (greeter, message, offset); +} + +/** + * lightdm_greeter_start_session_sync: + * @greeter: A #LightDMGreeter + * @session: (allow-none): The session to log into or #NULL to use the default. + * @error: return location for a #GError, or %NULL + * + * Start a session for the authenticated user. + * + * Return value: TRUE if the session was started. + **/ +gboolean +lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + guint8 *response; + gsize response_length, offset = 0; + guint32 id, return_code = 1; + + g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); + + priv = GET_PRIVATE (greeter); + + g_return_val_if_fail (priv->connected, FALSE); + g_return_val_if_fail (priv->is_authenticated, FALSE); + + if (session) + g_debug ("Starting session %s", session); + else + g_debug ("Starting default session"); + + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset); + write_string (message, MAX_MESSAGE_LENGTH, session, &offset); + write_message (greeter, message, offset); + + response = read_message (greeter, &response_length, TRUE); + if (!response) + return FALSE; + + offset = 0; + id = read_int (response, response_length, &offset); + read_int (response, response_length, &offset); + if (id == SERVER_MESSAGE_SESSION_RESULT) + return_code = read_int (response, response_length, &offset); + else + g_warning ("Expected SESSION_RESULT message, got %d", id); + + g_free (response); + + return return_code == 0; +} + +static void +lightdm_greeter_init (LightDMGreeter *greeter) +{ + LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); + + priv->read_buffer = g_malloc (HEADER_SIZE); + priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +static void +lightdm_greeter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +lightdm_greeter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMGreeter *self; + + self = LIGHTDM_GREETER (object); + + switch (prop_id) { + case PROP_DEFAULT_SESSION_HINT: + g_value_set_string (value, lightdm_greeter_get_default_session_hint (self)); + break; + case PROP_HIDE_USERS_HINT: + g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self)); + break; + case PROP_SHOW_MANUAL_LOGIN_HINT: + g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self)); + break; + case PROP_SHOW_REMOTE_LOGIN_HINT: + g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self)); + break; + case PROP_LOCK_HINT: + g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self)); + break; + case PROP_HAS_GUEST_ACCOUNT_HINT: + g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self)); + break; + case PROP_SELECT_USER_HINT: + g_value_set_string (value, lightdm_greeter_get_select_user_hint (self)); + break; + case PROP_SELECT_GUEST_HINT: + g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self)); + break; + case PROP_AUTOLOGIN_USER_HINT: + g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self)); + break; + case PROP_AUTOLOGIN_GUEST_HINT: + g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self)); + break; + case PROP_AUTOLOGIN_TIMEOUT_HINT: + g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self)); + break; + case PROP_AUTHENTICATION_USER: + g_value_set_string (value, lightdm_greeter_get_authentication_user (self)); + break; + case PROP_IN_AUTHENTICATION: + g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self)); + break; + case PROP_IS_AUTHENTICATED: + g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +marshal_VOID__STRING_INT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1, + gpointer arg_1, + gint arg_2, + gpointer data2); + register GMarshalFunc_VOID__STRING_INT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + (param_values + 1)->data[0].v_pointer, + (param_values + 2)->data[0].v_int, + data2); +} + +static void +lightdm_greeter_finalize (GObject *object) +{ + LightDMGreeter *self = LIGHTDM_GREETER (object); + LightDMGreeterPrivate *priv = GET_PRIVATE (self); + + if (priv->to_server_channel) + g_io_channel_unref (priv->to_server_channel); + if (priv->from_server_channel) + g_io_channel_unref (priv->from_server_channel); + g_free (priv->authentication_user); + g_hash_table_unref (priv->hints); + + G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object); +} + +static void +lightdm_greeter_class_init (LightDMGreeterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate)); + + object_class->set_property = lightdm_greeter_set_property; + object_class->get_property = lightdm_greeter_get_property; + object_class->finalize = lightdm_greeter_finalize; + + g_object_class_install_property (object_class, + PROP_DEFAULT_SESSION_HINT, + g_param_spec_string ("default-session-hint", + "default-session-hint", + "Default session hint", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_HIDE_USERS_HINT, + g_param_spec_boolean ("hide-users-hint", + "hide-users-hint", + "Hide users hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_SHOW_MANUAL_LOGIN_HINT, + g_param_spec_boolean ("show-manual-login-hint", + "show-manual-login-hint", + "Show manual login hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_SHOW_REMOTE_LOGIN_HINT, + g_param_spec_boolean ("show-remote-login-hint", + "show-remote-login-hint", + "Show remote login hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_LOCK_HINT, + g_param_spec_boolean ("lock-hint", + "lock-hint", + "Lock hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_HAS_GUEST_ACCOUNT_HINT, + g_param_spec_boolean ("has-guest-account-hint", + "has-guest-account-hint", + "Has guest account hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_SELECT_USER_HINT, + g_param_spec_string ("select-user-hint", + "select-user-hint", + "Select user hint", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_SELECT_GUEST_HINT, + g_param_spec_boolean ("select-guest-hint", + "select-guest-hint", + "Select guest account hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_AUTOLOGIN_USER_HINT, + g_param_spec_string ("autologin-user-hint", + "autologin-user-hint", + "Autologin user hint", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_AUTOLOGIN_GUEST_HINT, + g_param_spec_boolean ("autologin-guest-hint", + "autologin-guest-hint", + "Autologin guest account hint", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_AUTOLOGIN_TIMEOUT_HINT, + g_param_spec_int ("autologin-timeout-hint", + "autologin-timeout-hint", + "Autologin timeout hint", + 0, G_MAXINT, 0, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_AUTHENTICATION_USER, + g_param_spec_string ("authentication-user", + "authentication-user", + "The user being authenticated", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_IN_AUTHENTICATION, + g_param_spec_boolean ("in-authentication", + "in-authentication", + "TRUE if a user is being authenticated", + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_IS_AUTHENTICATED, + g_param_spec_boolean ("is-authenticated", + "is-authenticated", + "TRUE if the selected user is authenticated", + FALSE, + G_PARAM_READABLE)); + + /** + * LightDMGreeter::show-prompt: + * @greeter: A #LightDMGreeter + * @text: Prompt text + * @type: Prompt type + * + * The ::show-prompt signal gets emitted when the greeter should show a + * prompt to the user. The given text should be displayed and an input + * field for the user to provide a response. + * + * Call lightdm_greeter_respond() with the resultant input or + * lightdm_greeter_cancel_authentication() to abort the authentication. + **/ + signals[SHOW_PROMPT] = + g_signal_new ("show-prompt", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt), + NULL, NULL, + marshal_VOID__STRING_INT, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); + + /** + * LightDMGreeter::show-message: + * @greeter: A #LightDMGreeter + * @text: Message text + * @type: Message type + * + * The ::show-message signal gets emitted when the greeter + * should show a message to the user. + **/ + signals[SHOW_MESSAGE] = + g_signal_new ("show-message", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, show_message), + NULL, NULL, + marshal_VOID__STRING_INT, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); + + /** + * LightDMGreeter::authentication-complete: + * @greeter: A #LightDMGreeter + * + * The ::authentication-complete signal gets emitted when the greeter + * has completed authentication. + * + * Call lightdm_greeter_get_is_authenticated() to check if the authentication + * was successful. + **/ + signals[AUTHENTICATION_COMPLETE] = + g_signal_new ("authentication-complete", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * LightDMGreeter::autologin-timer-expired: + * @greeter: A #LightDMGreeter + * + * The ::timed-login signal gets emitted when the automatic login timer has expired. + * The application should then call lightdm_greeter_login(). + **/ + signals[AUTOLOGIN_TIMER_EXPIRED] = + g_signal_new ("autologin-timer-expired", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c new file mode 100644 index 00000000..cc7e26f5 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2010 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include <string.h> +#include <locale.h> +#include <langinfo.h> +#include <stdio.h> +#include <glib/gi18n.h> + +#include "lightdm/language.h" + +enum { + PROP_0, + PROP_CODE, + PROP_NAME, + PROP_TERRITORY +}; + +typedef struct +{ + gchar *code; + gchar *name; + gchar *territory; +} LightDMLanguagePrivate; + +G_DEFINE_TYPE (LightDMLanguage, lightdm_language, G_TYPE_OBJECT); + +#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LANGUAGE, LightDMLanguagePrivate) + +static gboolean have_languages = FALSE; +static GList *languages = NULL; + +static void +update_languages (void) +{ + gchar *command = "locale -a"; + gchar *stdout_text = NULL, *stderr_text = NULL; + gint exit_status; + gboolean result; + GError *error = NULL; + + if (have_languages) + return; + + result = g_spawn_command_line_sync (command, &stdout_text, &stderr_text, &exit_status, &error); + if (error) + { + g_warning ("Failed to run '%s': %s", command, error->message); + g_clear_error (&error); + } + else if (exit_status != 0) + g_warning ("Failed to get languages, '%s' returned %d", command, exit_status); + else if (result) + { + gchar **tokens; + int i; + + tokens = g_strsplit_set (stdout_text, "\n\r", -1); + for (i = 0; tokens[i]; i++) + { + LightDMLanguage *language; + gchar *code; + + code = g_strchug (tokens[i]); + if (code[0] == '\0') + continue; + + /* Ignore the non-interesting languages */ + if (strcmp (command, "locale -a") == 0 && !g_strrstr (code, ".utf8")) + continue; + + language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL); + languages = g_list_append (languages, language); + } + + g_strfreev (tokens); + } + + g_free (stdout_text); + g_free (stderr_text); + + have_languages = TRUE; +} + +static gboolean +is_utf8 (const gchar *code) +{ + return g_strrstr (code, ".utf8") || g_strrstr (code, ".UTF-8"); +} + +/* Get a valid locale name that can be passed to setlocale(), so we always can use nl_langinfo() to get language and country names. */ +static gchar * +get_locale_name (const gchar *code) +{ + gchar *locale = NULL, *language; + char *at; + static gchar **avail_locales; + gint i; + + if (is_utf8 (code)) + return (gchar *) code; + + if ((at = strchr (code, '@'))) + language = g_strndup (code, at - code); + else + language = g_strdup (code); + + if (!avail_locales) + { + gchar *locales; + GError *error = NULL; + + if (g_spawn_command_line_sync ("locale -a", &locales, NULL, NULL, &error)) + { + avail_locales = g_strsplit (g_strchomp (locales), "\n", -1); + g_free (locales); + } + else + { + g_warning ("Failed to run 'locale -a': %s", error->message); + g_clear_error (&error); + } + } + + if (avail_locales) + { + for (i = 0; avail_locales[i]; i++) + { + gchar *loc = avail_locales[i]; + if (!g_strrstr (loc, ".utf8")) + continue; + if (g_str_has_prefix (loc, language)) + { + locale = g_strdup (loc); + break; + } + } + } + + g_free (language); + + return locale; +} + +/** + * lightdm_get_language: + * + * Get the current language. + * + * Return value: (transfer none): The current language or #NULL if no language. + **/ +LightDMLanguage * +lightdm_get_language (void) +{ + const gchar *lang; + GList *link; + + lang = g_getenv ("LANG"); + if (!lang) + return NULL; + + for (link = lightdm_get_languages (); link; link = link->next) + { + LightDMLanguage *language = link->data; + if (lightdm_language_matches (language, lang)) + return language; + } + + return NULL; +} + +/** + * lightdm_get_languages: + * + * Get a list of languages to present to the user. + * + * Return value: (element-type LightDMLanguage) (transfer none): A list of #LightDMLanguage that should be presented to the user. + **/ +GList * +lightdm_get_languages (void) +{ + update_languages (); + return languages; +} + +/** + * lightdm_language_get_code: + * @language: A #LightDMLanguage + * + * Get the code of a language. + * + * Return value: The code of the language + **/ +const gchar * +lightdm_language_get_code (LightDMLanguage *language) +{ + g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL); + return GET_PRIVATE (language)->code; +} + +/** + * lightdm_language_get_name: + * @language: A #LightDMLanguage + * + * Get the name of a language. + * + * Return value: The name of the language + **/ +const gchar * +lightdm_language_get_name (LightDMLanguage *language) +{ + LightDMLanguagePrivate *priv; + + g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL); + + priv = GET_PRIVATE (language); + + if (!priv->name) + { + gchar *locale = get_locale_name (priv->code); + if (locale) + { + gchar *current = setlocale (LC_ALL, NULL); + setlocale (LC_IDENTIFICATION, locale); + setlocale (LC_MESSAGES, ""); + + gchar *language_en = nl_langinfo (_NL_IDENTIFICATION_LANGUAGE); + if (language_en && strlen (language_en) > 0) + priv->name = g_strdup (dgettext ("iso_639_3", language_en)); + + setlocale (LC_ALL, current); + } + if (!priv->name) + { + gchar **tokens = g_strsplit_set (priv->code, "_.@", 2); + priv->name = g_strdup (tokens[0]); + g_strfreev (tokens); + } + } + + return priv->name; +} + +/** + * lightdm_language_get_territory: + * @language: A #LightDMLanguage + * + * Get the territory the language is used in. + * + * Return value: The territory the language is used in. + **/ +const gchar * +lightdm_language_get_territory (LightDMLanguage *language) +{ + LightDMLanguagePrivate *priv; + + g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL); + + priv = GET_PRIVATE (language); + + if (!priv->territory && strchr (priv->code, '_')) + { + gchar *locale = get_locale_name (priv->code); + if (locale) + { + gchar *current = setlocale (LC_ALL, NULL); + setlocale (LC_IDENTIFICATION, locale); + setlocale (LC_MESSAGES, ""); + + gchar *country_en = nl_langinfo (_NL_IDENTIFICATION_TERRITORY); + if (country_en && strlen (country_en) > 0 && g_strcmp0 (country_en, "ISO") != 0) + priv->territory = g_strdup (dgettext ("iso_3166", country_en)); + + setlocale (LC_ALL, current); + } + if (!priv->territory) + { + gchar **tokens = g_strsplit_set (priv->code, "_.@", 3); + priv->territory = g_strdup (tokens[1]); + g_strfreev (tokens); + } + } + + return priv->territory; +} + +/** + * lightdm_language_matches: + * @language: A #LightDMLanguage + * @code: A language code + * + * Check if a language code matches this language. + * + * Return value: #TRUE if the code matches this language. + **/ +gboolean +lightdm_language_matches (LightDMLanguage *language, const gchar *code) +{ + LightDMLanguagePrivate *priv; + + g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), FALSE); + g_return_val_if_fail (code != NULL, FALSE); + + priv = GET_PRIVATE (language); + + /* Handle the fact the UTF-8 is specified both as '.utf8' and '.UTF-8' */ + if (is_utf8 (priv->code) && is_utf8 (code)) + { + /* Match the characters before the '.' */ + int i; + for (i = 0; priv->code[i] && code[i] && priv->code[i] == code[i] && code[i] != '.' ; i++); + return priv->code[i] == '.' && code[i] == '.'; + } + + return g_str_equal (priv->code, code); +} + +static void +lightdm_language_init (LightDMLanguage *language) +{ +} + +static void +lightdm_language_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + LightDMLanguage *self = LIGHTDM_LANGUAGE (object); + LightDMLanguagePrivate *priv = GET_PRIVATE (self); + + switch (prop_id) { + case PROP_CODE: + g_free (priv->name); + priv->code = g_strdup (g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_language_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMLanguage *self; + + self = LIGHTDM_LANGUAGE (object); + + switch (prop_id) { + case PROP_CODE: + g_value_set_string (value, lightdm_language_get_code (self)); + break; + case PROP_NAME: + g_value_set_string (value, lightdm_language_get_name (self)); + break; + case PROP_TERRITORY: + g_value_set_string (value, lightdm_language_get_territory (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_language_class_init (LightDMLanguageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMLanguagePrivate)); + + object_class->set_property = lightdm_language_set_property; + object_class->get_property = lightdm_language_get_property; + + g_object_class_install_property (object_class, + PROP_CODE, + g_param_spec_string ("code", + "code", + "Language code", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "Name of the language", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_TERRITORY, + g_param_spec_string ("territory", + "territory", + "Territory the language is from", + NULL, + G_PARAM_READABLE)); +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c new file mode 100644 index 00000000..eb2b8544 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c @@ -0,0 +1,335 @@ +/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*- + * + * Copyright (C) 2010 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include <libxklavier/xklavier.h> + +#include "lightdm/layout.h" + +enum { + PROP_0, + PROP_NAME, + PROP_SHORT_DESCRIPTION, + PROP_DESCRIPTION +}; + +typedef struct +{ + gchar *name; + gchar *short_description; + gchar *description; +} LightDMLayoutPrivate; + +G_DEFINE_TYPE (LightDMLayout, lightdm_layout, G_TYPE_OBJECT); + +#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LAYOUT, LightDMLayoutPrivate) + +static gboolean have_layouts = FALSE; +static Display *display = NULL; +static XklEngine *xkl_engine = NULL; +static XklConfigRec *xkl_config = NULL; +static GList *layouts = NULL; +static LightDMLayout *default_layout = NULL; + +static gchar * +make_layout_string (const gchar *layout, const gchar *variant) +{ + if (!layout || layout[0] == 0) + return NULL; + else if (!variant || variant[0] == 0) + return g_strdup (layout); + else + return g_strdup_printf ("%s\t%s", layout, variant); +} + +static void +parse_layout_string (const gchar *name, gchar **layout, gchar **variant) +{ + gchar **split; + + *layout = NULL; + *variant = NULL; + + if (!name) + return; + + split = g_strsplit (name, "\t", 2); + if (split[0]) + { + *layout = g_strdup (split[0]); + if (split[1]) + *variant = g_strdup (split[1]); + } + g_strfreev (split); +} + +static void +variant_cb (XklConfigRegistry *config, + const XklConfigItem *item, + gpointer data) +{ + LightDMLayout *layout; + gchar *full_name; + + full_name = make_layout_string (data, item->name); + + layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", full_name, "short-description", item->short_description, "description", item->description, NULL); + layouts = g_list_append (layouts, layout); + + g_free (full_name); +} + +static void +layout_cb (XklConfigRegistry *config, + const XklConfigItem *item, + gpointer data) +{ + LightDMLayout *layout; + + layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", item->name, "short-description", item->short_description, "description", item->description, NULL); + layouts = g_list_append (layouts, layout); + + xkl_config_registry_foreach_layout_variant (config, item->name, variant_cb, (gpointer) item->name); +} + +/** + * lightdm_get_layouts: + * + * Get a list of keyboard layouts to present to the user. + * + * Return value: (element-type LightDMLayout) (transfer none): A list of #LightDMLayout that should be presented to the user. + **/ +GList * +lightdm_get_layouts (void) +{ + XklConfigRegistry *registry; + + if (have_layouts) + return layouts; + + display = XOpenDisplay (NULL); + xkl_engine = xkl_engine_get_instance (display); + xkl_config = xkl_config_rec_new (); + if (!xkl_config_rec_get_from_server (xkl_config, xkl_engine)) + g_warning ("Failed to get Xkl configuration from server"); + + registry = xkl_config_registry_get_instance (xkl_engine); + xkl_config_registry_load (registry, FALSE); + xkl_config_registry_foreach_layout (registry, layout_cb, NULL); + g_object_unref (registry); + + have_layouts = TRUE; + + return layouts; +} + +/** + * lightdm_set_layout: + * @layout: The layout to use + * + * Set the layout for this session. + **/ +void +lightdm_set_layout (LightDMLayout *dmlayout) +{ + XklConfigRec *config; + gchar *layout, *variant; + + g_return_if_fail (dmlayout != NULL); + + g_debug ("Setting keyboard layout to '%s'", lightdm_layout_get_name (dmlayout)); + + parse_layout_string (lightdm_layout_get_name (dmlayout), &layout, &variant); + + config = xkl_config_rec_new (); + config->layouts = g_malloc (sizeof (gchar *) * 2); + config->variants = g_malloc (sizeof (gchar *) * 2); + config->model = g_strdup (xkl_config->model); + config->layouts[0] = layout; + config->layouts[1] = NULL; + config->variants[0] = variant; + config->variants[1] = NULL; + if (!xkl_config_rec_activate (config, xkl_engine)) + g_warning ("Failed to activate XKL config"); + g_object_unref (config); +} + +/** + * lightdm_get_layout: + * + * Get the current keyboard layout. + * + * Return value: (transfer none): The currently active layout for this user. + **/ +LightDMLayout * +lightdm_get_layout (void) +{ + lightdm_get_layouts (); + + if (layouts && xkl_config && !default_layout) + { + gchar *full_name; + GList *item; + + full_name = make_layout_string (xkl_config->layouts ? xkl_config->layouts[0] : NULL, + xkl_config->variants ? xkl_config->variants[0] : NULL); + + for (item = layouts; item; item = item->next) + { + LightDMLayout *iter_layout = (LightDMLayout *) item->data; + if (g_strcmp0 (lightdm_layout_get_name (iter_layout), full_name) == 0) + { + default_layout = iter_layout; + break; + } + } + + g_free (full_name); + } + + return default_layout; +} + +/** + * lightdm_layout_get_name: + * @layout: A #LightDMLayout + * + * Get the name of a layout. + * + * Return value: The name of the layout + **/ +const gchar * +lightdm_layout_get_name (LightDMLayout *layout) +{ + g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL); + return GET_PRIVATE (layout)->name; +} + +/** + * lightdm_layout_get_short_description: + * @layout: A #LightDMLayout + * + * Get the short description of a layout. + * + * Return value: A short description of the layout + **/ +const gchar * +lightdm_layout_get_short_description (LightDMLayout *layout) +{ + g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL); + return GET_PRIVATE (layout)->short_description; +} + +/** + * lightdm_layout_get_description: + * @layout: A #LightDMLayout + * + * Get the long description of a layout. + * + * Return value: A long description of the layout + **/ +const gchar * +lightdm_layout_get_description (LightDMLayout *layout) +{ + g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL); + return GET_PRIVATE (layout)->description; +} + +static void +lightdm_layout_init (LightDMLayout *layout) +{ +} + +static void +lightdm_layout_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + LightDMLayout *self = LIGHTDM_LAYOUT (object); + LightDMLayoutPrivate *priv = GET_PRIVATE (self); + + switch (prop_id) { + case PROP_NAME: + g_free (priv->name); + priv->name = g_strdup (g_value_get_string (value)); + break; + case PROP_SHORT_DESCRIPTION: + g_free (priv->short_description); + priv->short_description = g_strdup (g_value_get_string (value)); + break; + case PROP_DESCRIPTION: + g_free (priv->description); + priv->description = g_strdup (g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_layout_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMLayout *self; + + self = LIGHTDM_LAYOUT (object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, lightdm_layout_get_name (self)); + break; + case PROP_SHORT_DESCRIPTION: + g_value_set_string (value, lightdm_layout_get_short_description (self)); + break; + case PROP_DESCRIPTION: + g_value_set_string (value, lightdm_layout_get_description (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_layout_class_init (LightDMLayoutClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMLayoutPrivate)); + + object_class->set_property = lightdm_layout_set_property; + object_class->get_property = lightdm_layout_get_property; + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "Name of the layout", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_SHORT_DESCRIPTION, + g_param_spec_string ("short-description", + "short-description", + "Short description of the layout", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_DESCRIPTION, + g_param_spec_string ("description", + "description", + "Long description of the layout", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c new file mode 100644 index 00000000..88387084 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2010-2011 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include "config.h" + +#include <string.h> +#include <gio/gio.h> + +#include "lightdm/power.h" + +static GDBusProxy *upower_proxy = NULL; +static GDBusProxy *ck_proxy = NULL; + +static gboolean +upower_call_function (const gchar *function, gboolean default_result, GError **error) +{ + GVariant *result; + gboolean function_result = FALSE; + + if (!upower_proxy) + { + upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.UPower", + "/org/freedesktop/UPower", + "org.freedesktop.UPower", + NULL, + error); + if (!upower_proxy) + return FALSE; + } + + result = g_dbus_proxy_call_sync (upower_proxy, + function, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); + if (!result) + return default_result; + + if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)"))) + g_variant_get (result, "(b)", &function_result); + + g_variant_unref (result); + return function_result; +} + +/** + * lightdm_get_can_suspend: + * + * Checks if authorized to do a system suspend. + * + * Return value: #TRUE if can suspend the system + **/ +gboolean +lightdm_get_can_suspend (void) +{ + return upower_call_function ("SuspendAllowed", FALSE, NULL); +} + +/** + * lightdm_suspend: + * @error: return location for a #GError, or %NULL + * + * Triggers a system suspend. + * + * Return value: #TRUE if suspend initiated. + **/ +gboolean +lightdm_suspend (GError **error) +{ + return upower_call_function ("Suspend", TRUE, error); +} + +/** + * lightdm_get_can_hibernate: + * + * Checks if is authorized to do a system hibernate. + * + * Return value: #TRUE if can hibernate the system + **/ +gboolean +lightdm_get_can_hibernate (void) +{ + return upower_call_function ("HibernateAllowed", FALSE, NULL); +} + +/** + * lightdm_hibernate: + * @error: return location for a #GError, or %NULL + * + * Triggers a system hibernate. + * + * Return value: #TRUE if hibernate initiated. + **/ +gboolean +lightdm_hibernate (GError **error) +{ + return upower_call_function ("Hibernate", TRUE, error); +} + +static gboolean +ck_call_function (const gchar *function, gboolean default_result, GError **error) +{ + GVariant *result; + gboolean function_result = FALSE; + + if (!ck_proxy) + { + ck_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + NULL, + error); + if (!ck_proxy) + return FALSE; + } + + result = g_dbus_proxy_call_sync (ck_proxy, + function, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); + + if (!result) + return default_result; + + if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)"))) + g_variant_get (result, "(b)", &function_result); + + g_variant_unref (result); + return function_result; +} + +/** + * lightdm_get_can_restart: + * + * Checks if is authorized to do a system restart. + * + * Return value: #TRUE if can restart the system + **/ +gboolean +lightdm_get_can_restart (void) +{ + return ck_call_function ("CanRestart", FALSE, NULL); +} + +/** + * lightdm_restart: + * @error: return location for a #GError, or %NULL + * + * Triggers a system restart. + * + * Return value: #TRUE if restart initiated. + **/ +gboolean +lightdm_restart (GError **error) +{ + return ck_call_function ("Restart", TRUE, error); +} + +/** + * lightdm_get_can_shutdown: + * + * Checks if is authorized to do a system shutdown. + * + * Return value: #TRUE if can shutdown the system + **/ +gboolean +lightdm_get_can_shutdown (void) +{ + return ck_call_function ("CanStop", FALSE, NULL); +} + +/** + * lightdm_shutdown: + * @error: return location for a #GError, or %NULL + * + * Triggers a system shutdown. + * + * Return value: #TRUE if shutdown initiated. + **/ +gboolean +lightdm_shutdown (GError **error) +{ + return ck_call_function ("Stop", TRUE, error); +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c new file mode 100644 index 00000000..f1ccf6cc --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2010 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include <string.h> +#include <gio/gdesktopappinfo.h> + +#include "lightdm/session.h" + +enum { + PROP_0, + PROP_KEY, + PROP_NAME, + PROP_COMMENT +}; + +typedef struct +{ + gchar *key; + gchar *name; + gchar *comment; +} LightDMSessionPrivate; + +G_DEFINE_TYPE (LightDMSession, lightdm_session, G_TYPE_OBJECT); + +#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_SESSION, LightDMSessionPrivate) + +static gboolean have_sessions = FALSE; +static GList *local_sessions = NULL; +static GList *remote_sessions = NULL; + +static gint +compare_session (gconstpointer a, gconstpointer b) +{ + LightDMSessionPrivate *priv_a = GET_PRIVATE (a); + LightDMSessionPrivate *priv_b = GET_PRIVATE (b); + return strcmp (priv_a->name, priv_b->name); +} + +static LightDMSession * +load_session (GKeyFile *key_file, const gchar *key) +{ + gchar *domain, *name; + LightDMSession *session; + LightDMSessionPrivate *priv; + gchar *try_exec; + + if (g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) || + g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL)) + return NULL; + +#ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN + domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL); +#else + domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL); +#endif + name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL); + if (!name) + { + g_warning ("Ignoring session without name"); + g_free (domain); + return NULL; + } + + try_exec = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, domain, NULL); + if (try_exec) + { + gchar *full_path; + + full_path = g_find_program_in_path (try_exec); + g_free (try_exec); + + if (!full_path) + { + g_free (name); + g_free (domain); + return NULL; + } + g_free (full_path); + } + + session = g_object_new (LIGHTDM_TYPE_SESSION, NULL); + priv = GET_PRIVATE (session); + + g_free (priv->key); + priv->key = g_strdup (key); + + g_free (priv->name); + priv->name = name; + + g_free (priv->comment); + priv->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL); + if (!priv->comment) + priv->comment = g_strdup (""); + + g_free (domain); + + return session; +} + +static GList * +load_sessions (const gchar *sessions_dir) +{ + GDir *directory; + GList *sessions = NULL; + GError *error = NULL; + + directory = g_dir_open (sessions_dir, 0, &error); + if (error) + g_warning ("Failed to open sessions directory: %s", error->message); + g_clear_error (&error); + if (!directory) + return NULL; + + while (TRUE) + { + const gchar *filename; + gchar *path; + GKeyFile *key_file; + gboolean result; + + filename = g_dir_read_name (directory); + if (filename == NULL) + break; + + if (!g_str_has_suffix (filename, ".desktop")) + continue; + + path = g_build_filename (sessions_dir, filename, NULL); + + key_file = g_key_file_new (); + result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error); + if (error) + g_warning ("Failed to load session file %s: %s:", path, error->message); + g_clear_error (&error); + + if (result) + { + gchar *key; + LightDMSession *session; + + key = g_strndup (filename, strlen (filename) - strlen (".desktop")); + session = load_session (key_file, key); + if (session) + { + g_debug ("Loaded session %s (%s, %s)", path, GET_PRIVATE (session)->name, GET_PRIVATE (session)->comment); + sessions = g_list_insert_sorted (sessions, session, compare_session); + } + else + g_debug ("Ignoring session %s", path); + g_free (key); + } + + g_free (path); + g_key_file_free (key_file); + } + + g_dir_close (directory); + + return sessions; +} + +static void +update_sessions (void) +{ + GKeyFile *config_key_file = NULL; + gchar *config_path = NULL; + gchar *xsessions_dir; + gchar *remote_sessions_dir; + gboolean result; + GError *error = NULL; + + if (have_sessions) + return; + + xsessions_dir = g_strdup (XSESSIONS_DIR); + remote_sessions_dir = g_strdup (REMOTE_SESSIONS_DIR); + + /* Use session directory from configuration */ + /* FIXME: This should be sent in the greeter connection */ + config_path = g_build_filename (CONFIG_DIR, "lightdm.conf", NULL); + config_key_file = g_key_file_new (); + result = g_key_file_load_from_file (config_key_file, config_path, G_KEY_FILE_NONE, &error); + if (error) + g_warning ("Failed to open configuration file: %s", error->message); + g_clear_error (&error); + if (result) + { + gchar *value; + + value = g_key_file_get_string (config_key_file, "LightDM", "xsessions-directory", NULL); + if (value) + { + g_free (xsessions_dir); + xsessions_dir = value; + } + + value = g_key_file_get_string (config_key_file, "LightDM", "remote-sessions-directory", NULL); + if (value) + { + g_free (remote_sessions_dir); + remote_sessions_dir = value; + } + } + g_key_file_free (config_key_file); + g_free (config_path); + + local_sessions = load_sessions (xsessions_dir); + remote_sessions = load_sessions (remote_sessions_dir); + + g_free (xsessions_dir); + g_free (remote_sessions_dir); + + have_sessions = TRUE; +} + +/** + * lightdm_get_sessions: + * + * Get the available sessions. + * + * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession + **/ +GList * +lightdm_get_sessions (void) +{ + update_sessions (); + return local_sessions; +} + +/** + * lightdm_get_remote_sessions: + * + * Get the available remote sessions. + * + * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession + **/ +GList * +lightdm_get_remote_sessions (void) +{ + update_sessions (); + return remote_sessions; +} + +/** + * lightdm_session_get_key: + * @session: A #LightDMSession + * + * Get the key for a session + * + * Return value: The session key + **/ +const gchar * +lightdm_session_get_key (LightDMSession *session) +{ + g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL); + return GET_PRIVATE (session)->key; +} + +/** + * lightdm_session_get_name: + * @session: A #LightDMSession + * + * Get the name for a session + * + * Return value: The session name + **/ +const gchar * +lightdm_session_get_name (LightDMSession *session) +{ + g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL); + return GET_PRIVATE (session)->name; +} + +/** + * lightdm_session_get_comment: + * @session: A #LightDMSession + * + * Get the comment for a session + * + * Return value: The session comment + **/ +const gchar * +lightdm_session_get_comment (LightDMSession *session) +{ + g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL); + return GET_PRIVATE (session)->comment; +} + +static void +lightdm_session_init (LightDMSession *session) +{ +} + +static void +lightdm_session_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +lightdm_session_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMSession *self; + + self = LIGHTDM_SESSION (object); + + switch (prop_id) { + case PROP_KEY: + g_value_set_string (value, lightdm_session_get_key (self)); + break; + case PROP_NAME: + g_value_set_string (value, lightdm_session_get_name (self)); + break; + case PROP_COMMENT: + g_value_set_string (value, lightdm_session_get_comment (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_session_finalize (GObject *object) +{ + LightDMSession *self = LIGHTDM_SESSION (object); + LightDMSessionPrivate *priv = GET_PRIVATE (self); + + g_free (priv->key); + g_free (priv->name); + g_free (priv->comment); +} + +static void +lightdm_session_class_init (LightDMSessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMSessionPrivate)); + + object_class->set_property = lightdm_session_set_property; + object_class->get_property = lightdm_session_get_property; + object_class->finalize = lightdm_session_finalize; + + g_object_class_install_property (object_class, + PROP_KEY, + g_param_spec_string ("key", + "key", + "Session key", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "name", + "Session name", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_COMMENT, + g_param_spec_string ("comment", + "comment", + "Session comment", + NULL, + G_PARAM_READABLE)); +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c new file mode 100644 index 00000000..3b99df3b --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010-2011 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include <sys/utsname.h> + +#include "lightdm/system.h" + +static gchar *hostname = NULL; + +/** + * lightdm_get_hostname: + * + * Return value: The name of the host we are running on. + **/ +const gchar * +lightdm_get_hostname (void) +{ + if (!hostname) + { + struct utsname info; + uname (&info); + hostname = g_strdup (info.nodename); + } + + return hostname; +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c new file mode 100644 index 00000000..5d1cc189 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c @@ -0,0 +1,1646 @@ +/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*- + * + * Copyright (C) 2010 Robert Ancell. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 or version 3 of the License. + * See http://www.gnu.org/copyleft/lgpl.html the full text of the license. + */ + +#include "config.h" + +#include <errno.h> +#include <string.h> +#include <sys/utsname.h> +#include <pwd.h> +#include <gio/gio.h> + +#include "lightdm/user.h" + +enum +{ + LIST_PROP_0, + LIST_PROP_NUM_USERS, + LIST_PROP_USERS, +}; + +enum +{ + USER_PROP_0, + USER_PROP_NAME, + USER_PROP_REAL_NAME, + USER_PROP_DISPLAY_NAME, + USER_PROP_HOME_DIRECTORY, + USER_PROP_IMAGE, + USER_PROP_BACKGROUND, + USER_PROP_LANGUAGE, + USER_PROP_LAYOUT, + USER_PROP_LAYOUTS, + USER_PROP_SESSION, + USER_PROP_LOGGED_IN, + USER_PROP_HAS_MESSAGES +}; + +enum +{ + USER_ADDED, + USER_CHANGED, + USER_REMOVED, + LAST_LIST_SIGNAL +}; +static guint list_signals[LAST_LIST_SIGNAL] = { 0 }; + +enum +{ + CHANGED, + LAST_USER_SIGNAL +}; +static guint user_signals[LAST_USER_SIGNAL] = { 0 }; + +typedef struct +{ + /* Connection to AccountsService */ + GDBusProxy *accounts_service_proxy; + GList *user_account_objects; + + /* Connection to DisplayManager */ + GDBusProxy *display_manager_proxy; + + /* File monitor for password file */ + GFileMonitor *passwd_monitor; + + /* TRUE if have scanned users */ + gboolean have_users; + + /* List of users */ + GList *users; + + /* List of sessions */ + GList *sessions; +} LightDMUserListPrivate; + +typedef struct +{ + GDBusProxy *proxy; + LightDMUser *user; +} UserAccountObject; + +typedef struct +{ + LightDMUserList *user_list; + + gchar *name; + gchar *real_name; + gchar *home_directory; + gchar *image; + gchar *background; + gboolean has_messages; + + GKeyFile *dmrc_file; + gchar *language; + gchar **layouts; + gchar *session; +} LightDMUserPrivate; + +typedef struct +{ + GObject parent_instance; + gchar *path; + gchar *username; +} Session; + +typedef struct +{ + GObjectClass parent_class; +} SessionClass; + +G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT); +G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT); +#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session)) +GType session_get_type (void); +G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT); + +#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate) +#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate) + +#define PASSWD_FILE "/etc/passwd" +#define USER_CONFIG_FILE "/etc/lightdm/users.conf" + +static LightDMUserList *singleton = NULL; + +/** + * lightdm_user_list_get_instance: + * + * Get the user list. + * + * Return value: (transfer none): the #LightDMUserList + **/ +LightDMUserList * +lightdm_user_list_get_instance (void) +{ + if (!singleton) + singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL); + return singleton; +} + +static LightDMUser * +get_user_by_name (LightDMUserList *user_list, const gchar *username) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + GList *link; + + for (link = priv->users; link; link = link->next) + { + LightDMUser *user = link->data; + if (strcmp (lightdm_user_get_name (user), username) == 0) + return user; + } + + return NULL; +} + +static gint +compare_user (gconstpointer a, gconstpointer b) +{ + LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b; + return strcmp (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b)); +} + +static gboolean +update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (user); + + if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 && + g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 && + g_strcmp0 (lightdm_user_get_image (user), image) == 0) + return FALSE; + + g_free (priv->real_name); + priv->real_name = g_strdup (real_name); + g_free (priv->home_directory); + priv->home_directory = g_strdup (home_directory); + g_free (priv->image); + priv->image = g_strdup (image); + + return TRUE; +} + +static void +user_changed_cb (LightDMUser *user, LightDMUserList *user_list) +{ + g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user); +} + +static void +load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + GKeyFile *config; + gchar *value; + gint minimum_uid; + gchar **hidden_users, **hidden_shells; + GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link; + GError *error = NULL; + + g_debug ("Loading user config from %s", USER_CONFIG_FILE); + + config = g_key_file_new (); + g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error); + if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) + g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info + g_clear_error (&error); + + if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL)) + minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL); + else + minimum_uid = 500; + + value = g_key_file_get_string (config, "UserList", "hidden-users", NULL); + if (!value) + value = g_strdup ("nobody nobody4 noaccess"); + hidden_users = g_strsplit (value, " ", -1); + g_free (value); + + value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL); + if (!value) + value = g_strdup ("/bin/false /usr/sbin/nologin"); + hidden_shells = g_strsplit (value, " ", -1); + g_free (value); + + g_key_file_free (config); + + setpwent (); + + while (TRUE) + { + struct passwd *entry; + LightDMUser *user; + LightDMUserPrivate *user_priv; + char **tokens; + gchar *real_name, *image; + int i; + + errno = 0; + entry = getpwent (); + if (!entry) + break; + + /* Ignore system users */ + if (entry->pw_uid < minimum_uid) + continue; + + /* Ignore users disabled by shell */ + if (entry->pw_shell) + { + for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++); + if (hidden_shells[i]) + continue; + } + + /* Ignore certain users */ + for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++); + if (hidden_users[i]) + continue; + + tokens = g_strsplit (entry->pw_gecos, ",", -1); + if (tokens[0] != NULL && tokens[0][0] != '\0') + real_name = g_strdup (tokens[0]); + else + real_name = g_strdup (""); + g_strfreev (tokens); + + image = g_build_filename (entry->pw_dir, ".face", NULL); + if (!g_file_test (image, G_FILE_TEST_EXISTS)) + { + g_free (image); + image = g_build_filename (entry->pw_dir, ".face.icon", NULL); + if (!g_file_test (image, G_FILE_TEST_EXISTS)) + { + g_free (image); + image = NULL; + } + } + + user = g_object_new (LIGHTDM_TYPE_USER, NULL); + user_priv = GET_USER_PRIVATE (user); + user_priv->user_list = user_list; + g_free (user_priv->name); + user_priv->name = g_strdup (entry->pw_name); + g_free (user_priv->real_name); + user_priv->real_name = real_name; + g_free (user_priv->home_directory); + user_priv->home_directory = g_strdup (entry->pw_dir); + g_free (user_priv->image); + user_priv->image = image; + + /* Update existing users if have them */ + for (link = priv->users; link; link = link->next) + { + LightDMUser *info = link->data; + if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0) + { + if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user))) + changed_users = g_list_insert_sorted (changed_users, info, compare_user); + g_object_unref (user); + user = info; + break; + } + } + if (!link) + { + /* Only notify once we have loaded the user list */ + if (priv->have_users) + new_users = g_list_insert_sorted (new_users, user, compare_user); + } + users = g_list_insert_sorted (users, user, compare_user); + } + g_strfreev (hidden_users); + g_strfreev (hidden_shells); + + if (errno != 0) + g_warning ("Failed to read password database: %s", strerror (errno)); + + endpwent (); + + /* Use new user list */ + old_users = priv->users; + priv->users = users; + + /* Notify of changes */ + for (link = new_users; link; link = link->next) + { + LightDMUser *info = link->data; + g_debug ("User %s added", lightdm_user_get_name (info)); + g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), user_list); + if (emit_add_signal) + g_signal_emit (user_list, list_signals[USER_ADDED], 0, info); + } + g_list_free (new_users); + for (link = changed_users; link; link = link->next) + { + LightDMUser *info = link->data; + g_debug ("User %s changed", lightdm_user_get_name (info)); + g_signal_emit (info, user_signals[CHANGED], 0); + } + g_list_free (changed_users); + for (link = old_users; link; link = link->next) + { + GList *new_link; + + /* See if this user is in the current list */ + for (new_link = priv->users; new_link; new_link = new_link->next) + { + if (new_link->data == link->data) + break; + } + + if (!new_link) + { + LightDMUser *info = link->data; + g_debug ("User %s removed", lightdm_user_get_name (info)); + g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info); + g_object_unref (info); + } + } + g_list_free (old_users); +} + +static void +passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list) +{ + if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) + { + g_debug ("%s changed, reloading user list", g_file_get_path (file)); + load_passwd_file (user_list, TRUE); + } +} + +static gboolean +update_user (UserAccountObject *object) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (object->user); + GVariant *result, *value; + GVariantIter *iter; + gchar *name; + GError *error = NULL; + + result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (object->proxy), + "org.freedesktop.Accounts", + g_dbus_proxy_get_object_path (object->proxy), + "org.freedesktop.DBus.Properties", + "GetAll", + g_variant_new ("(s)", "org.freedesktop.Accounts.User"), + G_VARIANT_TYPE ("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + g_warning ("Error updating user %s: %s", g_dbus_proxy_get_object_path (object->proxy), error->message); + g_clear_error (&error); + if (!result) + return FALSE; + + g_variant_get (result, "(a{sv})", &iter); + while (g_variant_iter_loop (iter, "{&sv}", &name, &value)) + { + if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + gchar *user_name; + g_variant_get (value, "&s", &user_name); + g_free (priv->name); + priv->name = g_strdup (user_name); + } + else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + gchar *real_name; + g_variant_get (value, "&s", &real_name); + g_free (priv->real_name); + priv->real_name = g_strdup (real_name); + } + else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + gchar *home_directory; + g_variant_get (value, "&s", &home_directory); + g_free (priv->home_directory); + priv->home_directory = g_strdup (home_directory); + } + else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + gchar *icon_file; + g_variant_get (value, "&s", &icon_file); + g_free (priv->image); + if (strcmp (icon_file, "") == 0) + priv->image = NULL; + else + priv->image = g_strdup (icon_file); + } + else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + gchar *background_file; + g_variant_get (value, "&s", &background_file); + g_free (priv->background); + if (strcmp (background_file, "") == 0) + priv->background = NULL; + else + priv->background = g_strdup (background_file); + } + } + g_variant_iter_free (iter); + + g_variant_unref (result); + + return TRUE; +} + +static void +user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UserAccountObject *object) +{ + if (strcmp (signal_name, "Changed") == 0) + { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()"))) + { + g_debug ("User %s changed", g_dbus_proxy_get_object_path (object->proxy)); + update_user (object); + g_signal_emit (object->user, user_signals[CHANGED], 0); + } + else + g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters)); + } +} + +static UserAccountObject * +user_account_object_new (LightDMUserList *user_list, const gchar *path) +{ + GDBusProxy *proxy; + UserAccountObject *object; + GError *error = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + path, + "org.freedesktop.Accounts.User", + NULL, + &error); + if (error) + g_warning ("Error getting user %s: %s", path, error->message); + g_clear_error (&error); + if (!proxy) + return NULL; + + object = g_malloc0 (sizeof (UserAccountObject)); + object->user = g_object_new (LIGHTDM_TYPE_USER, NULL); + GET_USER_PRIVATE (object->user)->user_list = user_list; + object->proxy = proxy; + g_signal_connect (proxy, "g-signal", G_CALLBACK (user_signal_cb), object); + + return object; +} + +static void +user_account_object_free (UserAccountObject *object) +{ + if (!object) + return; + g_object_unref (object->user); + g_object_unref (object->proxy); + g_free (object); +} + +static UserAccountObject * +find_user_account_object (LightDMUserList *user_list, const gchar *path) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + GList *link; + + for (link = priv->user_account_objects; link; link = link->next) + { + UserAccountObject *object = link->data; + if (strcmp (g_dbus_proxy_get_object_path (object->proxy), path) == 0) + return object; + } + + return NULL; +} + +static void +user_accounts_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + + if (strcmp (signal_name, "UserAdded") == 0) + { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + { + gchar *path; + UserAccountObject *object; + + g_variant_get (parameters, "(&o)", &path); + + /* Ignore duplicate requests */ + object = find_user_account_object (user_list, path); + if (object) + return; + + object = user_account_object_new (user_list, path); + if (object && update_user (object)) + { + g_debug ("User %s added", path); + priv->user_account_objects = g_list_append (priv->user_account_objects, object); + priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user); + g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list); + g_signal_emit (user_list, list_signals[USER_ADDED], 0, object->user); + } + else + user_account_object_free (object); + } + else + g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters)); + } + else if (strcmp (signal_name, "UserDeleted") == 0) + { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + { + gchar *path; + UserAccountObject *object; + + g_variant_get (parameters, "(&o)", &path); + + object = find_user_account_object (user_list, path); + if (!object) + return; + + g_debug ("User %s deleted", path); + priv->users = g_list_remove (priv->users, object->user); + g_object_unref (object->user); + + g_signal_emit (user_list, list_signals[USER_REMOVED], 0, object->user); + + priv->user_account_objects = g_list_remove (priv->user_account_objects, object); + user_account_object_free (object); + } + else + g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters)); + } +} + +static Session * +load_session (LightDMUserList *user_list, const gchar *path) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + Session *session = NULL; + GVariant *result, *username; + GError *error = NULL; + + result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy), + "org.freedesktop.DisplayManager", + path, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message); + g_clear_error (&error); + if (!result) + return NULL; + + g_variant_get (result, "(v)", &username); + if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING)) + { + gchar *name; + + g_variant_get (username, "&s", &name); + + g_debug ("Loaded session %s (%s)", path, name); + session = g_object_new (session_get_type (), NULL); + session->username = g_strdup (name); + session->path = g_strdup (path); + priv->sessions = g_list_append (priv->sessions, session); + } + g_variant_unref (username); + g_variant_unref (result); + + return session; +} + +static void +display_manager_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + + if (strcmp (signal_name, "SessionAdded") == 0) + { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + { + gchar *path; + Session *session; + LightDMUser *user = NULL; + + g_variant_get (parameters, "(&o)", &path); + session = load_session (user_list, path); + if (session) + user = get_user_by_name (user_list, session->username); + if (user) + g_signal_emit (user, user_signals[CHANGED], 0); + } + } + else if (strcmp (signal_name, "SessionRemoved") == 0) + { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + { + gchar *path; + GList *link; + + g_variant_get (parameters, "(&o)", &path); + + for (link = priv->sessions; link; link = link->next) + { + Session *session = link->data; + if (strcmp (session->path, path) == 0) + { + LightDMUser *user; + + g_debug ("Session %s removed", path); + priv->sessions = g_list_remove_link (priv->sessions, link); + user = get_user_by_name (user_list, session->username); + if (user) + g_signal_emit (user, user_signals[CHANGED], 0); + g_object_unref (session); + break; + } + } + } + } +} + +static void +update_users (LightDMUserList *user_list) +{ + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list); + GError *error = NULL; + + if (priv->have_users) + return; + priv->have_users = TRUE; + + priv->accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts", + NULL, + &error); + if (error) + g_warning ("Error contacting org.freedesktop.Accounts: %s", error->message); + g_clear_error (&error); + + /* Check if the service exists */ + if (priv->accounts_service_proxy) + { + gchar *name; + + name = g_dbus_proxy_get_name_owner (priv->accounts_service_proxy); + if (!name) + { + g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file"); + g_object_unref (priv->accounts_service_proxy); + priv->accounts_service_proxy = NULL; + } + g_free (name); + } + + if (priv->accounts_service_proxy) + { + GVariant *result; + + g_signal_connect (priv->accounts_service_proxy, "g-signal", G_CALLBACK (user_accounts_signal_cb), user_list); + + result = g_dbus_proxy_call_sync (priv->accounts_service_proxy, + "ListCachedUsers", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message); + g_clear_error (&error); + if (!result) + return; + + if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(ao)"))) + { + GVariantIter *iter; + const gchar *path; + + g_debug ("Loading users from org.freedesktop.Accounts"); + g_variant_get (result, "(ao)", &iter); + while (g_variant_iter_loop (iter, "&o", &path)) + { + UserAccountObject *object; + + g_debug ("Loading user %s", path); + + object = user_account_object_new (user_list, path); + if (object && update_user (object)) + { + priv->user_account_objects = g_list_append (priv->user_account_objects, object); + priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user); + g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list); + } + else + user_account_object_free (object); + } + g_variant_iter_free (iter); + } + else + g_warning ("Unexpected type from ListCachedUsers: %s", g_variant_get_type_string (result)); + + g_variant_unref (result); + } + else + { + GFile *passwd_file; + + load_passwd_file (user_list, FALSE); + + /* Watch for changes to user list */ + + passwd_file = g_file_new_for_path (PASSWD_FILE); + priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error); + g_object_unref (passwd_file); + if (error) + g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message); + else + g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list); + g_clear_error (&error); + } + + priv->display_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.DisplayManager", + "/org/freedesktop/DisplayManager", + "org.freedesktop.DisplayManager", + NULL, + &error); + if (error) + g_warning ("Error contacting org.freedesktop.DisplayManager: %s", error->message); + g_clear_error (&error); + + if (priv->display_manager_proxy) + { + GVariant *result; + + g_signal_connect (priv->display_manager_proxy, "g-signal", G_CALLBACK (display_manager_signal_cb), user_list); + + result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy), + "org.freedesktop.DisplayManager", + "/org/freedesktop/DisplayManager", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message); + g_clear_error (&error); + if (!result) + return; + + if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)"))) + { + GVariant *value; + GVariantIter *iter; + const gchar *path; + + g_variant_get (result, "(v)", &value); + + g_debug ("Loading sessions from org.freedesktop.DisplayManager"); + g_variant_get (value, "ao", &iter); + while (g_variant_iter_loop (iter, "&o", &path)) + load_session (user_list, path); + g_variant_iter_free (iter); + + g_variant_unref (value); + } + else + g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result)); + + g_variant_unref (result); + } +} + +/** + * lightdm_user_list_get_length: + * @user_list: a #LightDMUserList + * + * Return value: The number of users able to log in + **/ +gint +lightdm_user_list_get_length (LightDMUserList *user_list) +{ + g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0); + update_users (user_list); + return g_list_length (GET_LIST_PRIVATE (user_list)->users); +} + +/** + * lightdm_user_list_get_users: + * @user_list: A #LightDMUserList + * + * Get a list of users to present to the user. This list may be a subset of the + * available users and may be empty depending on the server configuration. + * + * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user. + **/ +GList * +lightdm_user_list_get_users (LightDMUserList *user_list) +{ + g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL); + update_users (user_list); + return GET_LIST_PRIVATE (user_list)->users; +} + +/** + * lightdm_user_list_get_user_by_name: + * @user_list: A #LightDMUserList + * @username: Name of user to get. + * + * Get infomation about a given user or #NULL if this user doesn't exist. + * + * Return value: (transfer none): A #LightDMUser entry for the given user. + **/ +LightDMUser * +lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username) +{ + g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL); + g_return_val_if_fail (username != NULL, NULL); + + update_users (user_list); + + return get_user_by_name (user_list, username); +} + +static void +lightdm_user_list_init (LightDMUserList *user_list) +{ +} + +static void +lightdm_user_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +lightdm_user_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMUserList *self; + + self = LIGHTDM_USER_LIST (object); + + switch (prop_id) + { + case LIST_PROP_NUM_USERS: + g_value_set_int (value, lightdm_user_list_get_length (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_user_list_finalize (GObject *object) +{ + LightDMUserList *self = LIGHTDM_USER_LIST (object); + LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self); + + if (priv->accounts_service_proxy) + g_object_unref (priv->accounts_service_proxy); + g_list_free_full (priv->user_account_objects, (GDestroyNotify) user_account_object_free); + if (priv->passwd_monitor) + g_object_unref (priv->passwd_monitor); + g_list_free_full (priv->users, g_object_unref); + g_list_free_full (priv->sessions, g_object_unref); + + G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object); +} + +static void +lightdm_user_list_class_init (LightDMUserListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMUserListPrivate)); + + object_class->set_property = lightdm_user_list_set_property; + object_class->get_property = lightdm_user_list_get_property; + object_class->finalize = lightdm_user_list_finalize; + + g_object_class_install_property (object_class, + LIST_PROP_NUM_USERS, + g_param_spec_int ("num-users", + "num-users", + "Number of login users", + 0, G_MAXINT, 0, + G_PARAM_READABLE)); + /** + * LightDMUserList::user-added: + * @user_list: A #LightDMUserList + * @user: The #LightDM user that has been added. + * + * The ::user-added signal gets emitted when a user account is created. + **/ + list_signals[USER_ADDED] = + g_signal_new ("user-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMUserListClass, user_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, LIGHTDM_TYPE_USER); + + /** + * LightDMUserList::user-changed: + * @user_list: A #LightDMUserList + * @user: The #LightDM user that has been changed. + * + * The ::user-changed signal gets emitted when a user account is modified. + **/ + list_signals[USER_CHANGED] = + g_signal_new ("user-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMUserListClass, user_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, LIGHTDM_TYPE_USER); + + /** + * LightDMUserList::user-removed: + * @user_list: A #LightDMUserList + * @user: The #LightDM user that has been removed. + * + * The ::user-removed signal gets emitted when a user account is removed. + **/ + list_signals[USER_REMOVED] = + g_signal_new ("user-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMUserListClass, user_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, LIGHTDM_TYPE_USER); +} + +/** + * lightdm_user_get_name: + * @user: A #LightDMUser + * + * Get the name of a user. + * + * Return value: The name of the given user + **/ +const gchar * +lightdm_user_get_name (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + return GET_USER_PRIVATE (user)->name; +} + +/** + * lightdm_user_get_real_name: + * @user: A #LightDMUser + * + * Get the real name of a user. + * + * Return value: The real name of the given user + **/ +const gchar * +lightdm_user_get_real_name (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + return GET_USER_PRIVATE (user)->real_name; +} + +/** + * lightdm_user_get_display_name: + * @user: A #LightDMUser + * + * Get the display name of a user. + * + * Return value: The display name of the given user + **/ +const gchar * +lightdm_user_get_display_name (LightDMUser *user) +{ + LightDMUserPrivate *priv; + + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + + priv = GET_USER_PRIVATE (user); + if (strcmp (priv->real_name, "")) + return priv->real_name; + else + return priv->name; +} + +/** + * lightdm_user_get_home_directory: + * @user: A #LightDMUser + * + * Get the home directory for a user. + * + * Return value: The users home directory + */ +const gchar * +lightdm_user_get_home_directory (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + return GET_USER_PRIVATE (user)->home_directory; +} + +/** + * lightdm_user_get_image: + * @user: A #LightDMUser + * + * Get the image URI for a user. + * + * Return value: The image URI for the given user or #NULL if no URI + **/ +const gchar * +lightdm_user_get_image (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + return GET_USER_PRIVATE (user)->image; +} + +/** + * lightdm_user_get_background: + * @user: A #LightDMUser + * + * Get the background file path for a user. + * + * Return value: The background file path for the given user or #NULL if no path + **/ +const gchar * +lightdm_user_get_background (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + return GET_USER_PRIVATE (user)->background; +} + +static void +load_dmrc (LightDMUser *user) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (user); + gchar *path; + //gboolean have_dmrc; + + if (!priv->dmrc_file) + priv->dmrc_file = g_key_file_new (); + + /* Load from the user directory */ + path = g_build_filename (priv->home_directory, ".dmrc", NULL); + /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL); + g_free (path); + + /* If no ~/.dmrc, then load from the cache */ + // FIXME + + // FIXME: Watch for changes + + /* The Language field is actually a locale, strip the codeset off it to get the language */ + if (priv->language) + g_free (priv->language); + priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL); + if (priv->language) + { + gchar *codeset = strchr (priv->language, '.'); + if (codeset) + *codeset = '\0'; + } + + if (priv->layouts) + { + g_strfreev (priv->layouts); + priv->layouts = NULL; + } + if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL)) + { + priv->layouts = g_malloc (sizeof (gchar *) * 2); + priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL); + priv->layouts[1] = NULL; + } + + if (priv->session) + g_free (priv->session); + priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL); +} + +static GVariant * +get_property (GDBusProxy *proxy, const gchar *property) +{ + GVariant *answer; + + if (!proxy) + return NULL; + + answer = g_dbus_proxy_get_cached_property (proxy, property); + + if (!answer) + { + g_warning ("Could not get accounts property %s", property); + return NULL; + } + + return answer; +} + +static gboolean +get_boolean_property (GDBusProxy *proxy, const gchar *property) +{ + GVariant *answer; + gboolean rv; + + answer = get_property (proxy, property); + if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_BOOLEAN)) + { + g_warning ("Unexpected accounts property type for %s: %s", + property, g_variant_get_type_string (answer)); + g_variant_unref (answer); + return FALSE; + } + + rv = g_variant_get_boolean (answer); + g_variant_unref (answer); + + return rv; +} + +static gchar * +get_string_property (GDBusProxy *proxy, const gchar *property) +{ + GVariant *answer; + gchar *rv; + + answer = get_property (proxy, property); + if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_STRING)) + { + g_warning ("Unexpected accounts property type for %s: %s", + property, g_variant_get_type_string (answer)); + g_variant_unref (answer); + return NULL; + } + + rv = g_strdup (g_variant_get_string (answer, NULL)); + if (strcmp (rv, "") == 0) + { + g_free (rv); + rv = NULL; + } + g_variant_unref (answer); + + return rv; +} + +static gchar ** +get_string_array_property (GDBusProxy *proxy, const gchar *property) +{ + GVariant *answer; + gchar **rv; + + if (!proxy) + return NULL; + + answer = g_dbus_proxy_get_cached_property (proxy, property); + + if (!answer) + { + g_warning ("Could not get accounts property %s", property); + return NULL; + } + + if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("as"))) + { + g_warning ("Unexpected accounts property type for %s: %s", + property, g_variant_get_type_string (answer)); + g_variant_unref (answer); + return NULL; + } + + rv = g_variant_dup_strv (answer, NULL); + + g_variant_unref (answer); + return rv; +} + +static gboolean +load_accounts_service (LightDMUser *user) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (user); + LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list); + UserAccountObject *account = NULL; + GList *iter; + gchar **value; + + /* First, find AccountObject proxy */ + for (iter = list_priv->user_account_objects; iter; iter = iter->next) + { + UserAccountObject *a = iter->data; + if (a->user == user) + { + account = a; + break; + } + } + if (!account) + return FALSE; + + /* We have proxy, let's grab some properties */ + if (priv->language) + g_free (priv->language); + priv->language = get_string_property (account->proxy, "Language"); + if (priv->session) + g_free (priv->session); + priv->session = get_string_property (account->proxy, "XSession"); + + value = get_string_array_property (account->proxy, "XKeyboardLayouts"); + if (value) + { + if (value[0]) + { + g_strfreev (priv->layouts); + priv->layouts = value; + } + else + g_strfreev (value); + } + + priv->has_messages = get_boolean_property (account->proxy, "XHasMessages"); + + return TRUE; +} + +/* Loads language/layout/session info for user */ +static void +load_user_values (LightDMUser *user) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (user); + + load_dmrc (user); + load_accounts_service (user); // overrides dmrc values + + /* Ensure a few guarantees */ + if (priv->layouts == NULL) + { + priv->layouts = g_malloc (sizeof (gchar *) * 1); + priv->layouts[0] = NULL; + } +} + +/** + * lightdm_user_get_language: + * @user: A #LightDMUser + * + * Get the language for a user. + * + * Return value: The language for the given user or #NULL if using system defaults. + **/ +const gchar * +lightdm_user_get_language (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + load_user_values (user); + return GET_USER_PRIVATE (user)->language; +} + +/** + * lightdm_user_get_layout: + * @user: A #LightDMUser + * + * Get the keyboard layout for a user. + * + * Return value: The keyboard layout for the given user or #NULL if using system defaults. Copy the value if you want to use it long term. + **/ +const gchar * +lightdm_user_get_layout (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + load_user_values (user); + return GET_USER_PRIVATE (user)->layouts[0]; +} + +/** + * lightdm_user_get_layouts: + * @user: A #LightDMUser + * + * Get the configured keyboard layouts for a user. + * + * Return value: (transfer none): A NULL-terminated array of keyboard layouts for the given user. Copy the values if you want to use them long term. + **/ +const gchar * const * +lightdm_user_get_layouts (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + load_user_values (user); + return (const gchar * const *) GET_USER_PRIVATE (user)->layouts; +} + +/** + * lightdm_user_get_session: + * @user: A #LightDMUser + * + * Get the session for a user. + * + * Return value: The session for the given user or #NULL if using system defaults. + **/ +const gchar * +lightdm_user_get_session (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL); + load_user_values (user); + return GET_USER_PRIVATE (user)->session; +} + +/** + * lightdm_user_get_logged_in: + * @user: A #LightDMUser + * + * Check if a user is logged in. + * + * Return value: #TRUE if the user is currently logged in. + **/ +gboolean +lightdm_user_get_logged_in (LightDMUser *user) +{ + LightDMUserPrivate *priv = GET_USER_PRIVATE (user); + LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list); + GList *link; + + g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE); + + for (link = list_priv->sessions; link; link = link->next) + { + Session *session = link->data; + if (strcmp (session->username, priv->name) == 0) + return TRUE; + } + + return FALSE; +} + +/** + * lightdm_user_get_has_messages: + * @user: A #LightDMUser + * + * Check if a user has waiting messages. + * + * Return value: #TRUE if the user has waiting messages. + **/ +gboolean +lightdm_user_get_has_messages (LightDMUser *user) +{ + g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE); + load_user_values (user); + return GET_USER_PRIVATE (user)->has_messages; +} + +static void +lightdm_user_init (LightDMUser *user) +{ +} + +static void +lightdm_user_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +lightdm_user_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LightDMUser *self; + + self = LIGHTDM_USER (object); + + switch (prop_id) + { + case USER_PROP_NAME: + g_value_set_string (value, lightdm_user_get_name (self)); + break; + case USER_PROP_REAL_NAME: + g_value_set_string (value, lightdm_user_get_real_name (self)); + break; + case USER_PROP_DISPLAY_NAME: + g_value_set_string (value, lightdm_user_get_display_name (self)); + break; + case USER_PROP_HOME_DIRECTORY: + g_value_set_string (value, lightdm_user_get_home_directory (self)); + break; + case USER_PROP_IMAGE: + g_value_set_string (value, lightdm_user_get_image (self)); + break; + case USER_PROP_BACKGROUND: + g_value_set_string (value, lightdm_user_get_background (self)); + break; + case USER_PROP_LANGUAGE: + g_value_set_string (value, lightdm_user_get_language (self)); + break; + case USER_PROP_LAYOUT: + g_value_set_string (value, lightdm_user_get_layout (self)); + break; + case USER_PROP_LAYOUTS: + g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self))); + break; + case USER_PROP_SESSION: + g_value_set_string (value, lightdm_user_get_session (self)); + break; + case USER_PROP_LOGGED_IN: + g_value_set_boolean (value, lightdm_user_get_logged_in (self)); + break; + case USER_PROP_HAS_MESSAGES: + g_value_set_boolean (value, lightdm_user_get_has_messages (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +lightdm_user_finalize (GObject *object) +{ + LightDMUser *self = LIGHTDM_USER (object); + LightDMUserPrivate *priv = GET_USER_PRIVATE (self); + + g_free (priv->name); + g_free (priv->real_name); + g_free (priv->home_directory); + g_free (priv->image); + g_free (priv->background); + g_strfreev (priv->layouts); + if (priv->dmrc_file) + g_key_file_free (priv->dmrc_file); +} + +static void +lightdm_user_class_init (LightDMUserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (LightDMUserPrivate)); + + object_class->set_property = lightdm_user_set_property; + object_class->get_property = lightdm_user_get_property; + object_class->finalize = lightdm_user_finalize; + + g_object_class_install_property (object_class, + USER_PROP_NAME, + g_param_spec_string ("name", + "name", + "Username", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_REAL_NAME, + g_param_spec_string ("real-name", + "real-name", + "Users real name", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_DISPLAY_NAME, + g_param_spec_string ("display-name", + "display-name", + "Users display name", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + USER_PROP_HOME_DIRECTORY, + g_param_spec_string ("home-directory", + "home-directory", + "Home directory", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_IMAGE, + g_param_spec_string ("image", + "image", + "Avatar image", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_BACKGROUND, + g_param_spec_string ("background", + "background", + "User background", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_LANGUAGE, + g_param_spec_string ("language", + "language", + "Language used by this user", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + USER_PROP_LAYOUT, + g_param_spec_string ("layout", + "layout", + "Keyboard layout used by this user", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + USER_PROP_LAYOUTS, + g_param_spec_boxed ("layouts", + "layouts", + "Keyboard layouts used by this user", + G_TYPE_STRV, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + USER_PROP_SESSION, + g_param_spec_string ("session", + "session", + "Session used by this user", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + USER_PROP_LOGGED_IN, + g_param_spec_boolean ("logged-in", + "logged-in", + "TRUE if the user is currently in a session", + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + USER_PROP_LOGGED_IN, + g_param_spec_boolean ("has-messages", + "has-messages", + "TRUE if the user is has waiting messages", + FALSE, + G_PARAM_READWRITE)); + + /** + * LightDMUser::changed: + * @user: A #LightDMUser + * + * The ::changed signal gets emitted this user account is modified. + **/ + user_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMUserClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +session_init (Session *session) +{ +} + +static void +session_finalize (GObject *object) +{ + Session *self = SESSION (object); + + g_free (self->path); + g_free (self->username); +} + +static void +session_class_init (SessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = session_finalize; +} diff --git a/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.cpp b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.cpp new file mode 100644 index 00000000..179f0fc2 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.cpp @@ -0,0 +1,1505 @@ +/* $Id: vbox-greeter.cpp $ */ +/** @file + * vbox-greeter - an own LightDM greeter module supporting auto-logons + * controlled by the host. + */ + +/* + * Copyright (C) 2012-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <pwd.h> +#include <syslog.h> +#include <stdlib.h> + +#include <lightdm.h> +#ifdef VBOX_WITH_FLTK +# include <FL/Fl.H> +# include <FL/fl_ask.H> /* Yes, the casing is correct for 1.3.0 -- d'oh. */ +# include <FL/Fl_Box.H> +# include <FL/Fl_Button.H> +# include <FL/fl_draw.H> /* Same as above. */ +# include <FL/Fl_Double_Window.H> +# include <FL/Fl_Input.H> +# include <FL/Fl_Menu_Button.H> +# ifdef VBOX_GREETER_WITH_PNG_SUPPORT +# include <FL/Fl_PNG_Image.H> +# include <FL/Fl_Shared_Image.H> +# endif +# include <FL/Fl_Secret_Input.H> +#else +# include <cairo-xlib.h> +# include <gtk/gtk.h> +# include <gdk/gdkx.h> +#endif + +#include <package-generated.h> +#include "product-generated.h" + +#include <iprt/assert.h> +#include <iprt/buildconfig.h> +#include <iprt/env.h> +#include <iprt/file.h> +#include <iprt/getopt.h> +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/message.h> +#include <iprt/path.h> +#include <iprt/process.h> +#include <iprt/stream.h> +#include <iprt/system.h> +#include <iprt/string.h> +#include <iprt/thread.h> +#include <iprt/time.h> + +#include <VBox/log.h> +#include <VBox/VBoxGuestLib.h> + +/* The greeter's full name for logging. */ +#define VBOX_MODULE_NAME "vbox-lightdm-greeter" + +/* UI elements used in this greeter. */ +#define VBOX_GREETER_UI_WND_GREETER "wnd_greeter" + +#define VBOX_GREETER_UI_EDT_USER "edt_username" +#define VBOX_GREETER_UI_EDT_PASSWORD "edt_password" +#define VBOX_GREETER_UI_BTN_LOGIN "btn_login" +#define VBOX_GREETER_UI_LBL_INFO "lbl_info" + +/* UI display options. */ +/** Show the restart menu entry / button. */ +#define VBOX_GREETER_UI_SHOW_RESTART RT_BIT(0) +/** Show the shutdown menu entry / button. */ +#define VBOX_GREETER_UI_SHOW_SHUTDOWN RT_BIT(1) +/** Show the (customized) top banner. */ +#define VBOX_GREETER_UI_SHOW_BANNER RT_BIT(2) +/** Enable custom colors */ +#define VBOX_GREETER_UI_USE_THEMING RT_BIT(3) + +/** Extracts the 8-bit red component from an uint32_t. */ +#define VBOX_RGB_COLOR_RED(uColor) uColor & 0xFF +/** Extracts the 8-bit green component from an uint32_t. */ +#define VBOX_RGB_COLOR_GREEN(uColor) (uColor >> 8) & 0xFF +/** Extracts the 8-bit blue component from an uint32_t. */ +#define VBOX_RGB_COLOR_BLUE(uColor) (uColor >> 16) & 0xFF + +#include <VBox/log.h> +#ifdef VBOX_WITH_GUEST_PROPS + #include <VBox/HostServices/GuestPropertySvc.h> + using namespace guestProp; +#endif + +/** The program name (derived from argv[0]). */ +char *g_pszProgName = (char *)""; +/** For debugging. */ +#ifdef DEBUG + static int g_iVerbosity = 99; +#else + static int g_iVerbosity = 0; +#endif +static bool g_fRunning = true; + +/** Logging parameters. */ +/** @todo Make this configurable later. */ +static PRTLOGGER g_pLoggerRelease = NULL; +static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */ +static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */ +static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */ + +/** + * Context structure which contains all needed + * data within callbacks. + */ +typedef struct VBOXGREETERCTX +{ + /** Pointer to this greeter instance. */ + LightDMGreeter *pGreeter; +#ifdef VBOX_WITH_FLTK + Fl_Button *pBtnLogin; + Fl_Input *pEdtUsername; + Fl_Secret_Input *pEdtPassword; + Fl_Box *pLblInfo; +#else + /** The GTK builder instance for accessing + * the UI elements. */ + GtkBuilder *pBuilder; +#endif + /** The timeout (in ms) to wait for credentials. */ + uint32_t uTimeoutMS; + /** The starting timestamp (in ms) to calculate + * the timeout. */ + uint64_t uStartMS; + /** Timestamp of last abort message. */ + uint64_t uTsAbort; + /** The HGCM client ID. */ + uint32_t uClientId; + /** The credential password. */ + char *pszPassword; +} VBOXGREETERCTX, *PVBOXGREETERCTX; + +static void vboxGreeterError(const char *pszFormat, ...) +{ + va_list va; + char *buf; + va_start(va, pszFormat); + if (RTStrAPrintfV(&buf, pszFormat, va)) + { + RTLogRelPrintf("%s: error: %s", VBOX_MODULE_NAME, buf); + RTStrFree(buf); + } + va_end(va); +} + +static void vboxGreeterLog(const char *pszFormat, ...) +{ + if (g_iVerbosity) + { + va_list va; + char *buf; + va_start(va, pszFormat); + if (RTStrAPrintfV(&buf, pszFormat, va)) + { + /* Only do normal logging in debug mode; could contain + * sensitive data! */ + RTLogRelPrintf("%s: %s", VBOX_MODULE_NAME, buf); + RTStrFree(buf); + } + va_end(va); + } +} + +/** @tood Move the following two functions to VbglR3 (also see pam_vbox). */ +#ifdef VBOX_WITH_GUEST_PROPS +/** + * Reads a guest property. + * + * @return IPRT status code. + * @param hPAM PAM handle. + * @param uClientID Guest property service client ID. + * @param pszKey Key (name) of guest property to read. + * @param fReadOnly Indicates whether this key needs to be + * checked if it only can be read (and *not* written) + * by the guest. + * @param pszValue Buffer where to store the key's value. + * @param cbValue Size of buffer (in bytes). + * @param puTimestamp Timestamp of the value + * retrieved. Optional. + */ +static int vbox_read_prop(uint32_t uClientID, + const char *pszKey, bool fReadOnly, + char *pszValue, size_t cbValue, uint64_t *puTimestamp) +{ + AssertReturn(uClientID, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszKey, VERR_INVALID_POINTER); + AssertPtrReturn(pszValue, VERR_INVALID_POINTER); + /* puTimestamp is optional. */ + + int rc; + + uint64_t u64Timestamp = 0; + char *pszValTemp = NULL; + char *pszFlags = NULL; + /* The buffer for storing the data and its initial size. We leave a bit + * of space here in case the maximum values are raised. */ + void *pvBuf = NULL; + uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K; + + /* Because there is a race condition between our reading the size of a + * property and the guest updating it, we loop a few times here and + * hope. Actually this should never go wrong, as we are generous + * enough with buffer space. */ + for (unsigned i = 0; i < 10; i++) + { + pvBuf = RTMemRealloc(pvBuf, cbBuf); + if (pvBuf) + { + rc = VbglR3GuestPropRead(uClientID, pszKey, pvBuf, cbBuf, + &pszValTemp, &u64Timestamp, &pszFlags, + &cbBuf); + } + else + rc = VERR_NO_MEMORY; + + switch (rc) + { + case VERR_BUFFER_OVERFLOW: + { + /* Buffer too small, try it with a bigger one next time. */ + cbBuf += _1K; + continue; /* Try next round. */ + } + + default: + break; + } + + /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */ + break; + } + + if (RT_SUCCESS(rc)) + { + /* Check security bits. */ + if (pszFlags) + { + if ( fReadOnly + && !RTStrStr(pszFlags, "RDONLYGUEST")) + { + /* If we want a property which is read-only on the guest + * and it is *not* marked as such, deny access! */ + rc = VERR_ACCESS_DENIED; + } + } + else /* No flags, no access! */ + rc = VERR_ACCESS_DENIED; + + if (RT_SUCCESS(rc)) + { + /* If everything went well copy property value to our destination buffer. */ + if (!RTStrPrintf(pszValue, cbValue, "%s", pszValTemp)) + rc = VERR_BUFFER_OVERFLOW; + + if (puTimestamp) + *puTimestamp = u64Timestamp; + } + } + +#ifdef DEBUG + vboxGreeterLog("Read guest property \"%s\"=\"%s\" (Flags: %s, TS: %RU64): %Rrc\n", + pszKey, pszValTemp ? pszValTemp : "<None>", + pszFlags ? pszFlags : "<None>", u64Timestamp, rc); +#endif + + if (pvBuf) + RTMemFree(pvBuf); + + return rc; +} + +/** + * Waits for a guest property to be changed. + * + * @return IPRT status code. + * @param hPAM PAM handle. + * @param uClientID Guest property service client ID. + * @param pszKey Key (name) of guest property to wait for. + * @param uTimeoutMS Timeout (in ms) to wait for the change. Specify + * RT_INDEFINITE_WAIT to wait indefinitly. + */ +static int vbox_wait_prop(uint32_t uClientID, + const char *pszKey, uint32_t uTimeoutMS) +{ + AssertReturn(uClientID, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszKey, VERR_INVALID_POINTER); + + int rc; + + /* The buffer for storing the data and its initial size. We leave a bit + * of space here in case the maximum values are raised. */ + void *pvBuf = NULL; + uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K; + + for (int i = 0; i < 10; i++) + { + void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf); + if (pvTmpBuf) + { + char *pszName = NULL; + char *pszValue = NULL; + uint64_t u64TimestampOut = 0; + char *pszFlags = NULL; + + pvBuf = pvTmpBuf; + rc = VbglR3GuestPropWait(uClientID, pszKey, pvBuf, cbBuf, + 0 /* Last timestamp; just wait for next event */, uTimeoutMS, + &pszName, &pszValue, &u64TimestampOut, + &pszFlags, &cbBuf); + } + else + rc = VERR_NO_MEMORY; + + if (rc == VERR_BUFFER_OVERFLOW) + { + /* Buffer too small, try it with a bigger one next time. */ + cbBuf += _1K; + continue; /* Try next round. */ + } + + /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */ + break; + } + + return rc; +} +#endif /* VBOX_WITH_GUEST_PROPS */ + +/** + * Checks for credentials provided by the host / HGCM. + * + * @return IPRT status code. VERR_NOT_FOUND if no credentials are available, + * VINF_SUCCESS on successful retrieval or another IPRT error. + * @param pCtx Greeter context. + */ +static int vboxGreeterCheckCreds(PVBOXGREETERCTX pCtx) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + static bool s_fCredsNotFoundMsgShown = false; + int rc = VbglR3CredentialsQueryAvailability(); + if (RT_FAILURE(rc)) + { + if (rc != VERR_NOT_FOUND) + vboxGreeterError("vboxGreeterCheckCreds: could not query for credentials! rc=%Rrc. Aborting\n", rc); + else if (!s_fCredsNotFoundMsgShown) + { + vboxGreeterLog("vboxGreeterCheckCreds: no credentials available\n"); + s_fCredsNotFoundMsgShown = true; + } + } + else + { + /** @todo Domain handling needed? */ + char *pszUsername; /* User name only is kept local. */ + char *pszDomain = NULL; + rc = VbglR3CredentialsRetrieve(&pszUsername, &pCtx->pszPassword, &pszDomain); + if (RT_FAILURE(rc)) + { + vboxGreeterError("vboxGreeterCheckCreds: could not retrieve credentials! rc=%Rrc. Aborting\n", rc); + } + else + { + vboxGreeterLog("vboxGreeterCheckCreds: credentials retrieved: user=%s, password=%s, domain=%s\n", + pszUsername, +#ifdef DEBUG + pCtx->pszPassword, +#else + "XXX", +#endif + pszDomain); + /* Trigger LightDM authentication with the user name just retrieved. */ + lightdm_greeter_authenticate(pCtx->pGreeter, pszUsername); /* Must be the real user name from host! */ + + /* Securely wipe the user name + domain again. */ + VbglR3CredentialsDestroy(pszUsername, NULL /* pszPassword */, pszDomain, + 3 /* Three wipe passes */); + } + } + +#ifdef DEBUG + vboxGreeterLog("vboxGreeterCheckCreds: returned with rc=%Rrc\n", rc); +#endif + return rc; +} + +/** + * Called by LightDM when greeter is not needed anymore. + * + * @param signum Signal number. + */ +static void cb_sigterm(int signum) +{ + /* Note: This handler must be reentrant-safe. */ +#ifdef VBOX_WITH_FLTK + g_fRunning = false; +#else + exit(RTEXITCODE_SUCCESS); +#endif +} + +/** + * Callback for showing a user prompt, issued by the LightDM server. + * + * @param pGreeter Pointer to this greeter instance. + * @param pszText Text to display. + * @param enmType Type of prompt to display. + * @param pvData Pointer to user-supplied data. + */ +static void cb_lightdm_show_prompt(LightDMGreeter *pGreeter, + const gchar *pszText, LightDMPromptType enmType, + gpointer pvData) +{ + vboxGreeterLog("cb_lightdm_show_prompt: text=%s, type=%d\n", pszText, enmType); + + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtr(pCtx); + + switch (enmType) + { + case 1: /* Password. */ + { + if (pCtx->pszPassword) + { + lightdm_greeter_respond(pGreeter, pCtx->pszPassword); + } + else + { +#ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pEdtPassword); + const char *pszPwd = pCtx->pEdtPassword->value(); +#else + GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, "edt_password")); + AssertPtr(pEdtPwd); + const gchar *pszPwd = gtk_entry_get_text(pEdtPwd); +#endif + lightdm_greeter_respond(pGreeter, pszPwd); + } + break; + } + /** @todo Other fields? */ + + default: + break; + } + + VbglR3CredentialsDestroy(NULL /* pszUsername */, pCtx->pszPassword, NULL /* pszDomain */, + 3 /* Three wipe passes */); + pCtx->pszPassword = NULL; +} + +/** + * Callback for showing a message, issued by the LightDM server. + * + * @param pGreeter Pointer to this greeter instance. + * @param pszText Text to display. + * @param enmType Type of message to display. + * @param pvData Pointer to user-supplied data. + */ +static void cb_lightdm_show_message(LightDMGreeter *pGreeter, + const gchar *pszText, LightDMPromptType enmType, + gpointer pvData) +{ + vboxGreeterLog("cb_lightdm_show_message: text=%s, type=%d\n", pszText, enmType); + + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtrReturnVoid(pCtx); + +#ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pLblInfo); + pCtx->pLblInfo->copy_label(pszText); +#else + GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, "lbl_info")); + AssertPtr(pLblInfo); + gtk_label_set_text(pLblInfo, pszText); +#endif +} + +/** + * Callback for authentication completion, issued by the LightDM server. + * + * @param pGreeter Pointer to this greeter instance. + */ +static void cb_lightdm_auth_complete(LightDMGreeter *pGreeter) +{ + vboxGreeterLog("cb_lightdm_auth_complete\n"); + + const gchar *pszUser = lightdm_greeter_get_authentication_user(pGreeter); + vboxGreeterLog("authenticating user: %s\n", pszUser ? pszUser : "<NULL>"); + + if (lightdm_greeter_get_is_authenticated(pGreeter)) + { + /** @todo Add non-default session support. */ + gchar *pszSession = g_strdup(lightdm_greeter_get_default_session_hint(pGreeter)); + if (pszSession) + { + vboxGreeterLog("starting session: %s\n", pszSession); + GError *pError = NULL; + if (!lightdm_greeter_start_session_sync(pGreeter, pszSession, &pError)) + { + vboxGreeterError("unable to start session '%s': %s\n", + pszSession, pError ? pError->message : "Unknown error"); + } + else + { + AssertPtr(pszSession); + vboxGreeterLog("session '%s' successfully started\n", pszSession); + } + if (pError) + g_error_free(pError); + g_free(pszSession); + } + else + vboxGreeterError("unable to get default session\n"); + } + else + vboxGreeterLog("user not authenticated successfully (yet)\n"); +} + +/** + * Callback for clicking on the "Login" button. + * + * @param pWidget Widget this callback is bound to. + * @param pvData Pointer to user-supplied data. + */ +#ifdef VBOX_WITH_FLTK +void cb_btn_login(Fl_Widget *pWidget, void *pvData) +#else +void cb_btn_login(GtkWidget *pWidget, gpointer pvData) +#endif +{ + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtr(pCtx); + +#ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pEdtUsername); + const char *pszUser = pCtx->pEdtUsername->value(); + AssertPtr(pCtx->pEdtPassword); + const char *pszPwd = pCtx->pEdtPassword->value(); +#else + GtkEntry *pEdtUser = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_USER)); + AssertPtr(pEdtUser); + const gchar *pszUser = gtk_entry_get_text(pEdtUser); + + GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_PASSWORD)); + AssertPtr(pEdtPwd); + const gchar *pszPwd = gtk_entry_get_text(pEdtPwd); +#endif + + /** @todo Add domain handling? */ + vboxGreeterLog("login button pressed: greeter=%p, user=%s, password=%s\n", + pCtx->pGreeter, + pszUser ? pszUser : "<NONE>", +#ifdef DEBUG + pszPwd ? pszPwd : "<NONE>"); +#else + /* Don't log passwords in release mode! */ + "XXX"); +#endif + if (strlen(pszUser)) /* Only authenticate if username is given. */ + { + lightdm_greeter_respond(pCtx->pGreeter, pszPwd); + lightdm_greeter_authenticate(pCtx->pGreeter, pszUser); + } +} + +/** + * Callback for clicking on the "Menu" button. + * + * @param pWidget Widget this callback is bound to. + * @param pvData Pointer to user-supplied data. + */ +#ifdef VBOX_WITH_FLTK +void cb_btn_menu(Fl_Widget *pWidget, void *pvData) +#else +void cb_btn_menu(GtkWidget *pWidget, gpointer pvData) +#endif +{ + vboxGreeterLog("menu button pressed\n"); +} + +/** + * Callback for clicking on the "Restart" button / menu entry. + * + * @param pWidget Widget this callback is bound to. + * @param pvData Pointer to user-supplied data. + */ +#ifdef VBOX_WITH_FLTK +void cb_btn_restart(Fl_Widget *pWidget, void *pvData) +#else +void cb_btn_restart(GtkWidget *pWidget, gpointer pvData) +#endif +{ + vboxGreeterLog("restart button pressed\n"); + + bool fRestart = true; +#ifdef VBOX_WITH_FLTK + int rc = fl_choice("Really restart the system?", "Yes", "No", NULL); + fRestart = rc == 0; +#endif + + if (fRestart) + { + vboxGreeterLog("restart requested\n"); +#ifndef DEBUG + lightdm_restart(NULL); +#endif + } +} + +/** + * Callback for clicking on the "Shutdown" button / menu entry. + * + * @param pWidget Widget this callback is bound to. + * @param pvData Pointer to user-supplied data. + */ +#ifdef VBOX_WITH_FLTK +void cb_btn_shutdown(Fl_Widget *pWidget, void *pvData) +#else +void cb_btn_shutdown(GtkWidget *pWidget, gpointer pvData) +#endif +{ + vboxGreeterLog("shutdown button pressed\n"); + + bool fShutdown = true; +#ifdef VBOX_WITH_FLTK + int rc = fl_choice("Really shutdown the system?", "Yes", "No", NULL); + fShutdown = rc == 0; +#endif + + if (fShutdown) + { + vboxGreeterLog("shutdown requested\n"); +#ifndef DEBUG + lightdm_shutdown(NULL); +#endif + } +} + +#ifdef VBOX_WITH_FLTK +void cb_edt_username(Fl_Widget *pWidget, void *pvData) +#else +void cb_edt_username(GtkWidget *pWidget, gpointer pvData) +#endif +{ + vboxGreeterLog("cb_edt_username called\n"); + + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtr(pCtx); +#ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pEdtPassword); + Fl::focus(pCtx->pEdtPassword); +#endif +} + +#ifdef VBOX_WITH_FLTK +void cb_edt_password(Fl_Widget *pWidget, void *pvData) +#else +void cb_edt_password(GtkWidget *pWidget, gpointer pvData) +#endif +{ + vboxGreeterLog("cb_edt_password called\n"); + + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtr(pCtx); +#ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pBtnLogin); + cb_btn_login(pCtx->pBtnLogin, pvData); +#endif +} + +/** + * Callback for the timer event which is checking for new credentials + * from the host. + * + * @param pvData Pointer to user-supplied data. + */ +#ifdef VBOX_WITH_FLTK +static void cb_check_creds(void *pvData) +#else +static gboolean cb_check_creds(gpointer pvData) +#endif +{ + PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData; + AssertPtr(pCtx); + +#ifdef DEBUG + vboxGreeterLog("cb_check_creds called, clientId=%RU32, timeoutMS=%RU32\n", + pCtx->uClientId, pCtx->uTimeoutMS); +#endif + + int rc = VINF_SUCCESS; + +#ifdef VBOX_WITH_GUEST_PROPS + bool fAbort = false; + char szVal[255]; + if (pCtx->uClientId) + { + uint64_t tsAbort; + rc = vbox_read_prop(pCtx->uClientId, + "/VirtualBox/GuestAdd/PAM/CredsWaitAbort", + true /* Read-only on guest */, + szVal, sizeof(szVal), &tsAbort); + switch (rc) + { + case VINF_SUCCESS: +# ifdef DEBUG + vboxGreeterLog("cb_check_creds: tsAbort %RU64 <-> %RU64\n", + pCtx->uTsAbort, tsAbort); +# endif + if (tsAbort != pCtx->uTsAbort) + fAbort = true; /* Timestamps differs, abort. */ + pCtx->uTsAbort = tsAbort; + break; + + case VERR_TOO_MUCH_DATA: + vboxGreeterError("cb_check_creds: temporarily unable to get abort notification\n"); + break; + + case VERR_NOT_FOUND: + /* Value not found, continue checking for credentials. */ + break; + + default: + vboxGreeterError("cb_check_creds: the abort notification request failed with rc=%Rrc\n", rc); + fAbort = true; /* Abort on error. */ + break; + } + } + + if (fAbort) + { + /* Get optional message. */ + szVal[0] = '\0'; + int rc2 = vbox_read_prop(pCtx->uClientId, + "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if ( RT_FAILURE(rc2) + && rc2 != VERR_NOT_FOUND) + vboxGreeterError("cb_check_creds: getting wait abort message failed with rc=%Rrc\n", rc2); +# ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pLblInfo); + pCtx->pLblInfo->copy_label(szVal); +# else /* !VBOX_WITH_FLTK */ + GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO)); + AssertPtr(pLblInfo); + gtk_label_set_text(pLblInfo, szVal); +# endif /* !VBOX_WITH_FLTK */ + vboxGreeterLog("cb_check_creds: got notification from host to abort waiting\n"); + } + else + { +#endif /* VBOX_WITH_GUEST_PROPS */ + rc = vboxGreeterCheckCreds(pCtx); + if (RT_SUCCESS(rc)) + { + /* Credentials retrieved. */ + } + else if (rc == VERR_NOT_FOUND) + { + /* No credentials found, but try next round (if there's + * time left for) ... */ + } +#ifdef VBOX_WITH_GUEST_PROPS + } +#endif /* VBOX_WITH_GUEST_PROPS */ + + if (rc == VERR_NOT_FOUND) /* No credential found this round. */ + { + /* Calculate timeout value left after process has been started. */ + uint64_t u64Elapsed = RTTimeMilliTS() - pCtx->uStartMS; + /* Is it time to bail out? */ + if (pCtx->uTimeoutMS < u64Elapsed) + { +#ifdef VBOX_WITH_GUEST_PROPS + szVal[0] = '\0'; + int rc2 = vbox_read_prop(pCtx->uClientId, + "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if ( RT_FAILURE(rc2) + && rc2 != VERR_NOT_FOUND) + vboxGreeterError("cb_check_creds: getting wait timeout message failed with rc=%Rrc\n", rc2); +# ifdef VBOX_WITH_FLTK + AssertPtr(pCtx->pLblInfo); + pCtx->pLblInfo->copy_label(szVal); +# else + GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO)); + AssertPtr(pLblInfo); + gtk_label_set_text(pLblInfo, szVal); +# endif +#endif /* VBOX_WITH_GUEST_PROPS */ + vboxGreeterLog("cb_check_creds: no credentials retrieved within time (%RU32ms), giving up\n", + pCtx->uTimeoutMS); + rc = VERR_TIMEOUT; + } + } + +#ifdef DEBUG + vboxGreeterLog("cb_check_creds returned with rc=%Rrc\n", rc); +#endif + + /* At the moment we only allow *one* shot from the host, + * so setting credentials in a second attempt won't be possible + * intentionally. */ + + if (rc == VERR_NOT_FOUND) +#ifdef VBOX_WITH_FLTK + Fl::repeat_timeout(0.5 /* 500 ms */, cb_check_creds, pvData); +#else + return TRUE; /* No credentials found, do another round. */ + + return FALSE; /* Remove timer source on every other error / status. */ +#endif +} + +/** + * Release logger callback. + * + * @return IPRT status code. + * @param pLoggerRelease + * @param enmPhase + * @param pfnLog + */ +static void vboxGreeterLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog) +{ + /* Some introductory information. */ + static RTTIMESPEC s_TimeSpec; + char szTmp[256]; + if (enmPhase == RTLOGPHASE_BEGIN) + RTTimeNow(&s_TimeSpec); + RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp)); + + switch (enmPhase) + { + case RTLOGPHASE_BEGIN: + { + pfnLog(pLoggerRelease, + "vbox-greeter %s r%s (verbosity: %d) %s (%s %s) release log\n" + "Log opened %s\n", + RTBldCfgVersion(), RTBldCfgRevisionStr(), g_iVerbosity, VBOX_BUILD_TARGET, + __DATE__, __TIME__, szTmp); + + int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp)); + if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) + pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp); + vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp)); + if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) + pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp); + vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp)); + if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) + pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp); + if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) + pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp); + + /* the package type is interesting for Linux distributions */ + char szExecName[RTPATH_MAX]; + char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName)); + pfnLog(pLoggerRelease, + "Executable: %s\n" + "Process ID: %u\n" + "Package type: %s" +#ifdef VBOX_OSE + " (OSE)" +#endif + "\n", + pszExecName ? pszExecName : "unknown", + RTProcSelf(), + VBOX_PACKAGE_STRING); + break; + } + + case RTLOGPHASE_PREROTATE: + pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp); + break; + + case RTLOGPHASE_POSTROTATE: + pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp); + break; + + case RTLOGPHASE_END: + pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp); + break; + + default: + /* nothing */; + } +} + +/** + * Creates the default release logger outputting to the specified file. + * + * @return IPRT status code. + * @param pszLogFile Filename for log output. Optional. + */ +static int vboxGreeterLogCreate(const char *pszLogFile) +{ + /* Create release logger (stdout + file). */ + static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; + RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + fFlags |= RTLOGFLAGS_USECRLF; +#endif + char szError[RTPATH_MAX + 128] = ""; + int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all", + "VBOXGREETER_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, + RTLOGDEST_STDOUT, + vboxGreeterLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime, + szError, sizeof(szError), pszLogFile); + if (RT_SUCCESS(rc)) + { + /* register this logger as the release logger */ + RTLogRelSetDefaultInstance(g_pLoggerRelease); + + /* Explicitly flush the log in case of VBOXGREETER_RELEASE_LOG_FLAGS=buffered. */ + RTLogFlush(g_pLoggerRelease); + } + + return rc; +} + +static void vboxGreeterLogDestroy(void) +{ + RTLogDestroy(RTLogRelSetDefaultInstance(NULL)); +} + +static int vboxGreeterUsage(void) +{ + RTPrintf("Usage:\n" + " %-12s [-h|-?|--help] [-F|--logfile <file>]\n" + " [-v|--verbose] [-V|--version]\n", g_pszProgName); + + RTPrintf("\n" + " Copyright (C) 2012-" VBOX_C_YEAR " " VBOX_VENDOR "\n"); + + return RTEXITCODE_SYNTAX; +} + +int main(int argc, char **argv) +{ + int rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + g_pszProgName = RTPathFilename(argv[0]); + + static const RTGETOPTDEF s_aOptions[] = + { + { "--logfile", 'F', RTGETOPT_REQ_STRING }, + { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, + { "--version", 'V', RTGETOPT_REQ_NOTHING } + }; + + char szLogFile[RTPATH_MAX + 128] = ""; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, + s_aOptions, RT_ELEMENTS(s_aOptions), + 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST); + + while ( (ch = RTGetOpt(&GetState, &ValueUnion)) + && RT_SUCCESS(rc)) + { + /* For options that require an argument, ValueUnion has received the value. */ + switch (ch) + { + case 'F': + if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", ValueUnion.psz)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get prepare log file name"); + break; + + case 'h': + case '?': + return vboxGreeterUsage(); + + case 'v': /* Raise verbosity. */ + g_iVerbosity++; + break; + + case 'V': /* Print version and exit. */ + RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); + return RTEXITCODE_SUCCESS; + break; /* Never reached. */ + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + if (RT_FAILURE(rc)) + return RTEXITCODE_SYNTAX; + + rc = VbglR3InitUser(); + if (RT_FAILURE(rc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to init Vbgl (%Rrc)", rc); + + rc = vboxGreeterLogCreate(strlen(szLogFile) ? szLogFile : NULL); + if (RT_FAILURE(rc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)", + strlen(szLogFile) ? szLogFile : "<None>", rc); + + vboxGreeterLog("init\n"); + + signal(SIGTERM, cb_sigterm); + + /** @todo This function already is too long. Move code into + * functions. */ + + VBOXGREETERCTX ctx; + RT_ZERO(ctx); + + /* UI parameters. */ + uint32_t uBgColor = 0; /* The background color. */ + uint32_t uLogonDlgHdrColor = 0; + uint32_t uLogonDlgBgColor = 0; /* The greeter's dialog color. */ + uint32_t uLogonDlgBtnColor = 0; /* The greeter's button color. */ + + char szBannerPath[RTPATH_MAX]; + + /* By default most UI elements are shown. */ + uint32_t uOptsUI = VBOX_GREETER_UI_SHOW_RESTART + | VBOX_GREETER_UI_SHOW_SHUTDOWN; +#ifdef VBOX_WITH_GUEST_PROPS + uint32_t uClientId = 0; + rc = VbglR3GuestPropConnect(&uClientId); + if (RT_SUCCESS(rc)) + { + vboxGreeterLog("clientId=%RU32\n", uClientId); + + ctx.uClientId = uClientId; + + char szVal[256]; + int rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/HideRestart", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if ( RT_SUCCESS(rc2) + && !RTStrICmp(szVal, "1")) + { + uOptsUI &= ~VBOX_GREETER_UI_SHOW_RESTART; + } + + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/HideShutdown", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if ( RT_SUCCESS(rc2) + && !RTStrICmp(szVal, "1")) + { + uOptsUI &= ~VBOX_GREETER_UI_SHOW_SHUTDOWN; + } + +# ifdef VBOX_GREETER_WITH_PNG_SUPPORT + /* Load the banner. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/BannerPath", + true /* Read-only on guest */, + szBannerPath, sizeof(szBannerPath), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + if (RTFileExists(szBannerPath)) + { + vboxGreeterLog("showing banner from '%s'\n", szBannerPath); + uOptsUI |= VBOX_GREETER_UI_SHOW_BANNER; + } + else + vboxGreeterLog("warning: unable to find banner at '%s', skipping\n", szBannerPath); + } +# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */ + + /* Use theming?. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/UseTheming", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if ( RT_SUCCESS(rc2) + && !RTStrICmp(szVal, "1")) + { + vboxGreeterLog("custom theming enabled\n"); + uOptsUI |= VBOX_GREETER_UI_USE_THEMING; + } + + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + { + /* Get background color. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/Theme/BackgroundColor", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uBgColor = strtol(szVal, NULL, + /* Change conversion base when having a 0x prefix. */ + RTStrStr(szVal, "0x") == szVal ? 0 : 16); + } + + /* Logon dialog. */ + + /* Get header color. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/HeaderColor", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uLogonDlgHdrColor = strtol(szVal, NULL, + /* Change conversion base when having a 0x prefix. */ + RTStrStr(szVal, "0x") == szVal ? 0 : 16); + } + + /* Get dialog color. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/BackgroundColor", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uLogonDlgBgColor = strtol(szVal, NULL, + /* Change conversion base when having a 0x prefix. */ + RTStrStr(szVal, "0x") == szVal ? 0 : 16); + } + + /* Get button color. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/ButtonColor", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uLogonDlgBtnColor = strtol(szVal, NULL, + /* Change conversion base when having a 0x prefix. */ + RTStrStr(szVal, "0x") == szVal ? 0 : 16); + } + } + } + else + vboxGreeterError("unable to connect to guest property service, rc=%Rrc\n", rc); +#endif + vboxGreeterLog("UI options are: %RU32\n", uOptsUI); + +#ifdef VBOX_WITH_FLTK + int rc2 = Fl::scheme("plastic"); + if (!rc2) + vboxGreeterLog("warning: unable to set visual scheme\n"); + + Fl::visual(FL_DOUBLE | FL_INDEX); + Fl_Double_Window *pWndMain = new Fl_Double_Window(Fl::w(), Fl::h(), "VirtualBox Guest Additions"); + AssertPtr(pWndMain); + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + pWndMain->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uBgColor), + VBOX_RGB_COLOR_GREEN(uBgColor), + VBOX_RGB_COLOR_BLUE(uBgColor))); + else /* Default colors. */ + pWndMain->color(fl_rgb_color(0x73, 0x7F, 0x8C)); + + Fl_Double_Window *pWndGreeter = new Fl_Double_Window(500, 350); + AssertPtr(pWndGreeter); + pWndGreeter->set_modal(); + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + pWndGreeter->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBgColor), + VBOX_RGB_COLOR_GREEN(uLogonDlgBgColor), + VBOX_RGB_COLOR_BLUE(uLogonDlgBgColor))); + else /* Default colors. */ + pWndGreeter->color(fl_rgb_color(255, 255, 255)); + + uint32_t uOffsetX = 130; + /** + * For now we're using a simple Y offset for moving all elements + * down if a banner needs to be shown on top of the greeter. Not + * very clean but does the job. Use some more layouting stuff + * when this gets more complex. + */ + uint32_t uOffsetY = 80; + +# ifdef VBOX_GREETER_WITH_PNG_SUPPORT + fl_register_images(); + + /** @todo Add basic image type detection based on file + * extension. */ + + Fl_PNG_Image *pImgBanner = NULL; + if (uOptsUI & VBOX_GREETER_UI_SHOW_BANNER) + { + pImgBanner = new Fl_PNG_Image(szBannerPath); + AssertPtr(pImgBanner); + + /** @todo Make the banner size configurable via guest + * properties. For now it's hardcoded to 460 x 90px. */ + Fl_Box *pBoxBanner = new Fl_Box(20, uOffsetY, 460, 90, ""); + AssertPtr(pBoxBanner); + pBoxBanner->image(pImgBanner); + + uOffsetY = 120; + } +# endif + + Fl_Box *pLblHeader = new Fl_Box(FL_NO_BOX, 242, uOffsetY, 300, 20, + "Desktop Login"); + AssertPtr(pLblHeader); + + /** Note to use an own font: + * Fl_Font myfnt = FL_FREE_FONT + 1; + * Fl::set_font(myfnt, "MyFont"); */ + Fl_Font fntHeader = FL_FREE_FONT; + Fl::set_font(fntHeader, "Courier"); + + pLblHeader->align(FL_ALIGN_LEFT); + pLblHeader->labelfont(FL_BOLD); + pLblHeader->labelsize(24); + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + pLblHeader->labelcolor(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgHdrColor), + VBOX_RGB_COLOR_GREEN(uLogonDlgHdrColor), + VBOX_RGB_COLOR_BLUE(uLogonDlgHdrColor))); + else /* Default color. */ + pLblHeader->labelcolor(fl_rgb_color(0x51, 0x5F, 0x77)); + uOffsetY += 40; + + /** @todo Add basic NLS support. */ + + Fl_Input *pEdtUsername = new Fl_Input(uOffsetX, uOffsetY, + 300, 20, "User Name"); + AssertPtr(pEdtUsername); + pEdtUsername->callback(cb_edt_username, &ctx); + pEdtUsername->when(FL_WHEN_ENTER_KEY_ALWAYS); + Fl::focus(pEdtUsername); + ctx.pEdtUsername = pEdtUsername; + + Fl_Secret_Input *pEdtPassword = new Fl_Secret_Input(uOffsetX, uOffsetY + 40, + 300, 20, "Password"); + AssertPtr(pEdtPassword); + pEdtPassword->callback(cb_edt_password, &ctx); + pEdtPassword->when(FL_WHEN_ENTER_KEY_ALWAYS); + ctx.pEdtPassword = pEdtPassword; + + Fl_Button *pBtnLogin = new Fl_Button(uOffsetX, uOffsetY + 70, + 100, 40, "Log In"); + AssertPtr(pBtnLogin); + pBtnLogin->callback(cb_btn_login, &ctx); + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + pBtnLogin->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor), + VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor), + VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor))); + else /* Default color. */ + pBtnLogin->color(fl_rgb_color(255, 255, 255)); + ctx.pBtnLogin = pBtnLogin; + + Fl_Menu_Button *pBtnMenu = new Fl_Menu_Button(uOffsetX + 120, uOffsetY + 70, + 100, 40, "Options"); + AssertPtr(pBtnMenu); + pBtnMenu->callback(cb_btn_menu, &ctx); + if (uOptsUI & VBOX_GREETER_UI_USE_THEMING) + pBtnMenu->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor), + VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor), + VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor))); + else /* Default color. */ + pBtnMenu->color(fl_rgb_color(255, 255, 255)); + + if (uOptsUI & VBOX_GREETER_UI_SHOW_RESTART) + pBtnMenu->add("Restart", "" /* Shortcut */, cb_btn_restart, &ctx, 0 /* Flags */); + if (uOptsUI & VBOX_GREETER_UI_SHOW_SHUTDOWN) + pBtnMenu->add("Shutdown", "" /* Shortcut */, cb_btn_shutdown, &ctx, 0 /* Flags */); + + char szLabel[255]; + RTStrPrintf(szLabel, sizeof(szLabel), "Oracle VM VirtualBox Guest Additions %sr%s", + RTBldCfgVersion(), RTBldCfgRevisionStr()); + Fl_Box *pLblInfo = new Fl_Box(FL_NO_BOX , 50, uOffsetY + 150, + 400, 20, szLabel); + AssertPtr(pLblInfo); + ctx.pLblInfo = pLblInfo; + + pWndGreeter->end(); + pWndGreeter->position((Fl::w() - pWndGreeter->w()) / 2, + (Fl::h() - pWndGreeter->h()) / 2); + + pWndMain->fullscreen(); + pWndMain->show(argc, argv); + pWndMain->end(); + + pWndGreeter->show(); +#else /* !VBOX_WITH_FLTK */ + gtk_init(&argc, &argv); + + /* Set default cursor */ + gdk_window_set_cursor(gdk_get_default_root_window(), gdk_cursor_new(GDK_LEFT_PTR)); + + GError *pError = NULL; + GtkBuilder *pBuilder = gtk_builder_new(); + AssertPtr(pBuilder); + if (!gtk_builder_add_from_file(pBuilder, "/usr/share/xgreeters/vbox-greeter.ui", &pError)) + { + AssertPtr(pError); + vboxGreeterError("unable to load UI: %s", pError->message); + return RTEXITCODE_FAILURE; + } + + GtkWindow *pWndGreeter = GTK_WINDOW(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_WND_GREETER)); + AssertPtr(pWndGreeter); + GtkButton *pBtnLogin = GTK_BUTTON(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_BTN_LOGIN)); + AssertPtr(pBtnLogin); + GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_LBL_INFO)); + AssertPtr(pLblInfo); + + ctx.pBuilder = pBuilder; + + g_signal_connect(G_OBJECT(pBtnLogin), "clicked", G_CALLBACK(cb_btn_login), &ctx); + + GdkRectangle rectScreen; + gdk_screen_get_monitor_geometry(gdk_screen_get_default(), gdk_screen_get_primary_monitor(gdk_screen_get_default()), &rectScreen); + vboxGreeterLog("monitor (default) is %dx%d\n", rectScreen.width, rectScreen.height); + + gint iWndX, iWndY; + gtk_window_get_default_size(pWndGreeter, &iWndX, &iWndY); + vboxGreeterLog("greeter is %dx%d\n", iWndX, iWndY); + + gtk_window_move(pWndGreeter, + (rectScreen.width / 2) - (iWndX / 2), + (rectScreen.height / 2) - (iWndY / 2)); + gtk_widget_show(GTK_WIDGET(pWndGreeter)); + + g_clear_error(&pError); +#endif /* !VBOX_WITH_FLTK */ + + /* GType is needed in any case (for LightDM), whether we + * use GTK3 or not. */ + g_type_init(); + + GMainLoop *pMainLoop = g_main_loop_new(NULL, FALSE /* Not yet running */); + AssertPtr(pMainLoop); + + LightDMGreeter *pGreeter = lightdm_greeter_new(); + AssertPtr(pGreeter); + + g_signal_connect(pGreeter, "show-prompt", G_CALLBACK(cb_lightdm_show_prompt), &ctx); + g_signal_connect(pGreeter, "show-message", G_CALLBACK(cb_lightdm_show_message), &ctx); + g_signal_connect(pGreeter, "authentication-complete", G_CALLBACK(cb_lightdm_auth_complete), &ctx); + + ctx.pGreeter = pGreeter; + + if (!lightdm_greeter_connect_sync(pGreeter, NULL)) + { + vboxGreeterError("unable to connect to LightDM server, aborting\n"); + return RTEXITCODE_FAILURE; + } + + vboxGreeterLog("connected to LightDM server\n"); + +#ifdef VBOX_WITH_GUEST_PROPS + bool fCheckCreds = false; + if (uClientId) /* Connected to guest property service? */ + { + char szVal[256]; + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/PAM/CredsWait", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */ + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { + uTimeoutMS = RTStrToUInt32(szVal); + if (!uTimeoutMS) + { + vboxGreeterError("pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n"); + uTimeoutMS = RT_INDEFINITE_WAIT; + } + else + uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */ + } + + ctx.uTimeoutMS = uTimeoutMS; + + rc2 = vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting", + true /* Read-only on guest */, + szVal, sizeof(szVal), NULL /* Timestamp. */); + if (RT_SUCCESS(rc2)) + { +# ifdef VBOX_WITH_FLTK + Assert(pLblInfo); + pLblInfo->copy_label(szVal); +# else + gtk_label_set_text(pLblInfo, szVal); +# endif + } + + /* Get initial timestamp so that we can compare the time + * whether the value has been changed or not in our event callback. */ + vbox_read_prop(uClientId, + "/VirtualBox/GuestAdd/PAM/CredsWaitAbort", + true /* Read-only on guest */, + szVal, sizeof(szVal), &ctx.uTsAbort); + + if (RT_SUCCESS(rc)) + { + /* Before we actuall wait for credentials just make sure we didn't already get credentials + * set so that we can skip waiting for them ... */ + rc2 = vboxGreeterCheckCreds(&ctx); + if (rc2 == VERR_NOT_FOUND) + { + /* Get current time stamp to later calculate rest of timeout left. */ + ctx.uStartMS = RTTimeMilliTS(); + + fCheckCreds = true; + } + } + } + + /* Start the timer to check credentials availability. */ + if (fCheckCreds) + { + vboxGreeterLog("No credentials available on startup, starting to check periodically ...\n"); +# ifdef VBOX_WITH_FLTK + Fl::add_timeout(0.5 /* 500 ms */, cb_check_creds, &ctx); +# else + g_timeout_add(500 /* ms */, (GSourceFunc)cb_check_creds, &ctx); +# endif + } + } +#endif /* VBOX_WITH_GUEST_PROPS */ + +#ifdef VBOX_WITH_FLTK + /* + * Do own GDK main loop processing because FLTK also needs + * to have the chance of processing its events. + */ + GMainContext *pMainCtx = g_main_context_default(); + AssertPtr(pMainCtx); + + while (g_fRunning) + { + g_main_context_iteration(pMainCtx, + FALSE /* No blocking */); + Fl::check(); + RTThreadSleep(10); /* Wait a bit, don't hog the CPU too much. */ + } + + g_main_context_unref(pMainCtx); + +# ifdef VBOX_GREETER_WITH_PNG_SUPPORT + if (pImgBanner) + { + delete pImgBanner; /* Call destructor to free bitmap data. */ + pImgBanner = NULL; + } +# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */ +#else /* !VBOX_WITH_FLTK */ + gtk_main(); + /** @todo Never reached so far. LightDM sends a SIGTERM. */ +#endif /* !VBOX_WITH_FLTK */ + + vboxGreeterLog("terminating\n"); + +#ifdef VBOX_WITH_GUEST_PROPS + if (uClientId) + { + rc2 = VbglR3GuestPropDisconnect(uClientId); + AssertRC(rc2); + } +#endif /* VBOX_WITH_GUEST_PROPS */ + + VbglR3Term(); + + RTEXITCODE rcExit = RT_SUCCESS(rc) + ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; + + vboxGreeterLog("terminated with exit code %ld (rc=%Rrc)\n", + rcExit, rc); + + vboxGreeterLogDestroy(); + + return rcExit; +} + +#ifdef DEBUG +DECLEXPORT(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction) +{ + RTAssertMsg1(pszExpr, uLine, pszFile, pszFunction); +} +#endif + diff --git a/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.desktop b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.desktop new file mode 100644 index 00000000..b3946b38 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=VirtualBox Greeter +Comment=Provides Single Sign-On (SSO) support +Exec=/usr/sbin/vbox-greeter +Type=Application diff --git a/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.ui b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.ui new file mode 100644 index 00000000..76719b39 --- /dev/null +++ b/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.ui @@ -0,0 +1,227 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <object class="GtkWindow" id="wnd_greeter"> + <property name="width_request">512</property> + <property name="height_request">348</property> + <property name="can_focus">False</property> + <property name="title" translatable="yes">VirtualBox Guest Additions Login</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="window_position">center</property> + <property name="default_width">512</property> + <property name="default_height">348</property> + <property name="has_resize_grip">False</property> + <child> + <object class="GtkNotebook" id="nb_greeter"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkDrawingArea" id="drawingarea1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkAspectFrame" id="aspectframe3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">center</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="n_columns">2</property> + <child> + <object class="GtkEntry" id="edt_password"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + <property name="activates_default">True</property> + <property name="invisible_char_set">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="edt_username"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_right">20</property> + <property name="xalign">0</property> + <property name="ypad">10</property> + <property name="label" translatable="yes">Username</property> + <property name="justify">center</property> + <attributes> + <attribute name="weight" value="ultraheavy"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_right">20</property> + <property name="xalign">0</property> + <property name="ypad">10</property> + <property name="label" translatable="yes">Password</property> + <attributes> + <attribute name="weight" value="ultraheavy"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="btn_login"> + <property name="label" translatable="yes">Login</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="lbl_info"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="valign">end</property> + <property name="label" translatable="yes">VirtualBox Guest Additions</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="lblLogin"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Login</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkAspectFrame" id="aspectframe2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">VirtualBox Guest Additions Auto-Logon</property> + <property name="justify">center</property> + <attributes> + <attribute name="weight" value="ultraheavy"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="lblInformation"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Information</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + </object> + </child> + </object> +</interface> + diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c index f7f558a0..dcaddab1 100644 --- a/src/VBox/Additions/linux/sharedfolders/dirops.c +++ b/src/VBox/Additions/linux/sharedfolders/dirops.c @@ -233,7 +233,11 @@ static int sf_getdent(struct file *dir, char d_name[NAME_MAX]) * b. failure to compute fake inode number * c. filldir returns an error (see comment on that) */ -static int sf_dir_read (struct file *dir, void *opaque, filldir_t filldir) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) +static int sf_dir_iterate(struct file *dir, struct dir_context *ctx) +#else +static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir) +#endif { TRACE(); for (;;) @@ -257,12 +261,19 @@ static int sf_dir_read (struct file *dir, void *opaque, filldir_t filldir) /* skip erroneous entry and proceed */ LogFunc(("sf_getdent error %d\n", err)); dir->f_pos += 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + ctx->pos += 1; +#endif continue; } /* d_name now contains a valid entry name */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + sanity = ctx->pos + 0xbeef; +#else sanity = dir->f_pos + 0xbeef; +#endif fake_ino = sanity; if (sanity - fake_ino) { @@ -270,8 +281,14 @@ static int sf_dir_read (struct file *dir, void *opaque, filldir_t filldir) return -EINVAL; } - err = filldir(opaque, d_name, strlen(d_name), - dir->f_pos, fake_ino, DT_UNKNOWN); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, DT_UNKNOWN)) + { + LogFunc(("dir_emit failed\n")); + return 0; + } +#else + err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, DT_UNKNOWN); if (err) { LogFunc(("filldir returned error %d\n", err)); @@ -279,8 +296,12 @@ static int sf_dir_read (struct file *dir, void *opaque, filldir_t filldir) only when it runs out of space in opaque */ return 0; } +#endif dir->f_pos += 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + ctx->pos += 1; +#endif } BUG(); @@ -289,7 +310,11 @@ static int sf_dir_read (struct file *dir, void *opaque, filldir_t filldir) struct file_operations sf_dir_fops = { .open = sf_dir_open, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + .iterate = sf_dir_iterate, +#else .readdir = sf_dir_read, +#endif .release = sf_dir_release, .read = generic_read_dir #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) @@ -451,13 +476,6 @@ static int sf_instantiate(struct inode *parent, struct dentry *dentry, sf_init_inode(sf_g, inode, info); sf_new_i->path = path; SET_INODE_INFO(inode, sf_new_i); - - dentry->d_time = jiffies; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) - d_set_d_op(dentry, &sf_dentry_ops); -#else - dentry->d_op = &sf_dentry_ops; -#endif sf_new_i->force_restat = 1; sf_new_i->force_reread = 0; diff --git a/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c b/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c index 2bce2849..fd3097a8 100644 --- a/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c +++ b/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c index 9cce1739..a3bbd696 100644 --- a/src/VBox/Additions/linux/sharedfolders/regops.c +++ b/src/VBox/Additions/linux/sharedfolders/regops.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/linux/sharedfolders/utils.c b/src/VBox/Additions/linux/sharedfolders/utils.c index aa9c3965..674af7a5 100644 --- a/src/VBox/Additions/linux/sharedfolders/utils.c +++ b/src/VBox/Additions/linux/sharedfolders/utils.c @@ -144,8 +144,14 @@ void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode, #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + inode->i_uid = make_kuid(current_user_ns(), sf_g->uid); + inode->i_gid = make_kgid(current_user_ns(), sf_g->gid); +#else inode->i_uid = sf_g->uid; inode->i_gid = sf_g->gid; +#endif + inode->i_size = info->cbObject; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && !defined(KERNEL_FC6) inode->i_blksize = 4096; diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.c b/src/VBox/Additions/linux/sharedfolders/vfsmod.c index 4a7e9638..b465a29d 100644 --- a/src/VBox/Additions/linux/sharedfolders/vfsmod.c +++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.c @@ -10,7 +10,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -106,28 +106,43 @@ static int sf_glob_alloc(struct vbsf_mount_info_new *info, struct sf_glob_info * str_name->u16Size = name_len + 1; memcpy(str_name->String.utf8, info->name, name_len + 1); -/* Check if NLS charset is valid and not points to UTF8 table */ -#define VFSMOD_HAS_NLS(_name) \ - (_name[0] && strcmp(_name, "utf8")) - if (VFSMOD_HAS_NLS(info->nls_name)) +#define _IS_UTF8(_str) \ + (strcmp(_str, "utf8") == 0) +#define _IS_EMPTY(_str) \ + (strcmp(_str, "") == 0) + + /* Check if NLS charset is valid and not points to UTF8 table */ + if (info->nls_name[0]) { - sf_g->nls = load_nls(info->nls_name); - if (!sf_g->nls) + if (_IS_UTF8(info->nls_name)) + sf_g->nls = NULL; + else { - err = -EINVAL; - LogFunc(("failed to load nls %s\n", info->nls_name)); - goto fail1; + sf_g->nls = load_nls(info->nls_name); + if (!sf_g->nls) + { + err = -EINVAL; + LogFunc(("failed to load nls %s\n", info->nls_name)); + goto fail1; + } } } else { - /* If no NLS charset specified, try to load the default one */ - if (VFSMOD_HAS_NLS(CONFIG_NLS_DEFAULT)) +#ifdef CONFIG_NLS_DEFAULT + /* If no NLS charset specified, try to load the default + * one if it's not points to UTF8. */ + if (!_IS_UTF8(CONFIG_NLS_DEFAULT) && !_IS_EMPTY(CONFIG_NLS_DEFAULT)) sf_g->nls = load_nls_default(); else sf_g->nls = NULL; +#else + sf_g->nls = NULL; +#endif + +#undef _IS_UTF8 +#undef _IS_EMPTY } -#undef VFSMOD_HAS_NLS rc = vboxCallMapFolder(&client_handle, str_name, &sf_g->map); kfree(str_name); @@ -440,41 +455,40 @@ static int sf_remount_fs(struct super_block *sb, int *flags, char *data) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23) struct sf_glob_info *sf_g; - struct vbsf_mount_info_new *info; struct sf_inode_info *sf_i; struct inode *iroot; SHFLFSOBJINFO fsinfo; int err; - printk(KERN_DEBUG "ENTER: sf_remount_fs\n"); sf_g = GET_GLOB_INFO(sb); BUG_ON(!sf_g); - BUG_ON(data[0] != 0); - info = (struct vbsf_mount_info_new *)data; - BUG_ON( info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0 - || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1 - || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2); - - sf_g->uid = info->uid; - sf_g->gid = info->gid; - sf_g->ttl = info->ttl; - sf_g->dmode = info->dmode; - sf_g->fmode = info->fmode; - sf_g->dmask = info->dmask; - sf_g->fmask = info->fmask; + if (data && data[0] != 0) + { + struct vbsf_mount_info_new *info = + (struct vbsf_mount_info_new *)data; + if ( info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0 + && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 + && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2) + { + sf_g->uid = info->uid; + sf_g->gid = info->gid; + sf_g->ttl = info->ttl; + sf_g->dmode = info->dmode; + sf_g->fmode = info->fmode; + sf_g->dmask = info->dmask; + sf_g->fmask = info->fmask; + } + } iroot = ilookup(sb, 0); if (!iroot) - { - printk(KERN_DEBUG "can't find root inode\n"); return -ENOSYS; - } + sf_i = GET_INODE_INFO(iroot); err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0); BUG_ON(err != 0); sf_init_inode(sf_g, iroot, &fsinfo); /*unlock_new_inode(iroot);*/ - printk(KERN_DEBUG "LEAVE: sf_remount_fs\n"); return 0; #else return -ENOSYS; diff --git a/src/VBox/Additions/linux/testcase/TimesyncBackdoor.c b/src/VBox/Additions/linux/testcase/TimesyncBackdoor.c index c35956f1..e78dbb27 100644 --- a/src/VBox/Additions/linux/testcase/TimesyncBackdoor.c +++ b/src/VBox/Additions/linux/testcase/TimesyncBackdoor.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; |