diff options
author | Perberos <[email protected]> | 2011-12-01 23:53:21 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-12-01 23:53:21 -0300 |
commit | 505cabbd3036081f26586cabc64c26e7769c0ec9 (patch) | |
tree | 09e0498bf572128f5c9ab551531cb28d6d75e992 /plugins/smartcard | |
download | mate-settings-daemon-505cabbd3036081f26586cabc64c26e7769c0ec9.tar.bz2 mate-settings-daemon-505cabbd3036081f26586cabc64c26e7769c0ec9.tar.xz |
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'plugins/smartcard')
-rw-r--r-- | plugins/smartcard/Makefile.am | 47 | ||||
-rw-r--r-- | plugins/smartcard/Makefile.in | 684 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-manager.c | 1372 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-manager.h | 90 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-plugin.c | 340 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-plugin.h | 63 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard.c | 555 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard.h | 98 | ||||
-rw-r--r-- | plugins/smartcard/smartcard.mate-settings-plugin.in | 8 |
9 files changed, 3257 insertions, 0 deletions
diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am new file mode 100644 index 0000000..a70e0a0 --- /dev/null +++ b/plugins/smartcard/Makefile.am @@ -0,0 +1,47 @@ +plugin_LTLIBRARIES = \ + libsmartcard.la + +libsmartcard_la_SOURCES = \ + gsd-smartcard-plugin.h \ + gsd-smartcard-plugin.c \ + gsd-smartcard.h \ + gsd-smartcard.c \ + gsd-smartcard-manager.h \ + gsd-smartcard-manager.c + +libsmartcard_la_CPPFLAGS = \ + -I$(top_srcdir)/mate-settings-daemon \ + -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \ + $(AM_CPPFLAGS) + +libsmartcard_la_CFLAGS = \ + $(SETTINGS_PLUGIN_CFLAGS) \ + $(MATE_CFLAGS) \ + $(NSS_CFLAGS) \ + $(AM_CFLAGS) + +libsmartcard_la_LDFLAGS = \ + $(GSD_PLUGIN_LDFLAGS) + +libsmartcard_la_LIBADD = \ + $(SETTINGS_PLUGIN_LIBS) \ + $(NSS_LIBS) + +@GSD_INTLTOOL_PLUGIN_RULE@ + +plugin_in_files = \ + smartcard.mate-settings-plugin.in + +plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin) + +EXTRA_DIST = \ + $(plugin_in_files) + +CLEANFILES = \ + $(plugin_DATA) + +DISTCLEANFILES = \ + $(plugin_DATA) diff --git a/plugins/smartcard/Makefile.in b/plugins/smartcard/Makefile.in new file mode 100644 index 0000000..5e77c45 --- /dev/null +++ b/plugins/smartcard/Makefile.in @@ -0,0 +1,684 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = plugins/smartcard +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libsmartcard_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libsmartcard_la_OBJECTS = libsmartcard_la-gsd-smartcard-plugin.lo \ + libsmartcard_la-gsd-smartcard.lo \ + libsmartcard_la-gsd-smartcard-manager.lo +libsmartcard_la_OBJECTS = $(am_libsmartcard_la_OBJECTS) +libsmartcard_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libsmartcard_la_CFLAGS) \ + $(CFLAGS) $(libsmartcard_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libsmartcard_la_SOURCES) +DIST_SOURCES = $(libsmartcard_la_SOURCES) +DATA = $(plugin_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DBUS_SYS_DIR = @DBUS_SYS_DIR@ +DEBUG_CFLAGS = @DEBUG_CFLAGS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ +FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIOUNIX_CFLAGS = @GIOUNIX_CFLAGS@ +GIOUNIX_LIBS = @GIOUNIX_LIBS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GSD_INTLTOOL_PLUGIN_RULE = @GSD_INTLTOOL_PLUGIN_RULE@ +GSD_PLUGIN_LDFLAGS = @GSD_PLUGIN_LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBEXECDIR = @LIBEXECDIR@ +LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@ +LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@ +LIBMATENOTIFY_CFLAGS = @LIBMATENOTIFY_CFLAGS@ +LIBMATENOTIFY_LIBS = @LIBMATENOTIFY_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATE_KEYBINDINGS_KEYSDIR = @MATE_KEYBINDINGS_KEYSDIR@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_DATABASE = @NSS_DATABASE@ +NSS_LIBS = @NSS_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POLKIT_CFLAGS = @POLKIT_CFLAGS@ +POLKIT_LIBS = @POLKIT_LIBS@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PULSE_CFLAGS = @PULSE_CFLAGS@ +PULSE_LIBS = @PULSE_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SETTINGS_DAEMON_CFLAGS = @SETTINGS_DAEMON_CFLAGS@ +SETTINGS_DAEMON_LIBS = @SETTINGS_DAEMON_LIBS@ +SETTINGS_PLUGIN_CFLAGS = @SETTINGS_PLUGIN_CFLAGS@ +SETTINGS_PLUGIN_LIBS = @SETTINGS_PLUGIN_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +X11_LIBS = @X11_LIBS@ +XF86MISC_LIBS = @XF86MISC_LIBS@ +XGETTEXT = @XGETTEXT@ +XINPUT_LIBS = @XINPUT_LIBS@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +plugin_LTLIBRARIES = \ + libsmartcard.la + +libsmartcard_la_SOURCES = \ + gsd-smartcard-plugin.h \ + gsd-smartcard-plugin.c \ + gsd-smartcard.h \ + gsd-smartcard.c \ + gsd-smartcard-manager.h \ + gsd-smartcard-manager.c + +libsmartcard_la_CPPFLAGS = \ + -I$(top_srcdir)/mate-settings-daemon \ + -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \ + $(AM_CPPFLAGS) + +libsmartcard_la_CFLAGS = \ + $(SETTINGS_PLUGIN_CFLAGS) \ + $(MATE_CFLAGS) \ + $(NSS_CFLAGS) \ + $(AM_CFLAGS) + +libsmartcard_la_LDFLAGS = \ + $(GSD_PLUGIN_LDFLAGS) + +libsmartcard_la_LIBADD = \ + $(SETTINGS_PLUGIN_LIBS) \ + $(NSS_LIBS) + +plugin_in_files = \ + smartcard.mate-settings-plugin.in + +plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin) +EXTRA_DIST = \ + $(plugin_in_files) + +CLEANFILES = \ + $(plugin_DATA) + +DISTCLEANFILES = \ + $(plugin_DATA) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/smartcard/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu plugins/smartcard/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libsmartcard.la: $(libsmartcard_la_OBJECTS) $(libsmartcard_la_DEPENDENCIES) + $(libsmartcard_la_LINK) -rpath $(plugindir) $(libsmartcard_la_OBJECTS) $(libsmartcard_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsmartcard_la-gsd-smartcard-manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsmartcard_la-gsd-smartcard-plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsmartcard_la-gsd-smartcard.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libsmartcard_la-gsd-smartcard-plugin.lo: gsd-smartcard-plugin.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -MT libsmartcard_la-gsd-smartcard-plugin.lo -MD -MP -MF $(DEPDIR)/libsmartcard_la-gsd-smartcard-plugin.Tpo -c -o libsmartcard_la-gsd-smartcard-plugin.lo `test -f 'gsd-smartcard-plugin.c' || echo '$(srcdir)/'`gsd-smartcard-plugin.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsmartcard_la-gsd-smartcard-plugin.Tpo $(DEPDIR)/libsmartcard_la-gsd-smartcard-plugin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-smartcard-plugin.c' object='libsmartcard_la-gsd-smartcard-plugin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -c -o libsmartcard_la-gsd-smartcard-plugin.lo `test -f 'gsd-smartcard-plugin.c' || echo '$(srcdir)/'`gsd-smartcard-plugin.c + +libsmartcard_la-gsd-smartcard.lo: gsd-smartcard.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -MT libsmartcard_la-gsd-smartcard.lo -MD -MP -MF $(DEPDIR)/libsmartcard_la-gsd-smartcard.Tpo -c -o libsmartcard_la-gsd-smartcard.lo `test -f 'gsd-smartcard.c' || echo '$(srcdir)/'`gsd-smartcard.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsmartcard_la-gsd-smartcard.Tpo $(DEPDIR)/libsmartcard_la-gsd-smartcard.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-smartcard.c' object='libsmartcard_la-gsd-smartcard.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -c -o libsmartcard_la-gsd-smartcard.lo `test -f 'gsd-smartcard.c' || echo '$(srcdir)/'`gsd-smartcard.c + +libsmartcard_la-gsd-smartcard-manager.lo: gsd-smartcard-manager.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -MT libsmartcard_la-gsd-smartcard-manager.lo -MD -MP -MF $(DEPDIR)/libsmartcard_la-gsd-smartcard-manager.Tpo -c -o libsmartcard_la-gsd-smartcard-manager.lo `test -f 'gsd-smartcard-manager.c' || echo '$(srcdir)/'`gsd-smartcard-manager.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsmartcard_la-gsd-smartcard-manager.Tpo $(DEPDIR)/libsmartcard_la-gsd-smartcard-manager.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-smartcard-manager.c' object='libsmartcard_la-gsd-smartcard-manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsmartcard_la_CPPFLAGS) $(CPPFLAGS) $(libsmartcard_la_CFLAGS) $(CFLAGS) -c -o libsmartcard_la-gsd-smartcard-manager.lo `test -f 'gsd-smartcard-manager.c' || echo '$(srcdir)/'`gsd-smartcard-manager.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pluginDATA: $(plugin_DATA) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(plugindir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(plugindir)" || exit $$?; \ + done + +uninstall-pluginDATA: + @$(NORMAL_UNINSTALL) + @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(plugindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(plugindir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginDATA uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginDATA \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginDATA uninstall-pluginLTLIBRARIES + + +@GSD_INTLTOOL_PLUGIN_RULE@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c new file mode 100644 index 0000000..a231e20 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -0,0 +1,1372 @@ +/* gsd-smartcard-manager.c - object for monitoring smartcard insertion and + * removal events + * + * Copyright (C) 2006, 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode + */ +#include "config.h" + +#include "gsd-smartcard-manager.h" + +#define SMARTCARD_ENABLE_INTERNAL_API +#include "gsd-smartcard.h" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <glib.h> +#include <glib/gi18n.h> + +#include <prerror.h> +#include <nss.h> +#include <pk11func.h> +#include <secmod.h> +#include <secerr.h> + +#ifndef GSD_SMARTCARD_MANAGER_NSS_DB +#define GSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" +#endif + +typedef enum _GsdSmartcardManagerState GsdSmartcardManagerState; +typedef struct _GsdSmartcardManagerWorker GsdSmartcardManagerWorker; + +enum _GsdSmartcardManagerState { + GSD_SMARTCARD_MANAGER_STATE_STOPPED = 0, + GSD_SMARTCARD_MANAGER_STATE_STARTING, + GSD_SMARTCARD_MANAGER_STATE_STARTED, + GSD_SMARTCARD_MANAGER_STATE_STOPPING, +}; + +struct _GsdSmartcardManagerPrivate { + GsdSmartcardManagerState state; + SECMODModule *module; + char *module_path; + + GSource *smartcard_event_source; + GPid smartcard_event_watcher_pid; + GHashTable *smartcards; + + GThread *worker_thread; + + guint poll_timeout_id; + + guint32 is_unstoppable : 1; + guint32 nss_is_loaded : 1; +}; + +struct _GsdSmartcardManagerWorker { + SECMODModule *module; + GHashTable *smartcards; + int write_fd; + + guint32 nss_is_loaded : 1; +}; + +static void gsd_smartcard_manager_finalize (GObject *object); +static void gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *service_class); +static void gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *service_class); +static void gsd_smartcard_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gsd_smartcard_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager, + const char *module_path); +static void gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager, + GsdSmartcard *card); +static void gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager_class, + GsdSmartcard *card); +static gboolean gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager); +static void gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager); + +static gboolean gsd_smartcard_manager_create_worker (GsdSmartcardManager *manager, + int *worker_fd, GThread **worker_thread); + +static GsdSmartcardManagerWorker * gsd_smartcard_manager_worker_new (int write_fd); +static void gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker); +static gboolean open_pipe (int *write_fd, int *read_fd); +static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes); +static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes); +static GsdSmartcard *read_smartcard (int fd, SECMODModule *module); +static gboolean write_smartcard (int fd, GsdSmartcard *card); + +enum { + PROP_0 = 0, + PROP_MODULE_PATH, + NUMBER_OF_PROPERTIES +}; + +enum { + SMARTCARD_INSERTED = 0, + SMARTCARD_REMOVED, + ERROR, + NUMBER_OF_SIGNALS +}; + +static guint gsd_smartcard_manager_signals[NUMBER_OF_SIGNALS]; + +G_DEFINE_TYPE (GsdSmartcardManager, + gsd_smartcard_manager, + G_TYPE_OBJECT); + +static void +gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *manager_class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (manager_class); + + gobject_class->finalize = gsd_smartcard_manager_finalize; + + gsd_smartcard_manager_class_install_signals (manager_class); + gsd_smartcard_manager_class_install_properties (manager_class); + + g_type_class_add_private (manager_class, + sizeof (GsdSmartcardManagerPrivate)); +} + +static void +gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *card_class) +{ + GObjectClass *object_class; + GParamSpec *param_spec; + + object_class = G_OBJECT_CLASS (card_class); + object_class->set_property = gsd_smartcard_manager_set_property; + object_class->get_property = gsd_smartcard_manager_get_property; + + param_spec = g_param_spec_string ("module-path", _("Module Path"), + _("path to smartcard PKCS #11 driver"), + NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec); +} + +static void +gsd_smartcard_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object); + + switch (prop_id) { + case PROP_MODULE_PATH: + gsd_smartcard_manager_set_module_path (manager, + g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gsd_smartcard_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object); + char *module_path; + + switch (prop_id) { + case PROP_MODULE_PATH: + module_path = gsd_smartcard_manager_get_module_path (manager); + g_value_set_string (value, module_path); + g_free (module_path); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +char * +gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager) +{ + return manager->priv->module_path; +} + +static void +gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager, + const char *module_path) +{ + if ((manager->priv->module_path == NULL) && (module_path == NULL)) { + return; + } + + if (((manager->priv->module_path == NULL) || + (module_path == NULL) || + (strcmp (manager->priv->module_path, module_path) != 0))) { + g_free (manager->priv->module_path); + manager->priv->module_path = g_strdup (module_path); + g_object_notify (G_OBJECT (manager), "module-path"); + } +} + +static void +gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + g_debug ("informing smartcard of its removal"); + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); + g_debug ("done"); +} + +static void +gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + g_debug ("informing smartcard of its insertion"); + + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); + g_debug ("done"); + +} + +static void +gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *manager_class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (manager_class); + + gsd_smartcard_manager_signals[SMARTCARD_INSERTED] = + g_signal_new ("smartcard-inserted", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GsdSmartcardManagerClass, + smartcard_inserted), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + manager_class->smartcard_inserted = gsd_smartcard_manager_card_inserted_handler; + + gsd_smartcard_manager_signals[SMARTCARD_REMOVED] = + g_signal_new ("smartcard-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GsdSmartcardManagerClass, + smartcard_removed), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + manager_class->smartcard_removed = gsd_smartcard_manager_card_removed_handler; + + gsd_smartcard_manager_signals[ERROR] = + g_signal_new ("error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsdSmartcardManagerClass, error), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + manager_class->error = NULL; +} + +static gboolean +slot_id_equal (CK_SLOT_ID *slot_id_1, + CK_SLOT_ID *slot_id_2) +{ + g_assert (slot_id_1 != NULL); + g_assert (slot_id_2 != NULL); + + return *slot_id_1 == *slot_id_2; +} + +static gboolean +slot_id_hash (CK_SLOT_ID *slot_id) +{ + guint32 upper_bits, lower_bits; + int temp; + + if (sizeof (CK_SLOT_ID) == sizeof (int)) { + return g_int_hash (slot_id); + } + + upper_bits = ((*slot_id) >> 31) - 1; + lower_bits = (*slot_id) & 0xffffffff; + + /* The upper bits are almost certainly always zero, + * so let's degenerate to g_int_hash for the + * (very) common case + */ + temp = lower_bits + upper_bits; + return upper_bits + g_int_hash (&temp); +} + +static void +gsd_smartcard_manager_init (GsdSmartcardManager *manager) +{ + g_debug ("initializing smartcard manager"); + + manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + GSD_TYPE_SMARTCARD_MANAGER, + GsdSmartcardManagerPrivate); + manager->priv->poll_timeout_id = 0; + manager->priv->is_unstoppable = FALSE; + manager->priv->module = NULL; + + manager->priv->smartcards = + g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + if (!g_thread_supported ()) { + g_thread_init (NULL); + } + +} + +static void +gsd_smartcard_manager_finalize (GObject *object) +{ + GsdSmartcardManager *manager; + GObjectClass *gobject_class; + + manager = GSD_SMARTCARD_MANAGER (object); + gobject_class = + G_OBJECT_CLASS (gsd_smartcard_manager_parent_class); + + gsd_smartcard_manager_stop_now (manager); + + g_hash_table_destroy (manager->priv->smartcards); + manager->priv->smartcards = NULL; + + gobject_class->finalize (object); +} + +GQuark +gsd_smartcard_manager_error_quark (void) +{ + static GQuark error_quark = 0; + + if (error_quark == 0) { + error_quark = g_quark_from_static_string ("gsd-smartcard-manager-error-quark"); + } + + return error_quark; +} + +GsdSmartcardManager * +gsd_smartcard_manager_new (const char *module_path) +{ + GsdSmartcardManager *instance; + + instance = GSD_SMARTCARD_MANAGER (g_object_new (GSD_TYPE_SMARTCARD_MANAGER, + "module-path", module_path, + NULL)); + + return instance; +} + +static void +gsd_smartcard_manager_emit_error (GsdSmartcardManager *manager, + GError *error) +{ + manager->priv->is_unstoppable = TRUE; + g_signal_emit (manager, gsd_smartcard_manager_signals[ERROR], 0, + error); + manager->priv->is_unstoppable = FALSE; +} + +static void +gsd_smartcard_manager_emit_smartcard_inserted (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + manager->priv->is_unstoppable = TRUE; + g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_INSERTED], 0, + card); + manager->priv->is_unstoppable = FALSE; +} + +static void +gsd_smartcard_manager_emit_smartcard_removed (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + GsdSmartcardManagerState old_state; + + old_state = manager->priv->state; + manager->priv->is_unstoppable = TRUE; + g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_REMOVED], 0, + card); + manager->priv->is_unstoppable = FALSE; +} + +static gboolean +gsd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, + GIOCondition condition, + GsdSmartcardManager *manager) +{ + GsdSmartcard *card; + gboolean should_stop; + gchar event_type; + char *card_name; + int fd; + + card = NULL; + should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR); + + if (should_stop) { + g_debug ("received %s on event socket, stopping " + "manager...", + (condition & G_IO_HUP) && (condition & G_IO_ERR)? + "error and hangup" : + (condition & G_IO_HUP)? + "hangup" : "error"); + } + + if (!(condition & G_IO_IN)) { + goto out; + } + + fd = g_io_channel_unix_get_fd (io_channel); + + event_type = '\0'; + if (!read_bytes (fd, &event_type, 1)) { + should_stop = TRUE; + goto out; + } + + card = read_smartcard (fd, manager->priv->module); + + if (card == NULL) { + should_stop = TRUE; + goto out; + } + + card_name = gsd_smartcard_get_name (card); + + switch (event_type) { + case 'I': + g_hash_table_replace (manager->priv->smartcards, + card_name, card); + card_name = NULL; + + gsd_smartcard_manager_emit_smartcard_inserted (manager, card); + card = NULL; + break; + + case 'R': + gsd_smartcard_manager_emit_smartcard_removed (manager, card); + if (!g_hash_table_remove (manager->priv->smartcards, card_name)) { + g_debug ("got removal event of unknown card!"); + } + g_free (card_name); + card_name = NULL; + card = NULL; + break; + + default: + g_free (card_name); + card_name = NULL; + g_object_unref (card); + + should_stop = TRUE; + break; + } + +out: + if (should_stop) { + GError *error; + + error = g_error_new (GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, + "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); + + gsd_smartcard_manager_emit_error (manager, error); + g_error_free (error); + gsd_smartcard_manager_stop_now (manager); + return FALSE; + } + + return TRUE; +} + +static void +gsd_smartcard_manager_event_processing_stopped_handler (GsdSmartcardManager *manager) +{ + manager->priv->smartcard_event_source = NULL; + gsd_smartcard_manager_stop_now (manager); +} + +static gboolean +open_pipe (int *write_fd, + int *read_fd) +{ + int pipe_fds[2] = { -1, -1 }; + + g_assert (write_fd != NULL); + g_assert (read_fd != NULL); + + if (pipe (pipe_fds) < 0) { + return FALSE; + } + + if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) { + close (pipe_fds[0]); + close (pipe_fds[1]); + return FALSE; + } + + if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) { + close (pipe_fds[0]); + close (pipe_fds[1]); + return FALSE; + } + + *read_fd = pipe_fds[0]; + *write_fd = pipe_fds[1]; + + return TRUE; +} + +static void +gsd_smartcard_manager_stop_watching_for_events (GsdSmartcardManager *manager) +{ + if (manager->priv->smartcard_event_source != NULL) { + g_source_destroy (manager->priv->smartcard_event_source); + manager->priv->smartcard_event_source = NULL; + } + + if (manager->priv->worker_thread != NULL) { + SECMOD_CancelWait (manager->priv->module); + manager->priv->worker_thread = NULL; + } +} + +static gboolean +load_nss (GError **error) +{ + SECStatus status = SECSuccess; + static const guint32 flags = + NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | + NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | + NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD; + + g_debug ("attempting to load NSS database '%s'", + GSD_SMARTCARD_MANAGER_NSS_DB); + + status = NSS_Initialize (GSD_SMARTCARD_MANAGER_NSS_DB, + "", "", SECMOD_DB, flags); + + if (status != SECSuccess) { + gsize error_message_size; + char *error_message; + + error_message_size = PR_GetErrorTextLength (); + + if (error_message_size == 0) { + g_debug ("NSS security system could not be initialized"); + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + _("NSS security system could not be initialized")); + goto out; + } + + error_message = g_slice_alloc0 (error_message_size); + PR_GetErrorText (error_message); + + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + "%s", error_message); + g_debug ("NSS security system could not be initialized - %s", + error_message); + + g_slice_free1 (error_message_size, error_message); + + goto out; + } + + g_debug ("NSS database sucessfully loaded"); + return TRUE; + +out: + g_debug ("NSS database couldn't be sucessfully loaded"); + return FALSE; +} + +static SECMODModule * +load_driver (char *module_path, + GError **error) +{ + SECMODModule *module; + char *module_spec; + gboolean module_explicitly_specified; + + g_debug ("attempting to load driver..."); + + module = NULL; + module_explicitly_specified = module_path != NULL; + if (module_explicitly_specified) { + module_spec = g_strdup_printf ("library=\"%s\"", module_path); + g_debug ("loading smartcard driver using spec '%s'", + module_spec); + + module = SECMOD_LoadUserModule (module_spec, + NULL /* parent */, + FALSE /* recurse */); + g_free (module_spec); + module_spec = NULL; + + } else { + SECMODModuleList *modules, *tmp; + + modules = SECMOD_GetDefaultModuleList (); + + for (tmp = modules; tmp != NULL; tmp = tmp->next) { + if (!SECMOD_HasRemovableSlots (tmp->module) || + !tmp->module->loaded) + continue; + + module = SECMOD_ReferenceModule (tmp->module); + break; + } + } + + if (!module_explicitly_specified && module == NULL) { + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + _("no suitable smartcard driver could be found")); + } else if (module == NULL || !module->loaded) { + + gsize error_message_size; + char *error_message; + + if (module != NULL && !module->loaded) { + g_debug ("module found but not loaded?!"); + SECMOD_DestroyModule (module); + module = NULL; + } + + error_message_size = PR_GetErrorTextLength (); + + if (error_message_size == 0) { + g_debug ("smartcard driver '%s' could not be loaded", + module_path); + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + _("smartcard driver '%s' could not be " + "loaded"), module_path); + goto out; + } + + error_message = g_slice_alloc0 (error_message_size); + PR_GetErrorText (error_message); + + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + "%s", error_message); + + g_debug ("smartcard driver '%s' could not be loaded - %s", + module_path, error_message); + g_slice_free1 (error_message_size, error_message); + } + +out: + return module; +} + +static void +gsd_smartcard_manager_get_all_cards (GsdSmartcardManager *manager) +{ + int i; + + for (i = 0; i < manager->priv->module->slotCount; i++) { + GsdSmartcard *card; + CK_SLOT_ID slot_id; + int slot_series; + char *card_name; + + slot_id = PK11_GetSlotID (manager->priv->module->slots[i]); + slot_series = PK11_GetSlotSeries (manager->priv->module->slots[i]); + + card = _gsd_smartcard_new (manager->priv->module, + slot_id, slot_series); + + card_name = gsd_smartcard_get_name (card); + + g_hash_table_replace (manager->priv->smartcards, + card_name, card); + } +} + +gboolean +gsd_smartcard_manager_start (GsdSmartcardManager *manager, + GError **error) +{ + GError *watching_error; + int worker_fd; + GPid worker_pid; + GIOChannel *io_channel; + GSource *source; + GIOFlags channel_flags; + GError *nss_error; + + if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED) { + g_debug ("smartcard manager already started"); + return TRUE; + } + + manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTING; + + worker_fd = -1; + worker_pid = 0; + + nss_error = NULL; + if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) { + g_propagate_error (error, nss_error); + goto out; + } + manager->priv->nss_is_loaded = TRUE; + + if (manager->priv->module == NULL) { + manager->priv->module = load_driver (manager->priv->module_path, &nss_error); + } + + if (manager->priv->module == NULL) { + g_propagate_error (error, nss_error); + goto out; + } + + if (!gsd_smartcard_manager_create_worker (manager, &worker_fd, &manager->priv->worker_thread)) { + + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, + _("could not watch for incoming card events - %s"), + g_strerror (errno)); + + goto out; + } + + io_channel = g_io_channel_unix_new (worker_fd); + + channel_flags = g_io_channel_get_flags (io_channel); + watching_error = NULL; + + source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); + g_io_channel_unref (io_channel); + io_channel = NULL; + + manager->priv->smartcard_event_source = source; + + g_source_set_callback (manager->priv->smartcard_event_source, + (GSourceFunc) (GIOFunc) + gsd_smartcard_manager_check_for_and_process_events, + manager, + (GDestroyNotify) + gsd_smartcard_manager_event_processing_stopped_handler); + g_source_attach (manager->priv->smartcard_event_source, NULL); + g_source_unref (manager->priv->smartcard_event_source); + + /* populate the hash with cards that are already inserted + */ + gsd_smartcard_manager_get_all_cards (manager); + + manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTED; + +out: + /* don't leave it in a half started state + */ + if (manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STARTED) { + g_debug ("smartcard manager could not be completely started"); + gsd_smartcard_manager_stop (manager); + } else { + g_debug ("smartcard manager started"); + } + + return manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED; +} + +static gboolean +gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager) +{ + if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) { + return FALSE; + } + + manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPED; + gsd_smartcard_manager_stop_watching_for_events (manager); + + if (manager->priv->module != NULL) { + SECMOD_DestroyModule (manager->priv->module); + manager->priv->module = NULL; + } + + if (manager->priv->nss_is_loaded) { + NSS_Shutdown (); + manager->priv->nss_is_loaded = FALSE; + } + + g_debug ("smartcard manager stopped"); + + return FALSE; +} + +static void +gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager) +{ + + manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPING; + + g_idle_add ((GSourceFunc) gsd_smartcard_manager_stop_now, manager); +} + +void +gsd_smartcard_manager_stop (GsdSmartcardManager *manager) +{ + if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) { + return; + } + + if (manager->priv->is_unstoppable) { + gsd_smartcard_manager_queue_stop (manager); + return; + } + + gsd_smartcard_manager_stop_now (manager); +} + +static void +gsd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, + GsdSmartcard *card, + gboolean *is_inserted) +{ + g_assert (is_inserted != NULL); + + if (gsd_smartcard_is_login_card (card)) { + *is_inserted = TRUE; + } + +} + +gboolean +gsd_smartcard_manager_login_card_is_inserted (GsdSmartcardManager *manager) + +{ + gboolean is_inserted; + + is_inserted = FALSE; + g_hash_table_foreach (manager->priv->smartcards, + (GHFunc) + gsd_smartcard_manager_check_for_login_card, + &is_inserted); + return is_inserted; +} + +static GsdSmartcardManagerWorker * +gsd_smartcard_manager_worker_new (int write_fd) +{ + GsdSmartcardManagerWorker *worker; + + worker = g_slice_new0 (GsdSmartcardManagerWorker); + worker->write_fd = write_fd; + worker->module = NULL; + + worker->smartcards = + g_hash_table_new_full ((GHashFunc) slot_id_hash, + (GEqualFunc) slot_id_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + return worker; +} + +static void +gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker) +{ + if (worker->smartcards != NULL) { + g_hash_table_destroy (worker->smartcards); + worker->smartcards = NULL; + } + + g_slice_free (GsdSmartcardManagerWorker, worker); +} + +static gboolean +read_bytes (int fd, + gpointer bytes, + gsize num_bytes) +{ + size_t bytes_left; + size_t total_bytes_read; + ssize_t bytes_read; + + bytes_left = (size_t) num_bytes; + total_bytes_read = 0; + + do { + bytes_read = read (fd, + (char *) bytes + total_bytes_read, + bytes_left); + g_assert (bytes_read <= (ssize_t) bytes_left); + + if (bytes_read <= 0) { + if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) { + continue; + } + + bytes_left = 0; + } else { + bytes_left -= bytes_read; + total_bytes_read += bytes_read; + } + } while (bytes_left > 0); + + if (total_bytes_read < (size_t) num_bytes) { + return FALSE; + } + + return TRUE; +} + +static gboolean +write_bytes (int fd, + gconstpointer bytes, + gsize num_bytes) +{ + size_t bytes_left; + size_t total_bytes_written; + ssize_t bytes_written; + + bytes_left = (size_t) num_bytes; + total_bytes_written = 0; + + do { + bytes_written = write (fd, + (char *) bytes + total_bytes_written, + bytes_left); + g_assert (bytes_written <= (ssize_t) bytes_left); + + if (bytes_written <= 0) { + if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) { + continue; + } + + bytes_left = 0; + } else { + bytes_left -= bytes_written; + total_bytes_written += bytes_written; + } + } while (bytes_left > 0); + + if (total_bytes_written < (size_t) num_bytes) { + return FALSE; + } + + return TRUE; +} + +static GsdSmartcard * +read_smartcard (int fd, + SECMODModule *module) +{ + GsdSmartcard *card; + char *card_name; + gsize card_name_size; + + card_name_size = 0; + if (!read_bytes (fd, &card_name_size, sizeof (card_name_size))) { + return NULL; + } + + card_name = g_slice_alloc0 (card_name_size); + if (!read_bytes (fd, card_name, card_name_size)) { + g_slice_free1 (card_name_size, card_name); + return NULL; + } + card = _gsd_smartcard_new_from_name (module, card_name); + g_slice_free1 (card_name_size, card_name); + + return card; +} + +static gboolean +write_smartcard (int fd, + GsdSmartcard *card) +{ + gsize card_name_size; + char *card_name; + + card_name = gsd_smartcard_get_name (card); + card_name_size = strlen (card_name) + 1; + + if (!write_bytes (fd, &card_name_size, sizeof (card_name_size))) { + g_free (card_name); + return FALSE; + } + + if (!write_bytes (fd, card_name, card_name_size)) { + g_free (card_name); + return FALSE; + } + g_free (card_name); + + return TRUE; +} + +static gboolean +gsd_smartcard_manager_worker_emit_smartcard_removed (GsdSmartcardManagerWorker *worker, + GsdSmartcard *card, + GError **error) +{ + g_debug ("card '%s' removed!", gsd_smartcard_get_name (card)); + + if (!write_bytes (worker->write_fd, "R", 1)) { + goto error_out; + } + + if (!write_smartcard (worker->write_fd, card)) { + goto error_out; + } + + return TRUE; + +error_out: + g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, + "%s", g_strerror (errno)); + return FALSE; +} + +static gboolean +gsd_smartcard_manager_worker_emit_smartcard_inserted (GsdSmartcardManagerWorker *worker, + GsdSmartcard *card, + GError **error) +{ + GError *write_error; + + write_error = NULL; + g_debug ("card '%s' inserted!", gsd_smartcard_get_name (card)); + if (!write_bytes (worker->write_fd, "I", 1)) { + goto error_out; + } + + if (!write_smartcard (worker->write_fd, card)) { + goto error_out; + } + + return TRUE; + +error_out: + g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, + "%s", g_strerror (errno)); + return FALSE; +} + +static gboolean +gsd_smartcard_manager_worker_watch_for_and_process_event (GsdSmartcardManagerWorker *worker, + GError **error) +{ + PK11SlotInfo *slot; + CK_SLOT_ID slot_id, *key; + int slot_series, card_slot_series; + GsdSmartcard *card; + GError *processing_error; + gboolean ret; + + g_debug ("waiting for card event"); + ret = FALSE; + + slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); + processing_error = NULL; + + if (slot == NULL) { + int error_code; + + error_code = PORT_GetError (); + if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) { + g_debug ("spurrious event occurred"); + return TRUE; + } + + /* FIXME: is there a function to convert from a PORT error + * code to a translated string? + */ + g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + _("encountered unexpected error while " + "waiting for smartcard events")); + goto out; + } + + /* the slot id and series together uniquely identify a card. + * You can never have two cards with the same slot id at the + * same time, however (I think), so we can key off of it. + */ + slot_id = PK11_GetSlotID (slot); + slot_series = PK11_GetSlotSeries (slot); + + /* First check to see if there is a card that we're currently + * tracking in the slot. + */ + key = g_new (CK_SLOT_ID, 1); + *key = slot_id; + card = g_hash_table_lookup (worker->smartcards, key); + + if (card != NULL) { + card_slot_series = gsd_smartcard_get_slot_series (card); + } else { + card_slot_series = -1; + } + + if (PK11_IsPresent (slot)) { + /* Now, check to see if their is a new card in the slot. + * If there was a different card in the slot now than + * there was before, then we need to emit a removed signal + * for the old card (we don't want unpaired insertion events). + */ + if ((card != NULL) && + card_slot_series != slot_series) { + if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { + g_propagate_error (error, processing_error); + goto out; + } + } + + card = _gsd_smartcard_new (worker->module, + slot_id, slot_series); + + g_hash_table_replace (worker->smartcards, + key, card); + key = NULL; + + if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, + card, + &processing_error)) { + g_propagate_error (error, processing_error); + goto out; + } + } else { + /* if we aren't tracking the card, just discard the event. + * We don't want unpaired remove events. Note on startup + * NSS will generate an "insertion" event if a card is + * already inserted in the slot. + */ + if ((card != NULL)) { + /* FIXME: i'm not sure about this code. Maybe we + * shouldn't do this at all, or maybe we should do it + * n times (where n = slot_series - card_slot_series + 1) + * + * Right now, i'm just doing it once. + */ + if ((slot_series - card_slot_series) > 1) { + + if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { + g_propagate_error (error, processing_error); + goto out; + } + g_hash_table_remove (worker->smartcards, key); + + card = _gsd_smartcard_new (worker->module, + slot_id, slot_series); + g_hash_table_replace (worker->smartcards, + key, card); + key = NULL; + if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { + g_propagate_error (error, processing_error); + goto out; + } + } + + if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { + g_propagate_error (error, processing_error); + goto out; + } + + g_hash_table_remove (worker->smartcards, key); + card = NULL; + } else { + g_debug ("got spurious remove event"); + } + } + + ret = TRUE; + +out: + g_free (key); + PK11_FreeSlot (slot); + + return ret; +} + +static void +gsd_smartcard_manager_worker_run (GsdSmartcardManagerWorker *worker) +{ + GError *error; + + + error = NULL; + + while (gsd_smartcard_manager_worker_watch_for_and_process_event (worker, &error)); + + if (error != NULL) { + g_debug ("could not process card event - %s", error->message); + g_error_free (error); + } + + gsd_smartcard_manager_worker_free (worker); +} + +static gboolean +gsd_smartcard_manager_create_worker (GsdSmartcardManager *manager, + int *worker_fd, + GThread **worker_thread) +{ + GsdSmartcardManagerWorker *worker; + int write_fd, read_fd; + + write_fd = -1; + read_fd = -1; + if (!open_pipe (&write_fd, &read_fd)) { + return FALSE; + } + + worker = gsd_smartcard_manager_worker_new (write_fd); + worker->module = manager->priv->module; + + *worker_thread = g_thread_create ((GThreadFunc) + gsd_smartcard_manager_worker_run, + worker, FALSE, NULL); + + if (*worker_thread == NULL) { + gsd_smartcard_manager_worker_free (worker); + return FALSE; + } + + if (worker_fd) { + *worker_fd = read_fd; + } + + return TRUE; +} + +#ifdef GSD_SMARTCARD_MANAGER_ENABLE_TEST +#include <glib.h> + +static GMainLoop *event_loop; +static gboolean should_exit_on_next_remove = FALSE; + +static gboolean +on_timeout (GsdSmartcardManager *manager) +{ + GError *error; + g_print ("Re-enabling manager.\n"); + + if (!gsd_smartcard_manager_start (manager, &error)) { + g_warning ("could not start smartcard manager - %s", + error->message); + g_error_free (error); + return 1; + } + g_print ("Please re-insert smartcard\n"); + + should_exit_on_next_remove = TRUE; + + return FALSE; +} + +static void +on_device_inserted (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + g_print ("smartcard inserted!\n"); + g_print ("Please remove it.\n"); +} + +static void +on_device_removed (GsdSmartcardManager *manager, + GsdSmartcard *card) +{ + g_print ("smartcard removed!\n"); + + if (should_exit_on_next_remove) { + g_main_loop_quit (event_loop); + } else { + g_print ("disabling manager for 2 seconds\n"); + gsd_smartcard_manager_stop (manager); + g_timeout_add (2000, (GSourceFunc) on_timeout, manager); + } +} + +int +main (int argc, + char *argv[]) +{ + GsdSmartcardManager *manager; + GError *error; + + g_log_set_always_fatal (G_LOG_LEVEL_ERROR + | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); + + g_type_init (); + + g_message ("creating instance of 'smartcard manager' object..."); + manager = gsd_smartcard_manager_new (NULL); + g_message ("'smartcard manager' object created successfully"); + + g_signal_connect (manager, "smartcard-inserted", + G_CALLBACK (on_device_inserted), NULL); + + g_signal_connect (manager, "smartcard-removed", + G_CALLBACK (on_device_removed), NULL); + + g_message ("starting listener..."); + + error = NULL; + if (!gsd_smartcard_manager_start (manager, &error)) { + g_warning ("could not start smartcard manager - %s", + error->message); + g_error_free (error); + return 1; + } + + event_loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (event_loop); + g_main_loop_unref (event_loop); + event_loop = NULL; + + g_message ("destroying previously created 'smartcard manager' object..."); + g_object_unref (manager); + manager = NULL; + g_message ("'smartcard manager' object destroyed successfully"); + + return 0; +} +#endif diff --git a/plugins/smartcard/gsd-smartcard-manager.h b/plugins/smartcard/gsd-smartcard-manager.h new file mode 100644 index 0000000..9663124 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-manager.h @@ -0,0 +1,90 @@ +/* gsd-smartcard-manager.h - object for monitoring smartcard insertion and + * removal events + * + * Copyright (C) 2006, 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode + */ +#ifndef GSD_SMARTCARD_MANAGER_H +#define GSD_SMARTCARD_MANAGER_H + +#define GSD_SMARTCARD_ENABLE_INTERNAL_API +#include "gsd-smartcard.h" + +#include <glib.h> +#include <glib-object.h> + +#ifdef __cplusplus +extern "C" { +#endif +#define GSD_TYPE_SMARTCARD_MANAGER (gsd_smartcard_manager_get_type ()) +#define GSD_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManager)) +#define GSD_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) +#define GSD_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER)) +#define GSD_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER)) +#define GSD_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) +#define GSD_SMARTCARD_MANAGER_ERROR (gsd_smartcard_manager_error_quark ()) +typedef struct _GsdSmartcardManager GsdSmartcardManager; +typedef struct _GsdSmartcardManagerClass GsdSmartcardManagerClass; +typedef struct _GsdSmartcardManagerPrivate GsdSmartcardManagerPrivate; +typedef enum _GsdSmartcardManagerError GsdSmartcardManagerError; + +struct _GsdSmartcardManager { + GObject parent; + + /*< private > */ + GsdSmartcardManagerPrivate *priv; +}; + +struct _GsdSmartcardManagerClass { + GObjectClass parent_class; + + /* Signals */ + void (*smartcard_inserted) (GsdSmartcardManager *manager, + GsdSmartcard *token); + void (*smartcard_removed) (GsdSmartcardManager *manager, + GsdSmartcard *token); + void (*error) (GsdSmartcardManager *manager, + GError *error); +}; + +enum _GsdSmartcardManagerError { + GSD_SMARTCARD_MANAGER_ERROR_GENERIC = 0, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, + GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS +}; + +GType gsd_smartcard_manager_get_type (void) G_GNUC_CONST; +GQuark gsd_smartcard_manager_error_quark (void) G_GNUC_CONST; + +GsdSmartcardManager *gsd_smartcard_manager_new (const char *module); + +gboolean gsd_smartcard_manager_start (GsdSmartcardManager *manager, + GError **error); + +void gsd_smartcard_manager_stop (GsdSmartcardManager *manager); + +char *gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager); +gboolean gsd_smartcard_manager_login_card_is_inserted (GsdSmartcardManager *manager); + +#ifdef __cplusplus +} +#endif +#endif /* GSD_SMARTCARD_MANAGER_H */ diff --git a/plugins/smartcard/gsd-smartcard-plugin.c b/plugins/smartcard/gsd-smartcard-plugin.c new file mode 100644 index 0000000..9e3b4f2 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-plugin.c @@ -0,0 +1,340 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gmodule.h> + +#include <glib.h> +#include <glib-object.h> + +#include <dbus/dbus-glib.h> + +#include <mateconf/mateconf-client.h> + +#include "mate-settings-plugin.h" +#include "gsd-smartcard-plugin.h" +#include "gsd-smartcard-manager.h" + +struct GsdSmartcardPluginPrivate { + GsdSmartcardManager *manager; + DBusGConnection *bus_connection; + + guint32 is_active : 1; +}; + +typedef enum +{ + GSD_SMARTCARD_REMOVE_ACTION_NONE, + GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN, + GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT, +} GsdSmartcardRemoveAction; + +#define SCREENSAVER_DBUS_NAME "org.mate.ScreenSaver" +#define SCREENSAVER_DBUS_PATH "/" +#define SCREENSAVER_DBUS_INTERFACE "org.mate.ScreenSaver" + +#define SM_DBUS_NAME "org.mate.SessionManager" +#define SM_DBUS_PATH "/org/mate/SessionManager" +#define SM_DBUS_INTERFACE "org.mate.SessionManager" +#define SM_LOGOUT_MODE_FORCE 2 + +#define GSD_SMARTCARD_KEY "/desktop/mate/peripherals/smartcard" +#define KEY_REMOVE_ACTION GSD_SMARTCARD_KEY "/removal_action" + +#define GSD_SMARTCARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginPrivate)) + +MATE_SETTINGS_PLUGIN_REGISTER (GsdSmartcardPlugin, gsd_smartcard_plugin); + +static void +simulate_user_activity (GsdSmartcardPlugin *plugin) +{ + DBusGProxy *screensaver_proxy; + + g_debug ("GsdSmartcardPlugin telling screensaver about smart card insertion"); + screensaver_proxy = dbus_g_proxy_new_for_name (plugin->priv->bus_connection, + SCREENSAVER_DBUS_NAME, + SCREENSAVER_DBUS_PATH, + SCREENSAVER_DBUS_INTERFACE); + + dbus_g_proxy_call_no_reply (screensaver_proxy, + "SimulateUserActivity", + G_TYPE_INVALID, G_TYPE_INVALID); + + g_object_unref (screensaver_proxy); +} + +static void +lock_screen (GsdSmartcardPlugin *plugin) +{ + DBusGProxy *screensaver_proxy; + + g_debug ("GsdSmartcardPlugin telling screensaver to lock screen"); + screensaver_proxy = dbus_g_proxy_new_for_name (plugin->priv->bus_connection, + SCREENSAVER_DBUS_NAME, + SCREENSAVER_DBUS_PATH, + SCREENSAVER_DBUS_INTERFACE); + + dbus_g_proxy_call_no_reply (screensaver_proxy, + "Lock", + G_TYPE_INVALID, G_TYPE_INVALID); + + g_object_unref (screensaver_proxy); +} + +static void +force_logout (GsdSmartcardPlugin *plugin) +{ + DBusGProxy *sm_proxy; + GError *error; + gboolean res; + + g_debug ("GsdSmartcardPlugin telling session manager to force logout"); + sm_proxy = dbus_g_proxy_new_for_name (plugin->priv->bus_connection, + SM_DBUS_NAME, + SM_DBUS_PATH, + SM_DBUS_INTERFACE); + + error = NULL; + res = dbus_g_proxy_call (sm_proxy, + "Logout", + &error, + G_TYPE_UINT, SM_LOGOUT_MODE_FORCE, + G_TYPE_INVALID, G_TYPE_INVALID); + + if (! res) { + g_warning ("GsdSmartcardPlugin Unable to force logout: %s", error->message); + g_error_free (error); + } + + g_object_unref (sm_proxy); +} + +static void +gsd_smartcard_plugin_init (GsdSmartcardPlugin *plugin) +{ + plugin->priv = GSD_SMARTCARD_PLUGIN_GET_PRIVATE (plugin); + + g_debug ("GsdSmartcardPlugin initializing"); + + plugin->priv->manager = gsd_smartcard_manager_new (NULL); +} + +static void +gsd_smartcard_plugin_finalize (GObject *object) +{ + GsdSmartcardPlugin *plugin; + + g_return_if_fail (object != NULL); + g_return_if_fail (GSD_IS_SMARTCARD_PLUGIN (object)); + + g_debug ("GsdSmartcardPlugin finalizing"); + + plugin = GSD_SMARTCARD_PLUGIN (object); + + g_return_if_fail (plugin->priv != NULL); + + if (plugin->priv->manager != NULL) { + g_object_unref (plugin->priv->manager); + } + + G_OBJECT_CLASS (gsd_smartcard_plugin_parent_class)->finalize (object); +} + +static void +smartcard_inserted_cb (GsdSmartcardManager *card_monitor, + GsdSmartcard *card, + GsdSmartcardPlugin *plugin) +{ + char *name; + + name = gsd_smartcard_get_name (card); + g_debug ("GsdSmartcardPlugin smart card '%s' inserted", name); + g_free (name); + + simulate_user_activity (plugin); +} + +static gboolean +user_logged_in_with_smartcard (void) +{ + return g_getenv ("PKCS11_LOGIN_TOKEN_NAME") != NULL; +} + +static GsdSmartcardRemoveAction +get_configured_remove_action (GsdSmartcardPlugin *plugin) +{ + MateConfClient *client; + char *remove_action_string; + GsdSmartcardRemoveAction remove_action; + + client = mateconf_client_get_default (); + remove_action_string = mateconf_client_get_string (client, + KEY_REMOVE_ACTION, NULL); + + if (remove_action_string == NULL) { + g_warning ("GsdSmartcardPlugin unable to get smartcard remove action"); + remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; + } else if (strcmp (remove_action_string, "none") == 0) { + remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; + } else if (strcmp (remove_action_string, "lock_screen") == 0) { + remove_action = GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN; + } else if (strcmp (remove_action_string, "force_logout") == 0) { + remove_action = GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT; + } else { + g_warning ("GsdSmartcardPlugin unknown smartcard remove action"); + remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; + } + + g_object_unref (client); + + return remove_action; +} + +static void +process_smartcard_removal (GsdSmartcardPlugin *plugin) +{ + GsdSmartcardRemoveAction remove_action; + + g_debug ("GsdSmartcardPlugin processing smartcard removal"); + remove_action = get_configured_remove_action (plugin); + + switch (remove_action) + { + case GSD_SMARTCARD_REMOVE_ACTION_NONE: + return; + case GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN: + lock_screen (plugin); + break; + case GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT: + force_logout (plugin); + break; + } +} + +static void +smartcard_removed_cb (GsdSmartcardManager *card_monitor, + GsdSmartcard *card, + GsdSmartcardPlugin *plugin) +{ + + char *name; + + name = gsd_smartcard_get_name (card); + g_debug ("GsdSmartcardPlugin smart card '%s' removed", name); + g_free (name); + + if (!gsd_smartcard_is_login_card (card)) { + g_debug ("GsdSmartcardPlugin removed smart card was not used to login"); + return; + } + + process_smartcard_removal (plugin); +} + +static void +impl_activate (MateSettingsPlugin *plugin) +{ + GError *error; + GsdSmartcardPlugin *smartcard_plugin = GSD_SMARTCARD_PLUGIN (plugin); + + if (smartcard_plugin->priv->is_active) { + g_debug ("GsdSmartcardPlugin Not activating smartcard plugin, because it's " + "already active"); + return; + } + + if (!user_logged_in_with_smartcard ()) { + g_debug ("GsdSmartcardPlugin Not activating smartcard plugin, because user didn't use " + " smartcard to log in"); + smartcard_plugin->priv->is_active = FALSE; + return; + } + + g_debug ("GsdSmartcardPlugin Activating smartcard plugin"); + + error = NULL; + smartcard_plugin->priv->bus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + + if (smartcard_plugin->priv->bus_connection == NULL) { + g_warning ("GsdSmartcardPlugin Unable to connect to session bus: %s", error->message); + return; + } + + if (!gsd_smartcard_manager_start (smartcard_plugin->priv->manager, &error)) { + g_warning ("GsdSmartcardPlugin Unable to start smartcard manager: %s", error->message); + g_error_free (error); + } + + g_signal_connect (smartcard_plugin->priv->manager, + "smartcard-removed", + G_CALLBACK (smartcard_removed_cb), smartcard_plugin); + + g_signal_connect (smartcard_plugin->priv->manager, + "smartcard-inserted", + G_CALLBACK (smartcard_inserted_cb), smartcard_plugin); + + if (!gsd_smartcard_manager_login_card_is_inserted (smartcard_plugin->priv->manager)) { + g_debug ("GsdSmartcardPlugin processing smartcard removal immediately user logged in with smartcard " + "and it's not inserted"); + process_smartcard_removal (smartcard_plugin); + } + + smartcard_plugin->priv->is_active = TRUE; +} + +static void +impl_deactivate (MateSettingsPlugin *plugin) +{ + GsdSmartcardPlugin *smartcard_plugin = GSD_SMARTCARD_PLUGIN (plugin); + + if (!smartcard_plugin->priv->is_active) { + g_debug ("GsdSmartcardPlugin Not deactivating smartcard plugin, " + "because it's already inactive"); + return; + } + + g_debug ("GsdSmartcardPlugin Deactivating smartcard plugin"); + + gsd_smartcard_manager_stop (smartcard_plugin->priv->manager); + + g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, + smartcard_removed_cb, smartcard_plugin); + + g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, + smartcard_inserted_cb, smartcard_plugin); + smartcard_plugin->priv->bus_connection = NULL; + smartcard_plugin->priv->is_active = FALSE; +} + +static void +gsd_smartcard_plugin_class_init (GsdSmartcardPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass); + + object_class->finalize = gsd_smartcard_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + + g_type_class_add_private (klass, sizeof (GsdSmartcardPluginPrivate)); +} diff --git a/plugins/smartcard/gsd-smartcard-plugin.h b/plugins/smartcard/gsd-smartcard-plugin.h new file mode 100644 index 0000000..4c61686 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-plugin.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GSD_SMARTCARD_PLUGIN_H__ +#define __GSD_SMARTCARD_PLUGIN_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gmodule.h> + +#include "mate-settings-plugin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GSD_TYPE_SMARTCARD_PLUGIN (gsd_smartcard_plugin_get_type ()) +#define GSD_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPlugin)) +#define GSD_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginClass)) +#define GSD_IS_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SMARTCARD_PLUGIN)) +#define GSD_IS_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SMARTCARD_PLUGIN)) +#define GSD_SMARTCARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginClass)) + +typedef struct GsdSmartcardPluginPrivate GsdSmartcardPluginPrivate; + +typedef struct +{ + MateSettingsPlugin parent; + GsdSmartcardPluginPrivate *priv; +} GsdSmartcardPlugin; + +typedef struct +{ + MateSettingsPluginClass parent_class; +} GsdSmartcardPluginClass; + +GType gsd_smartcard_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module); + +#ifdef __cplusplus +} +#endif + +#endif /* __GSD_SMARTCARD_PLUGIN_H__ */ diff --git a/plugins/smartcard/gsd-smartcard.c b/plugins/smartcard/gsd-smartcard.c new file mode 100644 index 0000000..22f4e12 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard.c @@ -0,0 +1,555 @@ +/* gsd-smartcard.c - smartcard object + * + * Copyright (C) 2006 Ray Strode <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#define GSD_SMARTCARD_ENABLE_INTERNAL_API +#include "gsd-smartcard.h" + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <glib.h> +#include <glib/gi18n.h> + +#include <cert.h> +#include <nss.h> +#include <pk11func.h> +#include <prerror.h> +#include <secmod.h> +#include <secerr.h> + +struct _GsdSmartcardPrivate { + SECMODModule *module; + GsdSmartcardState state; + + CK_SLOT_ID slot_id; + int slot_series; + + PK11SlotInfo *slot; + char *name; + + CERTCertificate *signing_certificate; + CERTCertificate *encryption_certificate; +}; + +static void gsd_smartcard_finalize (GObject *object); +static void gsd_smartcard_class_install_signals (GsdSmartcardClass *card_class); +static void gsd_smartcard_class_install_properties (GsdSmartcardClass *card_class); +static void gsd_smartcard_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gsd_smartcard_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gsd_smartcard_set_name (GsdSmartcard *card, const char *name); +static void gsd_smartcard_set_slot_id (GsdSmartcard *card, + int slot_id); +static void gsd_smartcard_set_slot_series (GsdSmartcard *card, + int slot_series); +static void gsd_smartcard_set_module (GsdSmartcard *card, + SECMODModule *module); + +static PK11SlotInfo *gsd_smartcard_find_slot_from_id (GsdSmartcard *card, + int slot_id); + +static PK11SlotInfo *gsd_smartcard_find_slot_from_card_name (GsdSmartcard *card, + const char *card_name); +#ifndef GSD_SMARTCARD_DEFAULT_SLOT_ID +#define GSD_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1) +#endif + +#ifndef GSD_SMARTCARD_DEFAULT_SLOT_SERIES +#define GSD_SMARTCARD_DEFAULT_SLOT_SERIES -1 +#endif + +enum { + PROP_0 = 0, + PROP_NAME, + PROP_SLOT_ID, + PROP_SLOT_SERIES, + PROP_MODULE, + NUMBER_OF_PROPERTIES +}; + +enum { + INSERTED, + REMOVED, + NUMBER_OF_SIGNALS +}; + +static guint gsd_smartcard_signals[NUMBER_OF_SIGNALS]; + +G_DEFINE_TYPE (GsdSmartcard, gsd_smartcard, G_TYPE_OBJECT); + +static void +gsd_smartcard_class_init (GsdSmartcardClass *card_class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (card_class); + + gobject_class->finalize = gsd_smartcard_finalize; + + gsd_smartcard_class_install_signals (card_class); + gsd_smartcard_class_install_properties (card_class); + + g_type_class_add_private (card_class, + sizeof (GsdSmartcardPrivate)); +} + +static void +gsd_smartcard_class_install_signals (GsdSmartcardClass *card_class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (card_class); + + gsd_smartcard_signals[INSERTED] = + g_signal_new ("inserted", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsdSmartcardClass, + inserted), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gsd_smartcard_signals[REMOVED] = + g_signal_new ("removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsdSmartcardClass, + removed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +gsd_smartcard_class_install_properties (GsdSmartcardClass *card_class) +{ + GObjectClass *object_class; + GParamSpec *param_spec; + + object_class = G_OBJECT_CLASS (card_class); + object_class->set_property = gsd_smartcard_set_property; + object_class->get_property = gsd_smartcard_get_property; + + param_spec = g_param_spec_ulong ("slot-id", _("Slot ID"), + _("The slot the card is in"), + 1, G_MAXULONG, + GSD_SMARTCARD_DEFAULT_SLOT_ID, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec); + + param_spec = g_param_spec_int ("slot-series", _("Slot Series"), + _("per-slot card identifier"), + -1, G_MAXINT, + GSD_SMARTCARD_DEFAULT_SLOT_SERIES, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec); + + param_spec = g_param_spec_string ("name", _("name"), + _("name"), NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_NAME, param_spec); + + param_spec = g_param_spec_pointer ("module", _("Module"), + _("smartcard driver"), + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_MODULE, param_spec); +} + +static void +gsd_smartcard_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsdSmartcard *card = GSD_SMARTCARD (object); + + switch (prop_id) { + case PROP_NAME: + gsd_smartcard_set_name (card, g_value_get_string (value)); + break; + + case PROP_SLOT_ID: + gsd_smartcard_set_slot_id (card, + g_value_get_ulong (value)); + break; + + case PROP_SLOT_SERIES: + gsd_smartcard_set_slot_series (card, + g_value_get_int (value)); + break; + + case PROP_MODULE: + gsd_smartcard_set_module (card, + (SECMODModule *) + g_value_get_pointer (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +CK_SLOT_ID +gsd_smartcard_get_slot_id (GsdSmartcard *card) +{ + return card->priv->slot_id; +} + +GsdSmartcardState +gsd_smartcard_get_state (GsdSmartcard *card) +{ + return card->priv->state; +} + +char * +gsd_smartcard_get_name (GsdSmartcard *card) +{ + return g_strdup (card->priv->name); +} + +gboolean +gsd_smartcard_is_login_card (GsdSmartcard *card) +{ + const char *login_card_name; + login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME"); + + if ((login_card_name == NULL) || (card->priv->name == NULL)) { + return FALSE; + } + + if (strcmp (card->priv->name, login_card_name) == 0) { + return TRUE; + } + + return FALSE; +} + +static void +gsd_smartcard_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsdSmartcard *card = GSD_SMARTCARD (object); + + switch (prop_id) { + case PROP_NAME: + g_value_take_string (value, + gsd_smartcard_get_name (card)); + break; + + case PROP_SLOT_ID: + g_value_set_ulong (value, + (gulong) gsd_smartcard_get_slot_id (card)); + break; + + case PROP_SLOT_SERIES: + g_value_set_int (value, + gsd_smartcard_get_slot_series (card)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsd_smartcard_set_name (GsdSmartcard *card, + const char *name) +{ + if (name == NULL) { + return; + } + + if ((card->priv->name == NULL) || + (strcmp (card->priv->name, name) != 0)) { + g_free (card->priv->name); + card->priv->name = g_strdup (name); + + if (card->priv->slot == NULL) { + card->priv->slot = gsd_smartcard_find_slot_from_card_name (card, + card->priv->name); + + if (card->priv->slot != NULL) { + int slot_id, slot_series; + + slot_id = PK11_GetSlotID (card->priv->slot); + if (slot_id != card->priv->slot_id) { + gsd_smartcard_set_slot_id (card, slot_id); + } + + slot_series = PK11_GetSlotSeries (card->priv->slot); + if (slot_series != card->priv->slot_series) { + gsd_smartcard_set_slot_series (card, slot_series); + } + + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); + } else { + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); + } + } + + g_object_notify (G_OBJECT (card), "name"); + } +} + +static void +gsd_smartcard_set_slot_id (GsdSmartcard *card, + int slot_id) +{ + if (card->priv->slot_id != slot_id) { + card->priv->slot_id = slot_id; + + if (card->priv->slot == NULL) { + card->priv->slot = gsd_smartcard_find_slot_from_id (card, + card->priv->slot_id); + + if (card->priv->slot != NULL) { + const char *card_name; + + card_name = PK11_GetTokenName (card->priv->slot); + if ((card->priv->name == NULL) || + ((card_name != NULL) && + (strcmp (card_name, card->priv->name) != 0))) { + gsd_smartcard_set_name (card, card_name); + } + + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); + } else { + _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); + } + } + + g_object_notify (G_OBJECT (card), "slot-id"); + } +} + +static void +gsd_smartcard_set_slot_series (GsdSmartcard *card, + int slot_series) +{ + if (card->priv->slot_series != slot_series) { + card->priv->slot_series = slot_series; + g_object_notify (G_OBJECT (card), "slot-series"); + } +} + +static void +gsd_smartcard_set_module (GsdSmartcard *card, + SECMODModule *module) +{ + gboolean should_notify; + + if (card->priv->module != module) { + should_notify = TRUE; + } else { + should_notify = FALSE; + } + + if (card->priv->module != NULL) { + SECMOD_DestroyModule (card->priv->module); + card->priv->module = NULL; + } + + if (module != NULL) { + card->priv->module = SECMOD_ReferenceModule (module); + } + + if (should_notify) { + g_object_notify (G_OBJECT (card), "module"); + } +} + +int +gsd_smartcard_get_slot_series (GsdSmartcard *card) +{ + return card->priv->slot_series; +} + +static void +gsd_smartcard_init (GsdSmartcard *card) +{ + + g_debug ("initializing smartcard "); + + card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card, + GSD_TYPE_SMARTCARD, + GsdSmartcardPrivate); + + if (card->priv->slot != NULL) { + card->priv->name = g_strdup (PK11_GetTokenName (card->priv->slot)); + } +} + +static void gsd_smartcard_finalize (GObject *object) +{ + GsdSmartcard *card; + GObjectClass *gobject_class; + + card = GSD_SMARTCARD (object); + + g_free (card->priv->name); + + gsd_smartcard_set_module (card, NULL); + + gobject_class = G_OBJECT_CLASS (gsd_smartcard_parent_class); + + gobject_class->finalize (object); +} + +GQuark gsd_smartcard_error_quark (void) +{ + static GQuark error_quark = 0; + + if (error_quark == 0) { + error_quark = g_quark_from_static_string ("gsd-smartcard-error-quark"); + } + + return error_quark; +} + +GsdSmartcard * +_gsd_smartcard_new (SECMODModule *module, + CK_SLOT_ID slot_id, + int slot_series) +{ + GsdSmartcard *card; + + g_return_val_if_fail (module != NULL, NULL); + g_return_val_if_fail (slot_id >= 1, NULL); + g_return_val_if_fail (slot_series > 0, NULL); + g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL); + + card = GSD_SMARTCARD (g_object_new (GSD_TYPE_SMARTCARD, + "module", module, + "slot-id", (gulong) slot_id, + "slot-series", slot_series, + NULL)); + return card; +} + +GsdSmartcard * +_gsd_smartcard_new_from_name (SECMODModule *module, + const char *name) +{ + GsdSmartcard *card; + + g_return_val_if_fail (module != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + card = GSD_SMARTCARD (g_object_new (GSD_TYPE_SMARTCARD, + "module", module, + "name", name, + NULL)); + return card; +} + +void +_gsd_smartcard_set_state (GsdSmartcard *card, + GsdSmartcardState state) +{ + if (card->priv->state != state) { + card->priv->state = state; + + if (state == GSD_SMARTCARD_STATE_INSERTED) { + g_signal_emit (card, gsd_smartcard_signals[INSERTED], 0); + } else if (state == GSD_SMARTCARD_STATE_REMOVED) { + g_signal_emit (card, gsd_smartcard_signals[REMOVED], 0); + } else { + g_assert_not_reached (); + } + } +} + +/* So we could conceivably make the closure data a pointer to the card + * or something similiar and then emit signals when we want passwords, + * but it's probably easier to just get the password up front and use + * it. So we just take the passed in g_malloc'd (well probably, who knows) + * and strdup it using NSPR's memory allocation routines. + */ +static char * +gsd_smartcard_password_handler (PK11SlotInfo *slot, + PRBool is_retrying, + const char *password) +{ + if (is_retrying) { + return NULL; + } + + return password != NULL? PL_strdup (password): NULL; +} + +gboolean +gsd_smartcard_unlock (GsdSmartcard *card, + const char *password) +{ + SECStatus status; + + PK11_SetPasswordFunc ((PK11PasswordFunc) gsd_smartcard_password_handler); + + /* we pass PR_TRUE to load certificates + */ + status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password); + + if (status != SECSuccess) { + g_debug ("could not unlock card - %d", status); + return FALSE; + } + return TRUE; +} + +static PK11SlotInfo * +gsd_smartcard_find_slot_from_card_name (GsdSmartcard *card, + const char *card_name) +{ + int i; + + for (i = 0; i < card->priv->module->slotCount; i++) { + const char *slot_card_name; + + slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]); + + if ((slot_card_name != NULL) && + (strcmp (slot_card_name, card_name) == 0)) { + return card->priv->module->slots[i]; + } + } + + return NULL; +} + +static PK11SlotInfo * +gsd_smartcard_find_slot_from_id (GsdSmartcard *card, + int slot_id) +{ + int i; + + for (i = 0; i < card->priv->module->slotCount; i++) { + if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) { + return card->priv->module->slots[i]; + } + } + + return NULL; +} diff --git a/plugins/smartcard/gsd-smartcard.h b/plugins/smartcard/gsd-smartcard.h new file mode 100644 index 0000000..c8c1ea7 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard.h @@ -0,0 +1,98 @@ +/* securitycard.h - api for reading and writing data to a security card + * + * Copyright (C) 2006 Ray Strode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef GSD_SMARTCARD_H +#define GSD_SMARTCARD_H + +#include <glib.h> +#include <glib-object.h> + +#include <secmod.h> + +#ifdef __cplusplus +extern "C" { +#endif +#define GSD_TYPE_SMARTCARD (gsd_smartcard_get_type ()) +#define GSD_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_SMARTCARD, GsdSmartcard)) +#define GSD_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_SMARTCARD, GsdSmartcardClass)) +#define GSD_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_SMARTCARD)) +#define GSD_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSD_TYPE_SMARTCARD)) +#define GSD_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSD_TYPE_SMARTCARD, GsdSmartcardClass)) +#define GSD_SMARTCARD_ERROR (gsd_smartcard_error_quark ()) +typedef struct _GsdSmartcardClass GsdSmartcardClass; +typedef struct _GsdSmartcard GsdSmartcard; +typedef struct _GsdSmartcardPrivate GsdSmartcardPrivate; +typedef enum _GsdSmartcardError GsdSmartcardError; +typedef enum _GsdSmartcardState GsdSmartcardState; + +typedef struct _GsdSmartcardRequest GsdSmartcardRequest; + +struct _GsdSmartcard { + GObject parent; + + /*< private > */ + GsdSmartcardPrivate *priv; +}; + +struct _GsdSmartcardClass { + GObjectClass parent_class; + + void (* inserted) (GsdSmartcard *card); + void (* removed) (GsdSmartcard *card); +}; + +enum _GsdSmartcardError { + GSD_SMARTCARD_ERROR_GENERIC = 0, +}; + +enum _GsdSmartcardState { + GSD_SMARTCARD_STATE_INSERTED = 0, + GSD_SMARTCARD_STATE_REMOVED, +}; + +GType gsd_smartcard_get_type (void) G_GNUC_CONST; +GQuark gsd_smartcard_error_quark (void) G_GNUC_CONST; + +CK_SLOT_ID gsd_smartcard_get_slot_id (GsdSmartcard *card); +gint gsd_smartcard_get_slot_series (GsdSmartcard *card); +GsdSmartcardState gsd_smartcard_get_state (GsdSmartcard *card); + +char *gsd_smartcard_get_name (GsdSmartcard *card); +gboolean gsd_smartcard_is_login_card (GsdSmartcard *card); + +gboolean gsd_smartcard_unlock (GsdSmartcard *card, + const char *password); + +/* don't under any circumstances call these functions */ +#ifdef GSD_SMARTCARD_ENABLE_INTERNAL_API + +GsdSmartcard *_gsd_smartcard_new (SECMODModule *module, + CK_SLOT_ID slot_id, + gint slot_series); +GsdSmartcard *_gsd_smartcard_new_from_name (SECMODModule *module, + const char *name); + +void _gsd_smartcard_set_state (GsdSmartcard *card, + GsdSmartcardState state); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* GSD_SMARTCARD_H */ diff --git a/plugins/smartcard/smartcard.mate-settings-plugin.in b/plugins/smartcard/smartcard.mate-settings-plugin.in new file mode 100644 index 0000000..dd75784 --- /dev/null +++ b/plugins/smartcard/smartcard.mate-settings-plugin.in @@ -0,0 +1,8 @@ +[MATE Settings Plugin] +Module=smartcard +IAge=0 +_Name=Smartcard +_Description=Smartcard plugin +Authors=Ray Strode +Copyright=Copyright © 2010 Red Hat, Inc. +Website= |