implement ffmpeg webcam + imgur + twilio mms support.
This commit is contained in:
parent
3a1c71669f
commit
6ecebe7703
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
twilio.*
|
twilio.*
|
||||||
|
imgur.*
|
||||||
|
1
imgur_example.h
Normal file
1
imgur_example.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
#define IMGUR_CLIENT "{imgur-client-id}"
|
358
slock.c
358
slock.c
@ -25,12 +25,21 @@
|
|||||||
#include <bsd_auth.h>
|
#include <bsd_auth.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SLOCK_SHUTDOWN 1
|
#define CMD_LENGTH (500 * sizeof(char))
|
||||||
#define TWILIO_SEND 1
|
|
||||||
|
|
||||||
#if TWILIO_SEND
|
#define POWEROFF 1
|
||||||
|
#define TWILIO_SEND 1
|
||||||
|
#define WEBCAM_SHOT 1
|
||||||
|
#define IMGUR_UPLOAD 0
|
||||||
|
#define PLAY_AUDIO 1
|
||||||
|
|
||||||
|
#include "imgur.h"
|
||||||
#include "twilio.h"
|
#include "twilio.h"
|
||||||
#endif
|
|
||||||
|
typedef struct {
|
||||||
|
char *link;
|
||||||
|
char *deletehash;
|
||||||
|
} imgur_data;
|
||||||
|
|
||||||
char *g_pw = NULL;
|
char *g_pw = NULL;
|
||||||
int lock_tries = 0;
|
int lock_tries = 0;
|
||||||
@ -111,19 +120,252 @@ getpw(void) { /* only run as root */
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SLOCK_SHUTDOWN
|
static char *
|
||||||
|
read_tfile(char *name) {
|
||||||
|
FILE *f = fopen(name, "r");
|
||||||
|
|
||||||
|
struct stat s;
|
||||||
|
if (stat(name, &s) == -1) goto error;
|
||||||
|
|
||||||
|
char *buf = malloc(s.st_size);
|
||||||
|
if (buf == NULL) goto error;
|
||||||
|
fread(buf, 1, s.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (buf[i]) {
|
||||||
|
if (buf[i] == '\r' || buf[i] == '\n') {
|
||||||
|
buf[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
error:
|
||||||
|
fprintf(stderr, "Could not open: %s.\n", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poweroff if we're in danger.
|
||||||
static void
|
static void
|
||||||
poweroff() {
|
poweroff(void) {
|
||||||
|
#if POWEROFF
|
||||||
// Needs sudo privileges - alter your /etc/sudoers file:
|
// Needs sudo privileges - alter your /etc/sudoers file:
|
||||||
// systemd: [username] [hostname] =NOPASSWD: /usr/bin/systemctl poweroff
|
// systemd: [username] [hostname] =NOPASSWD: /usr/bin/systemctl poweroff
|
||||||
// sysvinit: [username] [hostname] =NOPASSWD: /usr/bin/shutdown -h now
|
// sysvinit: [username] [hostname] =NOPASSWD: /usr/bin/shutdown -h now
|
||||||
char *args[] = { "sudo", "systemctl", "poweroff", NULL };
|
char *args[] = { "sudo", "systemctl", "poweroff", NULL };
|
||||||
execvp("sudo", args);
|
|
||||||
char *args_legacy[] = { "sudo", "shutdown", "-h", "now", NULL };
|
char *args_legacy[] = { "sudo", "shutdown", "-h", "now", NULL };
|
||||||
execvp("sudo", args_legacy);
|
execvp(args[0], args);
|
||||||
|
execvp(args_legacy[0], args_legacy);
|
||||||
fprintf(stderr, "Error: cannot shutdown. Check your /etc/sudoers file.\n");
|
fprintf(stderr, "Error: cannot shutdown. Check your /etc/sudoers file.\n");
|
||||||
}
|
#else
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a screenshot of whoever is at the keyboard.
|
||||||
|
static int
|
||||||
|
webcam_shot(int async) {
|
||||||
|
#if WEBCAM_SHOT
|
||||||
|
char *cmd = (char *)malloc(CMD_LENGTH);
|
||||||
|
|
||||||
|
int r = snprintf(cmd, CMD_LENGTH,
|
||||||
|
"ffmpeg -y -loglevel quiet -f video4linux2 -i /dev/video0"
|
||||||
|
" -frames:v 1 -f image2 %s/slock.jpg%s",
|
||||||
|
getenv("HOME"), async ? " &" : "");
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(cmd);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cmd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
twilio_send(const char *msg, imgur_data *idata, int async) {
|
||||||
|
#if TWILIO_SEND
|
||||||
|
char *cmd = (char *)malloc(CMD_LENGTH);
|
||||||
|
|
||||||
|
// Send the SMS/MMS via Twilio
|
||||||
|
int r = snprintf(cmd, CMD_LENGTH,
|
||||||
|
"curl -s -A '' -X POST https://api.twilio.com/2010-04-01/Accounts/"
|
||||||
|
TWILIO_ACCOUNT "/SMS/Messages.json"
|
||||||
|
" -u " TWILIO_AUTH
|
||||||
|
" --data-urlencode 'From=" TWILIO_FROM "'"
|
||||||
|
" --data-urlencode 'To=" TWILIO_TO "'"
|
||||||
|
" --data-urlencode 'Body=%s'"
|
||||||
|
" --data-urlencode 'MediaUrl=%s' > /dev/null"
|
||||||
|
"%s", msg, idata ? idata->link : "", async ? " &" : "");
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(cmd);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cmd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static imgur_data *
|
||||||
|
imgur_upload(void) {
|
||||||
|
#if IMGUR_UPLOAD
|
||||||
|
char *buf = (char *)malloc(CMD_LENGTH);
|
||||||
|
imgur_data *idata = (imgur_data *)malloc(sizeof(imgur_data));
|
||||||
|
memset(idata, 0, sizeof(imgur_data));
|
||||||
|
int r;
|
||||||
|
|
||||||
|
// Upload the imgur image:
|
||||||
|
r = snprintf(buf, CMD_LENGTH,
|
||||||
|
"curl -s -A '' -X POST"
|
||||||
|
" -H 'Authorization: Client-ID " IMGUR_CLIENT "'"
|
||||||
|
" -F 'image=@%s/slock.jpg'"
|
||||||
|
" 'https://api.imgur.com/3/image' > %s/slock_imgur.curl",
|
||||||
|
getenv("HOME"), getenv("HOME"));
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(buf);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
if (r == -1) return NULL;
|
||||||
|
|
||||||
|
// Get the link:
|
||||||
|
r = snprintf(buf, CMD_LENGTH,
|
||||||
|
"cat %s/slock_imgur.curl"
|
||||||
|
" | grep -o '\"link\":\"[^\"]\\+'"
|
||||||
|
" | sed 's/\\\\//g'"
|
||||||
|
" | grep -o '[^\"]\\+$'"
|
||||||
|
" > %s/slock_imgur.link",
|
||||||
|
getenv("HOME"), getenv("HOME"));
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(buf);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
if (r == -1) return NULL;
|
||||||
|
|
||||||
|
// Get the deletehash:
|
||||||
|
r = snprintf(buf, CMD_LENGTH,
|
||||||
|
"cat %s/slock_imgur.curl"
|
||||||
|
" | grep -o '\"deletehash\":\"[^\"]\\+'"
|
||||||
|
" | grep -o '[^\"]\\+$'"
|
||||||
|
" > %s/slock_imgur.deletehash",
|
||||||
|
getenv("HOME"), getenv("HOME"));
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(buf);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
if (r == -1) return NULL;
|
||||||
|
|
||||||
|
r = snprintf(buf, CMD_LENGTH, "%s/slock_imgur.curl", getenv("HOME"));
|
||||||
|
if (r > 0) {
|
||||||
|
unlink(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = snprintf(buf, CMD_LENGTH, "%s/slock_imgur.link", getenv("HOME"));
|
||||||
|
if (r > 0) {
|
||||||
|
idata->link = read_tfile(buf);
|
||||||
|
unlink(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = snprintf(buf, CMD_LENGTH, "%s/slock_imgur.deletehash", getenv("HOME"));
|
||||||
|
if (r > 0) {
|
||||||
|
idata->deletehash = read_tfile(buf);
|
||||||
|
unlink(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (idata->link == NULL
|
||||||
|
|| !strlen(idata->link)
|
||||||
|
|| idata->deletehash == NULL
|
||||||
|
|| !strlen(idata->deletehash)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idata;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
imgur_delete(imgur_data *idata) {
|
||||||
|
#if IMGUR_UPLOAD
|
||||||
|
char *cmd = (char *)malloc(CMD_LENGTH);
|
||||||
|
|
||||||
|
// Delete the imgur image:
|
||||||
|
int r = snprintf(cmd, CMD_LENGTH,
|
||||||
|
"curl -s -A '' -X DELETE"
|
||||||
|
" -H 'Authorization: Client-ID " IMGUR_CLIENT "'"
|
||||||
|
" 'https://api.imgur.com/3/image/%s'", idata->deletehash);
|
||||||
|
|
||||||
|
// Wait for Twilio to do its request:
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
system(cmd);
|
||||||
|
r = 0;
|
||||||
|
} else {
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cmd);
|
||||||
|
free(idata->link);
|
||||||
|
free(idata->deletehash);
|
||||||
|
free(idata);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
play_beep(int async) {
|
||||||
|
#if PLAY_AUDIO
|
||||||
|
char snd[255] = {0};
|
||||||
|
snprintf(snd, sizeof(snd), "aplay %s/slock/beep.wav 2> /dev/null%s",
|
||||||
|
getenv("HOME"), async ? " &" : "");
|
||||||
|
system(snd);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
play_alarm(int async) {
|
||||||
|
#if PLAY_AUDIO
|
||||||
|
char snd[255] = {0};
|
||||||
|
snprintf(snd, sizeof(snd), "aplay %s/slock/police.wav 2> /dev/null%s",
|
||||||
|
getenv("HOME"), async ? " &" : "");
|
||||||
|
system(snd);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
#ifdef HAVE_BSD_AUTH
|
#ifdef HAVE_BSD_AUTH
|
||||||
@ -137,6 +379,7 @@ readpw(Display *dpy, const char *pws)
|
|||||||
unsigned int len, llen;
|
unsigned int len, llen;
|
||||||
KeySym ksym;
|
KeySym ksym;
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
imgur_data *idata = NULL;
|
||||||
|
|
||||||
len = llen = 0;
|
len = llen = 0;
|
||||||
running = True;
|
running = True;
|
||||||
@ -174,32 +417,44 @@ readpw(Display *dpy, const char *pws)
|
|||||||
if(running) {
|
if(running) {
|
||||||
XBell(dpy, 100);
|
XBell(dpy, 100);
|
||||||
lock_tries++;
|
lock_tries++;
|
||||||
#if TWILIO_SEND
|
|
||||||
twilio_send("Bad screenlock password.", 1);
|
// Poweroff if there are more than 5 bad attempts.
|
||||||
#endif
|
|
||||||
#if SLOCK_SHUTDOWN
|
|
||||||
if(lock_tries > 5) {
|
if(lock_tries > 5) {
|
||||||
|
// Take a webcam shot of whoever is tampering with our machine:
|
||||||
|
webcam_shot(0);
|
||||||
|
|
||||||
|
// Upload the image:
|
||||||
|
idata = imgur_upload();
|
||||||
|
|
||||||
|
// Send an SMS/MMS via twilio:
|
||||||
|
twilio_send("Bad screenlock password.", idata, 0);
|
||||||
|
|
||||||
|
// Delete the image from imgur:
|
||||||
|
imgur_delete(idata);
|
||||||
|
|
||||||
|
// Immediately poweroff:
|
||||||
poweroff();
|
poweroff();
|
||||||
// if we failed, simply resume
|
|
||||||
|
// If we failed, simply resume:
|
||||||
len = 0;
|
len = 0;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
// Take a webcam shot of whoever is tampering with our machine:
|
||||||
|
webcam_shot(1);
|
||||||
|
|
||||||
|
// Send an SMS via twilio:
|
||||||
|
twilio_send("Bad screenlock password.", NULL, 1);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// Play a siren if there are more than 2 bad
|
||||||
|
// passwords, a beep if a correct password:
|
||||||
if(lock_tries > 2) {
|
if(lock_tries > 2) {
|
||||||
// http://soundbible.com/1819-Police.html
|
play_alarm(0);
|
||||||
char snd[255] = {0};
|
|
||||||
snprintf(snd, sizeof(snd), "aplay %s/slock/police.wav", getenv("HOME"));
|
|
||||||
system(snd);
|
|
||||||
} else {
|
} else {
|
||||||
char snd[255] = {0};
|
play_beep(0);
|
||||||
snprintf(snd, sizeof(snd), "aplay %s/slock/beep.wav", getenv("HOME"));
|
|
||||||
system(snd);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// http://soundbible.com/1815-A-Tone.html
|
play_beep(1);
|
||||||
char snd[255] = {0};
|
|
||||||
snprintf(snd, sizeof(snd), "aplay %s/slock/beep.wav &", getenv("HOME"));
|
|
||||||
system(snd);
|
|
||||||
}
|
}
|
||||||
len = 0;
|
len = 0;
|
||||||
break;
|
break;
|
||||||
@ -210,7 +465,6 @@ readpw(Display *dpy, const char *pws)
|
|||||||
if(len)
|
if(len)
|
||||||
--len;
|
--len;
|
||||||
break;
|
break;
|
||||||
#if SLOCK_SHUTDOWN
|
|
||||||
case XK_Alt_L:
|
case XK_Alt_L:
|
||||||
case XK_Alt_R:
|
case XK_Alt_R:
|
||||||
case XK_Control_L:
|
case XK_Control_L:
|
||||||
@ -228,12 +482,22 @@ readpw(Display *dpy, const char *pws)
|
|||||||
case XK_F11:
|
case XK_F11:
|
||||||
case XK_F12:
|
case XK_F12:
|
||||||
case XK_F13:
|
case XK_F13:
|
||||||
#if TWILIO_SEND
|
// Take a webcam shot of whoever is tampering with our machine:
|
||||||
twilio_send("Bad screenlock key.", 0);
|
webcam_shot(0);
|
||||||
#endif
|
|
||||||
|
// Upload our image:
|
||||||
|
idata = imgur_upload();
|
||||||
|
|
||||||
|
// Send an SMS/MMS via twilio:
|
||||||
|
twilio_send("Bad screenlock key.", idata, 0);
|
||||||
|
|
||||||
|
// Delete the image from imgur:
|
||||||
|
imgur_delete(idata);
|
||||||
|
|
||||||
|
// Immediately poweroff:
|
||||||
poweroff();
|
poweroff();
|
||||||
|
|
||||||
; // fall-through if we fail
|
; // fall-through if we fail
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
if(num && !iscntrl((int) buf[0]) && (len + num < sizeof passwd)) {
|
if(num && !iscntrl((int) buf[0]) && (len + num < sizeof passwd)) {
|
||||||
memcpy(passwd + len, buf, num);
|
memcpy(passwd + len, buf, num);
|
||||||
@ -339,25 +603,6 @@ usage(void) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
read_pfile(char *name) {
|
|
||||||
FILE *f = fopen(name, "r");
|
|
||||||
|
|
||||||
struct stat s;
|
|
||||||
if (stat(name, &s) == -1) goto error;
|
|
||||||
|
|
||||||
char *buf = malloc(s.st_size);
|
|
||||||
if (buf == NULL) goto error;
|
|
||||||
fread(buf, 1, s.st_size, f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
|
|
||||||
error:
|
|
||||||
fprintf(stderr, "Could not open: %s.\n", name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
#ifndef HAVE_BSD_AUTH
|
#ifndef HAVE_BSD_AUTH
|
||||||
@ -373,7 +618,7 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
char buf[255] = {0};
|
char buf[255] = {0};
|
||||||
snprintf(buf, sizeof(buf), "%s/.slock_passwd", getenv("HOME"));
|
snprintf(buf, sizeof(buf), "%s/.slock_passwd", getenv("HOME"));
|
||||||
g_pw = read_pfile(buf);
|
g_pw = read_tfile(buf);
|
||||||
|
|
||||||
if((argc >= 2) && !strcmp("-v", argv[1])) {
|
if((argc >= 2) && !strcmp("-v", argv[1])) {
|
||||||
die("slock-%s, © 2006-2012 Anselm R Garbe\n", VERSION);
|
die("slock-%s, © 2006-2012 Anselm R Garbe\n", VERSION);
|
||||||
@ -381,17 +626,6 @@ main(int argc, char **argv) {
|
|||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_pw) {
|
|
||||||
int i = 0;
|
|
||||||
while (g_pw[i]) {
|
|
||||||
if (g_pw[i] == '\r' || g_pw[i] == '\n') {
|
|
||||||
g_pw[i] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
dontkillme();
|
dontkillme();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,17 +1,4 @@
|
|||||||
#define TWILIO_API_SIZE (500 * sizeof(char))
|
#define TWILIO_ACCOUNT "{account-id}"
|
||||||
|
#define TWILIO_AUTH "{user}:{pass}"
|
||||||
static int
|
#define TWILIO_FROM "+12225550001"
|
||||||
twilio_send(const char *msg, int async) {
|
#define TWILIO_TO "+12225550002"
|
||||||
char *cmd = (char *)malloc(TWILIO_API_SIZE);
|
|
||||||
int r = snprintf(cmd, TWILIO_API_SIZE,
|
|
||||||
"curl -X POST https://api.twilio.com/2010-04-01/Accounts/{account}/SMS/Messages.json"
|
|
||||||
" -u {username}:{password}"
|
|
||||||
" --data-urlencode 'From=+{twilio-number}'"
|
|
||||||
" --data-urlencode 'To=+{phone-number}'"
|
|
||||||
" --data-urlencode 'Body=%s'"
|
|
||||||
"%s", msg, async ? " &" : "");
|
|
||||||
if (r == -1) return r;
|
|
||||||
r = system(cmd);
|
|
||||||
free(cmd);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user