opensc-notify: notify for card events

... manually or in daemon mode

fixes compilation in MinGW/Travis CI
This commit is contained in:
Frank Morgner 2017-06-19 11:57:18 +02:00
parent b2cde0f7fb
commit ce3f27ff54
16 changed files with 1940 additions and 83 deletions

View File

@ -63,7 +63,7 @@ before_script:
fi
- ./bootstrap
- if [ -z "$HOST" ]; then
CFLAGS="-Werror" ./configure $ENABLE_DOC --enable-dnie-ui;
CFLAGS="-Werror" ./configure $ENABLE_DOC --enable-dnie-ui --disable-notify;
else
if [ ! -f "$(winepath 'C:/Program Files (x86)/Inno Setup 5/ISCC.exe')" ]; then
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16;

View File

@ -0,0 +1,2 @@
do shell script "killall opensc-notify || true"
do shell script "nohup /Library/OpenSC/bin/opensc-notify > /dev/null 2>&1 &"

View File

@ -108,6 +108,8 @@ if ! test -e NotificationProxy; then
git clone http://github.com/frankmorgner/NotificationProxy.git
fi
xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/Security/tokend/OpenSC.tokend/Contents/Resources/
mkdir -p "$BUILDPATH/target/Applications"
osacompile -o "$BUILDPATH/target/Applications/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript"
# Prepare target root
# The "UnInstaller"

View File

@ -16,6 +16,7 @@ rm -f /usr/local/lib/opensc-pkcs11.so
rm -f /usr/local/lib/onepin-opensc-pkcs11.so
# Remove installed files
rm -rf "/Applications/OpenSC Notify.app"
rm -rf /Library/OpenSC
rm -rf /Library/Security/tokend/OpenSC.tokend
rm -rf /System/Library/Security/tokend/OpenSC.tokend

View File

@ -133,6 +133,9 @@ case "${host}" in
;;
esac
AX_CHECK_COMPILE_FLAG(-Wno-error=unused-but-set-variable, [have_unused_but_set_variable="yes"], [have_unused_but_set_variable="no"], [-Werror -Wunknown-warning-option])
AM_CONDITIONAL([HAVE_UNUSED_BUT_SET_VARIABLE], [test "${have_unused_but_set_variable}" = "yes"])
AC_ARG_ENABLE(
[strict],
[AS_HELP_STRING([--disable-strict],[disable strict compile mode @<:@disabled@:>@])],
@ -384,7 +387,7 @@ AC_FUNC_VPRINTF
AC_CHECK_FUNCS([ \
getpass gettimeofday getline memset mkdir \
strdup strerror getopt_long getopt_long_only \
strlcpy strlcat strnlen
strlcpy strlcat strnlen sigaction
])
AC_CHECK_SIZEOF(void *)
if test "${ac_cv_sizeof_void_p}" = 8; then

View File

@ -0,0 +1,74 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@ -12,14 +12,16 @@ do_subst = $(SED) \
-e 's,[@]X509DIR[@],$(X509DIR),g'
NPA_TOOL_BUILT_SOURCES = npa-tool-cmdline.h npa-tool-cmdline.c
OPENSC_NOTIFY_BUILT_SOURCES = opensc-notify-cmdline.h opensc-notify-cmdline.c
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-tools.rc
EXTRA_DIST = Makefile.mak versioninfo-tools.rc.in npa-tool.ggo.in npa-tool.1
EXTRA_DIST = Makefile.mak versioninfo-tools.rc.in npa-tool.ggo.in npa-tool.1 opensc-notify.ggo.in
noinst_HEADERS = util.h fread_to_eof.h
noinst_PROGRAMS = sceac-example
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool opensc-notify
bin_PROGRAMS = opensc-tool opensc-explorer opensc-notify \
pkcs15-tool pkcs15-crypt pkcs11-tool \
cardos-tool eidenv openpgp-tool iasecc-tool
if ENABLE_OPENSSL
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool \
westcos-tool sc-hsm-tool dnie-tool gids-tool npa-tool
@ -46,7 +48,6 @@ piv_tool_SOURCES = piv-tool.c util.c
piv_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
opensc_explorer_SOURCES = opensc-explorer.c util.c
opensc_explorer_LDADD = $(OPTIONAL_READLINE_LIBS)
opensc_notify_SOURCES = opensc-notify.c
pkcs15_tool_SOURCES = pkcs15-tool.c util.c
pkcs15_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
pkcs11_tool_SOURCES = pkcs11-tool.c util.c
@ -101,6 +102,30 @@ npa-tool.1:
--source='$(PACKAGE_STRING)' \
$(builddir)/npa-tool$(EXEEXT)
opensc_notify_SOURCES = opensc-notify.c $(OPENSC_NOTIFY_BUILT_SOURCES)
opensc_notify_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_NOTIFY_LIBS)
opensc_notify_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_NOTIFY_CFLAGS)
opensc_notify_CFLAGS += -Wno-unused-but-set-variable -Wno-unknown-warning-option
opensc-notify.c: $(abs_builddir)/opensc-notify.ggo $(OPENSC_NOTIFY_BUILT_SOURCES)
# We only want *cmdline* to be generated when they have explicitly been removed.
$(OPENSC_NOTIFY_BUILT_SOURCES):
$(MAKE) $(abs_builddir)/opensc-notify.ggo
$(GENGETOPT) --include-getopt --file-name=opensc-notify-cmdline --output-dir=$(builddir) < $(abs_builddir)/opensc-notify.ggo
$(abs_builddir)/opensc-notify.ggo: opensc-notify.ggo.in
$(do_subst) < $(abs_srcdir)/opensc-notify.ggo.in > $@
# We only want opensc-notify.1 to be generated when it has explicitly been removed.
opensc-notify.1:
$(MAKE) opensc-notify$(EXEEXT)
$(HELP2MAN) \
--output=$@ \
--no-info \
--source='$(PACKAGE_STRING)' \
$(builddir)/opensc-notify$(EXEEXT)
if WIN32
opensc_tool_SOURCES += versioninfo-tools.rc
piv_tool_SOURCES += versioninfo-tools.rc
@ -121,4 +146,4 @@ gids_tool_SOURCES += versioninfo-tools.rc
endif
clean-local:
rm -f $(abs_builddir)/npa-tool.ggo
rm -f $(abs_builddir)/npa-tool.ggo $(abs_builddir)/opensc-notify.ggo

View File

@ -10,6 +10,10 @@ TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \
$(PROGRAMS_OPENSSL)
OBJECTS = util.obj npa-tool-cmdline.obj fread_to_eof.obj versioninfo-tools.res
TARGET2 = opensc-notify.exe
OBJECT2 = opensc-notify-cmdline.obj versioninfo-tools.res
LIBS = $(TOPDIR)\src\common\common.lib \
$(TOPDIR)\src\scconf\scconf.lib \
$(TOPDIR)\src\libopensc\opensc.lib \
@ -17,11 +21,13 @@ LIBS = $(TOPDIR)\src\common\common.lib \
$(TOPDIR)\src\common\libpkcs11.lib \
$(TOPDIR)\src\common\libscdl.lib
all: $(TARGETS)
all: $(TARGETS) $(TARGET2)
$(TARGETS): $(OBJECTS) $(LIBS)
$(TARGET2): $(OBJECT2) $(LIBS)
.c.exe:
cl $(COPTS) /c $<
link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib ws2_32.lib
link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
mt -manifest exe.manifest -outputresource:$@;1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
/** @file opensc-notify-cmdline.h
* @brief The header file for the command line option parser
* generated by GNU Gengetopt version 2.22.6
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
#ifndef OPENSC_NOTIFY_CMDLINE_H
#define OPENSC_NOTIFY_CMDLINE_H
/* If we use autoconf. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h> /* for FILE */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CMDLINE_PARSER_PACKAGE
/** @brief the program name (used for printing errors) */
#define CMDLINE_PARSER_PACKAGE "opensc-notify"
#endif
#ifndef CMDLINE_PARSER_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
#define CMDLINE_PARSER_PACKAGE_NAME "opensc-notify"
#endif
#ifndef CMDLINE_PARSER_VERSION
/** @brief the program version */
#define CMDLINE_PARSER_VERSION VERSION
#endif
/** @brief Where the command line options are stored */
struct gengetopt_args_info
{
const char *help_help; /**< @brief Print help and exit help description. */
const char *version_help; /**< @brief Print version and exit help description. */
char * title_arg; /**< @brief Title of the notification. */
char * title_orig; /**< @brief Title of the notification original value given at command line. */
const char *title_help; /**< @brief Title of the notification help description. */
char * message_arg; /**< @brief Main text of the notification. */
char * message_orig; /**< @brief Main text of the notification original value given at command line. */
const char *message_help; /**< @brief Main text of the notification help description. */
int notify_card_inserted_flag; /**< @brief See notify_card_inserted in opensc.conf (default=off). */
const char *notify_card_inserted_help; /**< @brief See notify_card_inserted in opensc.conf help description. */
int notify_card_removed_flag; /**< @brief See notify_card_inserted in opensc.conf (default=off). */
const char *notify_card_removed_help; /**< @brief See notify_card_inserted in opensc.conf help description. */
int notify_pin_good_flag; /**< @brief See notify_pin_good in opensc.conf (default=off). */
const char *notify_pin_good_help; /**< @brief See notify_pin_good in opensc.conf help description. */
int notify_pin_bad_flag; /**< @brief See notify_pin_bad in opensc.conf (default=off). */
const char *notify_pin_bad_help; /**< @brief See notify_pin_bad in opensc.conf help description. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
unsigned int title_given ; /**< @brief Whether title was given. */
unsigned int message_given ; /**< @brief Whether message was given. */
unsigned int notify_card_inserted_given ; /**< @brief Whether notify-card-inserted was given. */
unsigned int notify_card_removed_given ; /**< @brief Whether notify-card-removed was given. */
unsigned int notify_pin_good_given ; /**< @brief Whether notify-pin-good was given. */
unsigned int notify_pin_bad_given ; /**< @brief Whether notify-pin-bad was given. */
int customized_mode_counter; /**< @brief Counter for mode customized */
int daemon_mode_counter; /**< @brief Counter for mode daemon */
int standard_mode_counter; /**< @brief Counter for mode standard */
} ;
/** @brief The additional parameters to pass to parser functions */
struct cmdline_parser_params
{
int override; /**< @brief whether to override possibly already present options (default 0) */
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
} ;
/** @brief the purpose string of the program */
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
/** @brief the description string of the program */
extern const char *gengetopt_args_info_description;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
/**
* The command line parser
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser (int argc, char **argv,
struct gengetopt_args_info *args_info);
/**
* The command line parser (version with additional parameters - deprecated)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_ext() instead
*/
int cmdline_parser2 (int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The command line parser (version with additional parameters)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_ext (int argc, char **argv,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
* @param outfile the stream where to dump options
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_dump(FILE *outfile,
struct gengetopt_args_info *args_info);
/**
* Save the contents of the option struct into a (text) file.
* This file can be read by the config file parser (if generated by gengetopt)
* @param filename the file where to save
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
void cmdline_parser_print_help(void);
/**
* Print the version
*/
void cmdline_parser_print_version(void);
/**
* Initializes all the fields a cmdline_parser_params structure
* to their default values
* @param params the structure to initialize
*/
void cmdline_parser_params_init(struct cmdline_parser_params *params);
/**
* Allocates dynamically a cmdline_parser_params structure and initializes
* all its fields to their default values
* @return the created and initialized cmdline_parser_params structure
*/
struct cmdline_parser_params *cmdline_parser_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
void cmdline_parser_init (struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
void cmdline_parser_free (struct gengetopt_args_info *args_info);
/**
* Checks that all the required options were specified
* @param args_info the structure to check
* @param prog_name the name of the program that will be used to print
* possible errors
* @return
*/
int cmdline_parser_required (struct gengetopt_args_info *args_info,
const char *prog_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* OPENSC_NOTIFY_CMDLINE_H */

View File

@ -21,8 +21,24 @@
#include "config.h"
#endif
#include "libopensc/log.h"
#include "opensc-notify-cmdline.h"
#include "ui/notify.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int run_daemon = 0;
static struct sc_context *ctx = NULL;
void stop_daemon(int signo)
{
#ifdef PCSCLITE_GOOD
sc_cancel(ctx);
#endif
run_daemon = 0;
}
#ifndef _WIN32
#include <time.h>
@ -41,30 +57,183 @@ void Sleep(unsigned int Milliseconds)
nanosleep(&req , &rem);
}
#else
#include "ui/invisible_window.h"
static HINSTANCE g_hInstance = NULL;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CLOSE) {
sc_cancel(ctx);
run_daemon = 0;
return TRUE;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
#endif
void notify_daemon(void)
{
int r;
const unsigned int event_mask = SC_EVENT_CARD_EVENTS;
unsigned int event;
struct sc_reader *event_reader = NULL;
size_t error_count = 0;
/* timeout adjusted to the maximum response time for WM_CLOSE in case
* canceling doesn't work */
const int timeout = 20000;
struct sc_atr old_atr;
void *reader_states = NULL;
#ifdef _WIN32
LPCTSTR lpszClassName = "OPENSC_NOTIFY_CLASS";
HWND hwnd = create_invisible_window(lpszClassName, WndProc, g_hInstance);
#elif HAVE_SIGACTION
struct sigaction new_sig, old_sig;
/* Register signal handlers */
new_sig.sa_handler = stop_daemon;
sigemptyset(&new_sig.sa_mask);
new_sig.sa_flags = SA_RESTART;
if ((sigaction(SIGINT, &new_sig, &old_sig) < 0)
|| (sigaction(SIGTERM, &new_sig, &old_sig) < 0)) {
fprintf(stderr, "Failed to create signal handler: %s", strerror(errno));
return;
}
#endif
r = sc_establish_context(&ctx, "opensc-notify");
if (r < 0 || !ctx) {
fprintf(stderr, "Failed to create initial context: %s", sc_strerror(r));
return;
}
while (run_daemon) {
if (0 > sc_wait_for_event(ctx, event_mask, &event_reader,
&event, timeout, &reader_states)) {
error_count++;
continue;
}
error_count = 0;
if (event & SC_EVENT_CARD_REMOVED) {
sc_notify_id(ctx, &old_atr, NULL, NOTIFY_CARD_REMOVED);
}
if (event & SC_EVENT_CARD_INSERTED) {
if (event_reader) {
/* FIXME `pcsc_wait_for_event` has all the information that's
* requested again with `pcsc_detect_card_presence`, but it
* doesn't use the ATR, for example, to refresh the reader's
* attributes. To get the ATR we need to call
* sc_detect_card_presence. Eventually this should be fixed. */
sc_detect_card_presence(event_reader);
memcpy(old_atr.value, event_reader->atr.value,
event_reader->atr.len);
old_atr.len = event_reader->atr.len;
} else {
old_atr.len = 0;
}
sc_notify_id(ctx, old_atr.len ? &old_atr : NULL, NULL,
NOTIFY_CARD_INSERTED);
}
}
if (ctx) {
/* free `reader_states` */
sc_wait_for_event(ctx, 0, NULL, NULL, 0, &reader_states);
reader_states = NULL;
sc_release_context(ctx);
ctx = NULL;
}
#ifdef _WIN32
delete_invisible_window(hwnd, lpszClassName, g_hInstance);
#endif
}
#ifdef _WIN32
#include "ui/char_str_from_wchar.h"
#include <shellapi.h>
/* This application shall be executable without a console. Therefor we're
* creating a windows application that requires `WinMain()` rather than
* `main()` as entry point. As benefit, we can properly handle `WM_CLOSE`. */
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
{
LPWSTR *wargv = NULL;
char **argv = NULL;
int argc = 0, i;
struct gengetopt_args_info cmdline;
wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (wargv == NULL) {
return 1;
}
argv = LocalAlloc(0, (sizeof *argv) * argc);
if (argv == NULL) {
goto err;
}
for (i = 0; i < argc; i++) {
argv[i] = char_str_from_wchar(wargv[i]);
}
g_hInstance = hInstance;
#else
int
main (int argc, char **argv)
{
const char *title = NULL, *text = NULL;
switch (argc) {
case 3:
text = argv[2];
/* fall through */
case 2:
title = argv[1];
/* fall through */
case 1:
break;
struct gengetopt_args_info cmdline;
#endif
if (cmdline_parser(argc, argv, &cmdline) != 0)
goto err;
default:
fprintf(stderr, "Usage: opensc-notify [title [text]]");
return 1;
}
sc_notify_init();
sc_notify(title, text);
Sleep(250);
if (cmdline.customized_mode_counter) {
sc_notify(cmdline.title_arg, cmdline.message_arg);
}
if (cmdline.standard_mode_counter) {
if (cmdline.notify_card_inserted_flag) {
sc_notify_id(NULL, NULL, NULL, NOTIFY_CARD_INSERTED);
}
if (cmdline.notify_card_removed_flag) {
sc_notify_id(NULL, NULL, NULL, NOTIFY_CARD_REMOVED);
}
if (cmdline.notify_pin_good_flag) {
sc_notify_id(NULL, NULL, NULL, NOTIFY_PIN_GOOD);
}
if (cmdline.notify_pin_bad_flag) {
sc_notify_id(NULL, NULL, NULL, NOTIFY_PIN_BAD);
}
}
if ((!cmdline.customized_mode_counter && !cmdline.standard_mode_counter)
|| cmdline.daemon_mode_counter) {
run_daemon = 1;
notify_daemon();
} else {
/* give the notification process some time to spawn */
Sleep(100);
}
sc_notify_close();
cmdline_parser_free (&cmdline);
err:
#ifdef _WIN32
if (argv) {
for (i = 0; i <= argc; i++) {
LocalFree(argv[i]);
}
LocalFree(argv);
}
LocalFree(wargv);
#endif
return 0;
}

View File

@ -0,0 +1,45 @@
package "opensc-notify"
purpose "@PACKAGE_SUMMARY@"
description "If no arguments are given, monitor smart card events and send the appropriate notification."
defmode "daemon"
modedesc="Monitor smart card events to send notifications."
defmode "standard"
modedesc="Manually send standard notifications."
defmode "customized"
modedesc="Send customized notifications."
modeoption "title" t
"Title of the notification"
string
mode="customized"
argoptional
optional
modeoption "message" m
"Main text of the notification"
string
mode="customized"
argoptional
optional
modeoption "notify-card-inserted" I
"See notify_card_inserted in opensc.conf"
flag off
mode="standard"
modeoption "notify-card-removed" R
"See notify_card_inserted in opensc.conf"
flag off
mode="standard"
modeoption "notify-pin-good" G
"See notify_pin_good in opensc.conf"
flag off
mode="standard"
modeoption "notify-pin-bad" B
"See notify_pin_bad in opensc.conf"
flag off
mode="standard"
text "
Report bugs to @PACKAGE_BUGREPORT@
Written by Frank Morgner <frankmorgner@gmail.com>"

View File

@ -0,0 +1,46 @@
/*
* char_str_from_wchar.h: Conversion from wide string to string
*
* Copyright (C) 2017 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <windows.h>
static char *char_str_from_wchar(const WCHAR *in)
{
char *out;
int out_len;
if (!in)
return NULL;
out_len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL);
if (0 >= out_len)
return NULL;
out = LocalAlloc(0, (sizeof *out) * out_len);
if (!out)
return NULL;
out_len = WideCharToMultiByte(CP_UTF8, 0, in, -1, out, out_len, NULL, NULL);
if (out_len == 0xFFFD || 0 >= out_len) {
LocalFree(out);
return NULL;
}
return out;
}

52
src/ui/invisible_window.h Normal file
View File

@ -0,0 +1,52 @@
/*
* invisible_window.h: Create invisible Window
*
* Copyright (C) 2017 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <windows.h>
HWND create_invisible_window(LPCTSTR lpszClassName,
LRESULT (CALLBACK* WndProc)(HWND, UINT, WPARAM, LPARAM),
HINSTANCE hInstance)
{
HWND hWnd = NULL;
WNDCLASSEX wx = {0};
//Register Window class
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WndProc;
wx.hInstance = hInstance;
wx.lpszClassName = lpszClassName;
if (RegisterClassEx(&wx)) {
/* create window */
hWnd = CreateWindowEx(0, lpszClassName, lpszClassName, 0, 0, 0, 0, 0,
HWND_MESSAGE, NULL, NULL, NULL );
}
return hWnd;
}
static BOOL delete_invisible_window(HWND hWnd, LPCTSTR lpszClassName,
HINSTANCE hInstance)
{
BOOL r;
r = DestroyWindow(hWnd);
r &= UnregisterClass(lpszClassName, hInstance);
return r;
}

View File

@ -65,6 +65,7 @@ void sc_notify_close(void)
#if defined(ENABLE_NOTIFY) && defined(_WIN32)
#include "invisible_window.h"
#include "wchar_from_char_str.h"
#include <shellapi.h>
@ -72,13 +73,14 @@ static const GUID myGUID = {0x23977b55, 0x10e0, 0x4041, {0xb8,
0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x69}};
HINSTANCE sc_notify_instance = NULL;
HWND hwndNotification = NULL;
BOOL delete_icon = TRUE;
#define IDI_SMARTCARD 102
#define IDI_UNLOCKED 103
#define IDI_LOCKED 104
#define IDI_READER_EMPTY 105
#define IDI_CARD_INSERTED 106
UINT const WMAPP_NOTIFYCALLBACK = WM_APP + 1;
BOOL RestoreTooltip(void);
static BOOL RestoreTooltip();
// we need commctrl v6 for LoadIconMetric()
#include <commctrl.h>
@ -100,54 +102,16 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hwnd, message, wParam, lParam);
}
static const char* class_name = "DUMMY_CLASS";
static const char* window_name = "DUMMY_WINDOW";
static BOOL create_invisible_window(void)
{
if (!hwndNotification) {
//Register Window class
WNDCLASSEX wx = {0};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WndProc; // function which will handle messages
wx.hInstance = sc_notify_instance;
wx.lpszClassName = class_name;
if (!RegisterClassEx(&wx)) {
return FALSE;
}
/* create window */
hwndNotification = CreateWindowEx(0, class_name, window_name,
0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
}
if (hwndNotification) {
return TRUE;
}
return FALSE;
}
static BOOL delete_invisible_window(void)
{
BOOL r;
r = DestroyWindow(hwndNotification);
r &= UnregisterClass(class_name, sc_notify_instance);
hwndNotification = NULL;
return r;
}
static const char* lpszClassName = "NOTIFY_CLASS";
static BOOL AddNotificationIcon(void)
{
NOTIFYICONDATA nid = {sizeof(nid)};
NOTIFYICONDATA nid;
TCHAR path[MAX_PATH]={0};
BOOL r;
if (!create_invisible_window()) {
return FALSE;
}
memset(&nid, 0, sizeof nid);
nid.cbSize = sizeof nid;
nid.hWnd = hwndNotification;
// add the icon, setting the icon, tooltip, and callback message.
// the icon will be identified with the GUID
@ -156,7 +120,18 @@ static BOOL AddNotificationIcon(void)
nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK;
LoadIconMetric(sc_notify_instance, MAKEINTRESOURCEW(IDI_SMARTCARD), LIM_SMALL, &nid.hIcon);
if (GetModuleFileName(NULL, path, ARRAYSIZE(path))) {
strcpy_s(nid.szTip, ARRAYSIZE(nid.szTip), path);
const char *basename = strrchr(path, '\\');
if (basename) {
basename++;
if (0 != strcmp(basename, "opensc-notify.exe")) {
/* Allow creation of sytem tray icon only for
* "opensc-notify.exe" to avoid creation of the same icon by
* multiple processes. */
delete_icon = FALSE;
return FALSE;
}
}
strlcpy(nid.szTip, path, ARRAYSIZE(nid.szTip));
} else {
strcpy(nid.szTip, PACKAGE_NAME);
}
@ -166,19 +141,32 @@ static BOOL AddNotificationIcon(void)
nid.uVersion = NOTIFYICON_VERSION_4;
r &= Shell_NotifyIcon(NIM_SETVERSION, &nid);
hwndNotification = create_invisible_window(lpszClassName, WndProc, sc_notify_instance);
if (!hwndNotification) {
r = FALSE;
}
return r;
}
static BOOL DeleteNotificationIcon(void)
{
BOOL r;
NOTIFYICONDATA nid = {sizeof(nid)};
NOTIFYICONDATA nid;
if (!delete_icon) {
return FALSE;
}
memset(&nid, 0, sizeof nid);
nid.cbSize = sizeof nid;
nid.uFlags = NIF_GUID;
nid.guidItem = myGUID;
r = Shell_NotifyIcon(NIM_DELETE, &nid);
r &= delete_invisible_window();
r &= delete_invisible_window(hwndNotification, lpszClassName,
sc_notify_instance);
return r;
}
@ -186,8 +174,10 @@ static BOOL DeleteNotificationIcon(void)
static BOOL RestoreTooltip()
{
// After the balloon is dismissed, restore the tooltip.
NOTIFYICONDATA nid = {sizeof(nid)};
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof nid);
nid.cbSize = sizeof nid;
nid.uFlags = NIF_SHOWTIP | NIF_GUID;
nid.guidItem = myGUID;
@ -197,17 +187,19 @@ static BOOL RestoreTooltip()
static void notify_shell(struct sc_context *ctx,
const char *title, const char *text, WORD icon)
{
NOTIFYICONDATA nid = {sizeof(nid)};
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof nid);
nid.cbSize = sizeof nid;
nid.uFlags = NIF_GUID;
nid.guidItem = myGUID;
if (title) {
strcpy_s(nid.szInfoTitle, ARRAYSIZE(nid.szInfoTitle), title);
strlcpy(nid.szInfoTitle, title, ARRAYSIZE(nid.szInfoTitle));
}
if (text) {
nid.uFlags |= NIF_INFO;
strcpy_s(nid.szInfo, ARRAYSIZE(nid.szInfo), text);
strlcpy(nid.szInfo, text, ARRAYSIZE(nid.szInfo));
}
if (icon) {
nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
@ -240,17 +232,11 @@ void sc_notify(const char *title, const char *text)
void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr,
struct sc_pkcs15_card *p15card, enum ui_str id)
{
const char *title, *text, *group;
const char *title, *text;
WORD icon;
title = ui_get_str(ctx, atr, p15card, id);
text = ui_get_str(ctx, atr, p15card, id+1);
if (p15card && p15card->card && p15card->card->reader) {
group = p15card->card->reader->name;
} else {
group = ctx ? ctx->app_name : NULL;
}
switch (id) {
case NOTIFY_CARD_INSERTED:
icon = IDI_CARD_INSERTED;
@ -533,7 +519,7 @@ void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr,
#endif
#if defined(ENABLE_NOTIFY) && (defined(ENABLE_GIO2) || defined(GDBUS))
#if defined(ENABLE_NOTIFY) && (defined(ENABLE_GIO2) || defined(GDBUS) && !defined(_WIN32))
void sc_notify(const char *title, const char *text)
{
notify_gio(NULL, title, text, NULL, NULL);

View File

@ -138,6 +138,9 @@
<Component Id="opensc_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\opensc-tool.exe" Vital="yes"/>
</Component>
<Component Id="opensc_notify.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\opensc-notify.exe" Vital="yes"/>
</Component>
<Component Id="pkcs11_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\pkcs11-tool.exe" Vital="yes"/>
</Component>
@ -340,6 +343,7 @@
<Feature Id="OpenSC_tools" Level="1" Title="Tools and profiles" Description="Tools for debugging and personalization. Includes profiles needed for running pkcs15-init.exe">
<ComponentRef Id="opensc_explorer.exe"/>
<ComponentRef Id="opensc_tool.exe"/>
<ComponentRef Id="opensc_notify.exe"/>
<ComponentRef Id="pkcs11_tool.exe"/>
<ComponentRef Id="cardos_tool.exe"/>
<ComponentRef Id="eidenv.exe"/>