/* Terminal ScreenSaver
* Copyright (C) 2006 Kristian "gamkiller" Gunstone
*
* Locking and shadow password retrieval code based on
* vlock 1.3
* Copyright (C) 1994 Michael K. Johnson and Marek
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
***
*
* TODO:
* - Attempt to disable blanking and restore it on exit
* (usnig setterm -blank 0 (Don't know how to get it back?))
* - User-configurable object speeds
* - Better deinit on perrors
* - Security checks
* - Cleaning up
*
* BUGS:
* - Slight misalignments between internal data and curses
* - Floating point exception on init (Due to small termsize)
* - Offset problem in random values
*
* THOUGHS:
* - WARNING: "MAXLINES" used in non-line fashion(mirrorbuf)
*
* Changelog:
*
* 0.8.1
* - Added failed login attempt reporting via syslog
* 0.8
* - Initial direction selection
* - Inline mirror disabling
* - Command line options for object speeds
* 0.7.8.4
* - ASCII autopadding. No need to manually pad spaces!
* - Long options
* - Added an other char to mirror (b->d, d->b)
* - Widest line check fix (last line was never compared)
* - Minor offset adjustments for very small terminals
* - MAXPATH on all path related chars
* - Check if ascii path exceeds MAXPATH
*
* 0.7.8.3
* - VT_SETMODE error checking
* - frsig fix (Fixes broken locking in FreeBSD)
* 0.7.8.2
* - flush stdin before getinput (Fixes odd "ghost keys" on input)
* 0.7.8.1
* - Very minor bugfixes. has_colors() warning in code,
* changes to help and INSTALL
* 0.7.8
* - Commented out script exec code. Too lazy to do it.
* - Mirroring enabled by default
* - Added A_BOLD (Daemon now looks like in FreeBSD)
* - Removed static allocation for ascii
* - Full color support
* - Fixed typo in mirroring code
* 0.7.7
* - Ascii mirroring support
* - file_name broken if not random (from 0.7.5)
* 0.7.6
* - Size check for passwd screen
* - Timeout countdown display
* - Password entry timeout code
* - New frame for password box
* 0.7.5
* - Minor fixes
* - Added an other default directory, $HOME/.tss/
* - Failed login report on exit
* - Broken terminal configuration on exit (First seen in 0.7.4)
* - O_RDWR define fix (minor)
* 0.7.4
* - Minor fixes
* - VT Locking
* 0.7.3
* - Fixed fd_isset SIGABRT call when screen was too small
* - Additional experimental locking code
* - Load average as default scrolltext
* 0.7.2:
* - Lock screen (no actual lock yet)
* - Dynamic text in scrollbox
* - shellscript exeuction
* 0.7.1:
* - Argument handler
* - Scrollbox
* - Delay set
* 0.7:
* - Random ascii read support
* - Speed differing on objs
* - Complete code rewrite.
*
* */
#define _XOPEN_SOURCE 1
#include <pwd.h>
#include <time.h>
#include <glob.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <strings.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
#ifndef BSD
#include <ncurses.h>
#include <shadow.h>
#include <sys/vt.h>
#include <sys/kd.h>
#define SA_RESTART 0x10000000
#else
#include <curses.h>
#include <sys/consio.h>
#endif
#define VERSION "0.8.1"
#define DEFAULT_ASCII_DIR "/usr/local/etc/tss/"
#define DEFAULT_ASCII "default"
#define MAX_ASCII_SIZE 1024000
#define TIMEOUT 30
#define MAXLINES 1024
#define MAXPATH 512
#define SCROLL_BOX_WIDTH 20
#define UNAME 0
#define INFO 1
int lock_delay;
int failed_logins;
int vfd;
int screen_width;
int screen_height;
int current_color;
FILE *fd_ascii;
static char username[40];
static char userpass[200];
char _error_message[128];
char mirrorchr[2][15];
char *scroll_buffer;
glob_t list;
struct vt_mode ovtm;
struct termios oterm;
static sigset_t osig;
struct ascii_objEx{
char *data;
char *line[MAXLINES];
char *blank[MAXLINES];
char mirror[MAXLINES];
float x;
float y;
int max_x;
int max_y;
float direction_x;
float direction_y;
float speed;
int width;
int width_real;
int height;
} ascii_obj;
static struct option const long_options[] = {
{"no-mirror", no_argument, NULL, 'n'},
{"scrollbar", no_argument, NULL, 's'},
{"random", no_argument, NULL, 'r'},
{"lock-terminal", no_argument, NULL, 'l'},
{"delay", required_argument, NULL, 'd'},
{"ascii", required_argument, NULL, 'a'},
{"object-speed", required_argument, NULL, 'o'},
{"uname-speed", required_argument, NULL, 'e'},
{"info-speed", required_argument, NULL, 'i'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
void report_failed_login(char *user/*, char *pass*/){
openlog("tss", LOG_PID | LOG_ODELAY, LOG_USER);
/*syslog(LOG_NOTICE, "Failed login attempt with password \"%s\" for user \"%s\"", pass, user);*/
syslog(LOG_NOTICE, "Failed login attempt for user \"%s\"", user);
closelog();
}
void vt_release(int sig){
ioctl(vfd, VT_RELDISP, 0);
}
void signal_ignorer(int sig){
return;
}
void restore_terminal(void){
ioctl(vfd, VT_SETMODE, &ovtm);
tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
}
int getloadavg(double loadavg[], int nelem);
#ifndef BSD
void usleep(unsigned long usec);
#endif
long lof(FILE *fptr){
long old, new;
fseek(fptr, 0, SEEK_CUR);
old = ftell(fptr);
fseek(fptr, 0, SEEK_END);
new = ftell(fptr);
fseek(fptr, 0, old);
return new;
}
void cleanup(void){
int i;
for(i = 0; i < (ascii_obj.height - 1); i++){
/* fprintf(stderr, "DEBUG: Freeing objline %d (%db)\n", i, strlen(ascii_obj.line[i]));*/
free(ascii_obj.line[i]);
/* fprintf(stderr, "DEBUG: Freeing blkline %d (%db)\n", i, strlen(ascii_obj.blank[i]));*/
free(ascii_obj.blank[i]);
}
globfree(&list);
if(ascii_obj.data != NULL)
free(ascii_obj.data);
free(scroll_buffer);
if(fd_ascii != NULL)
fclose(fd_ascii);
if(vfd != -1)
close(vfd);
}
void severe_error(char *message){
endwin();
fprintf(stderr, "%s\n", message);
cleanup();
exit(1);
}
double tickcount(void){
struct timeval tick;
double time;
gettimeofday(&tick, 0);
time = (double) tick.tv_sec + ((double) tick.tv_usec) / 1000000;
return time;
}
void showver(void){
printf("Terminal Screensaver v%s (C) 2006 Kristian Gunstone.\n\n", VERSION);
}
void showcopyright(void){
printf("This is free software; see the source for copying conditions. "
"There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS "
"FOR A PARTICULAR PURPOSE.\n\n");
}
void usage(char *me){
showver();
printf("Usage: %s [-s] [-r] [-l] [-n] [-h] [-V] "
"[-d delay] [-a ascii]\n", me);
/*"[-d delay] [-a ascii] [-t script] [-u secs]\n", me);*/
printf("Default: %s -d 120 -o .5 -e .1 -i 1 -a %s/default\n\n", me, DEFAULT_ASCII_DIR);
printf(" -n, --no-delay Disable ASCII mirroring\n");
printf(" -s, --scrollbar Show load average in a scrollbar\n");
printf(" -r, --random Choose random ascii file\n");
printf(" -l, --lock-terminal Lock terminal\n");
printf(" -d, --delay=[delay] Update every [delay] milliseconds\n");
printf(" -a, --ascii=[ascii] Use ascii [ascii]\n");
printf(" -o, --object-speed=[speed] Set ascii speed (0.001 - 1.00)\n");
printf(" -e, --uname-speed=[speed] Set uname speed (0.001 - 1.00)\n");
printf(" -i, --info-speed=[speed] Set info speed (0.001 - 1.00)\n");
/*
printf(" [UNDONE] -t Show output of [script] in scrolltext\n");
printf(" [UNDONE] -u Run [script] every [seconds] seconds\n");
*/
printf(" -h, --help Show this text\n");
printf(" -V, --version Show version\n\n");
showcopyright();
}
void drawpercent(double value){
double v_percent;
double s_percent;
v_percent = 100 * value / TIMEOUT;
s_percent = screen_height * v_percent / 100;
mvprintw((int)s_percent - 1, 0, " ");
/*mvprintw((int)s_percent - 1, 1, " ");
mvprintw((int)s_percent, 1, "%.1f ", TIMEOUT - value);*/
}
char *getinput(void){
char *tmpbuf;
int offset;
int key;
int i;
short busy;
double timer_beg;
double timer_end;
offset = 0;
tmpbuf = calloc(1025, 1);
for(i = 0; i < screen_height; i++)
mvaddch(i, 0, ACS_VLINE);
/* In case we have garbage in our buffer */
fflush(stdin);
timer_beg = tickcount();
busy = 1;
while(busy){
key = getch();
timer_end = tickcount() - timer_beg;
if(timer_end >= TIMEOUT)
busy = 0;
drawpercent(timer_end);
switch(key){
case ERR: break;
case '\r':
case '\n':
busy = 0;
break;
case 127:
case '\b':
if(offset > 0){
offset--;
tmpbuf[offset] = 0;
}
break;
default:
if(offset < 1024)
tmpbuf[offset++] = key;
}
}
return tmpbuf;
}
int lock_screen(int w, int h){
char *pwd;
char text[128];
char blank[128];
int centerx;
int centery;
int result;
int i;
bzero(text, 128);
sprintf(text, "This screen has been locked by %s.", username);
bzero(blank, 128);
sprintf(blank,"Password:");
memset(&blank[9], 32, strlen(text) - 9);
blank[strlen(text) + 1] = 0;
centerx = (w - (strlen(text)/* - 1*/)) / 2;
centery = (h - 5) / 2;
attroff(A_BOLD);
attron(COLOR_PAIR(8));
/* Draw box. Dirty. */
for(i = 1; i < strlen(text) + 1; i++){
mvaddch(centery, centerx + i, ACS_HLINE);
mvaddch(centery + 3, centerx + i, ACS_HLINE);
}
mvaddch(centery, centerx + i, ACS_URCORNER);
mvaddch(centery + 3, centerx + i, ACS_LRCORNER);
for(i = 1; i < 3; i++){
mvaddch(centery + i, centerx, ACS_VLINE);
mvaddch(centery + i, centerx + strlen(text) + 1, ACS_VLINE);
}
mvaddch(centery, centerx, ACS_ULCORNER);
mvaddch(centery + 3, centerx, ACS_LLCORNER);
mvprintw(centery + 1, centerx + 1, "%s", text);
mvprintw(centery + 2, centerx + 1, "%s", blank);
/* Get input and check with password via crypt */
pwd = getinput();
if(strcmp(crypt(pwd, userpass), userpass) == 0)
result = 0;
else
result = 1;
bzero(pwd, strlen(pwd));
free(pwd);
/* If the terminal is closed, we should exit */
if(isatty(STDIN_FILENO) == 0){
perror("isatty");
restore_terminal();
severe_error(NULL);
}
if(result == 1){
report_failed_login(username/*, pwd*/);
sleep(lock_delay++);
mvprintw(centery + 2, centerx + 11, "Sorry.");
refresh();
if(lock_delay > 10){
sleep(5); /* Punishment */
lock_delay = 3;
}else{
sleep(1);
}
failed_logins++;
}
clear();
attroff(COLOR_PAIR(8));
attron(A_BOLD);
return result;
}
/* This code is SUID! Don't mess with it! */
static struct passwd *my_getpwuid(uid_t uid){
struct passwd *pwd;
#ifndef BSD
struct spwd *sp;
#endif
pwd = getpwuid(uid);
if(!pwd){
sprintf(_error_message, "getpwuid(%d) failed: %s\n", uid, strerror(errno));
severe_error(_error_message);
}
#ifndef BSD
/* Why the hell was I doing this? Shit. I forgot :| */
sp = getspnam(pwd->pw_name); /* Get pw via name instead of uid */
if(sp) /* If it _worked_, */
pwd->pw_passwd = sp->sp_pwdp; /* Copy it to our buffer */
/* buy WHY! We already have it %!"/&# */
endspent();
#endif
return pwd;
}
void colormvprintw(int y, int x, char *buf){
int i;
move(y, x);
for(i = 0; i < strlen(buf); i++){
if(buf[i] == 27){
if(buf[i + 2] == 27)
while(buf[i + 2] == 27)
i += 2;
attroff(COLOR_PAIR(current_color));
current_color = buf[i + 1] - 48;
attron(COLOR_PAIR(current_color));
i += 2;
}
printw("%c", buf[i]);
}
}
void perform_mirror(void){
int i, a, b;
for(i = 0; i < ascii_obj.height; i++){
strcpy(ascii_obj.mirror, ascii_obj.line[i]);
/* Pre-flip color codes and char */
for(a = 0; a < strlen(ascii_obj.mirror) - 1; a++)
if(ascii_obj.mirror[a] == 27){
ascii_obj.mirror[a] = ascii_obj.mirror[a + 1];
ascii_obj.mirror[a + 1] = 27;
a++;
}
for(a = 0, b = strlen(ascii_obj.mirror) - 1; a < strlen(ascii_obj.mirror), b >= 0; a++, b--)
ascii_obj.line[i][b] = ascii_obj.mirror[a];
}
/* Correct parralel characters */
for(i = 0; i < ascii_obj.height; i++)
for(a = 0; a < strlen(ascii_obj.line[i]); a++)
for(b = 0; b < strlen(mirrorchr[0]); b++)
if(ascii_obj.line[i][a] == mirrorchr[0][b]){
ascii_obj.line[i][a] = mirrorchr[1][b];
break;
}
}
int main(int argc, char **argv){
struct vt_mode vtm;
struct passwd *pwd;
static sigset_t sig;
static struct sigaction sig_action;
static struct termios term;
struct utsname _uname;
struct nameEx{
char text[128];
char blank[128];
float x;
float y;
int max_x;
int max_y;
float direction_x;
float direction_y;
float speed;
int width;
int height;
} name[2];
double loadavg[3];
char glob_string[MAXPATH];
char file_name[MAXPATH];
/*char file_script[MAXPATH];*/
short special;
short forced_direction;
short file_set;
short mirror;
short random;
short busy;
short screen_too_small;
short lock;
short schedule_scroll_replace;
short default_scrolltext;
int obj_check[MAXLINES];
int ansi_check[MAXLINES];
int offset;
int name_count;
int ret;
int i, a, c;
int scroll_count;
int scroll_length;
unsigned long delay;
double scroll_delay;
double scroll_begin;
double scroll_end;
scroll_buffer = NULL;
ascii_obj.data = NULL;
for(i = 0; i < MAXLINES; i++){
ascii_obj.line[i] = NULL;
ascii_obj.blank[i] = NULL;
}
/* Set defaults */
name[UNAME].speed = .5;
name[INFO].speed = .1;
ascii_obj.speed = 1.0;
forced_direction = 0;
special = 0;
mirror = 1;
current_color = 8;
file_set = 0;
failed_logins = 0;
vfd = -1;
lock_delay = 1; /* First failed pass delay in seconds */
name_count = 1;
lock = 0;
random = 0;
delay = 120000; /* Microseconds */
scroll_delay = 5; /* Seconds */
default_scrolltext = 1;
bzero(file_name, MAXPATH);
bzero(ascii_obj.mirror, MAXLINES);
/* Mirrorable characters */
sprintf(mirrorchr[0], "/\\()<>{}[]bd`'");
sprintf(mirrorchr[1], "\\/)(><}{][db'`");
while( (i = getopt_long(argc, argv, "nsrld:a:o:e:i:Vh", long_options, NULL) ) != -1 )
switch (i) {
case 'n': mirror = 0; break;
case 's': name_count = 2; break;
case 'r': random = 1; break;
case 'l': lock = 1; break;
case 'd': delay = 1000 * atoi(optarg); break;
case 'a':
if(strlen(optarg) >= MAXPATH){
fprintf(stderr, "Path too long!\n");
exit(1);
}
file_set = 1;
strcpy(file_name, optarg);
break;
case 'o':
if(atof(optarg) < .001 || atof(optarg) > 1.00){
usage(argv[0]);
exit(1);
}else
ascii_obj.speed = atof(optarg);
break;
case 'e':
if(atof(optarg) < .001 || atof(optarg) > 1.00){
usage(argv[0]);
exit(1);
}else
name[UNAME].speed = atof(optarg);
break;
case 'i':
if(atof(optarg) < .001 || atof(optarg) > 1.00){
usage(argv[0]);
exit(1);
}else
name[INFO].speed = atof(optarg);
break;
case 'V': showver(); showcopyright(); exit(0);
case 'h': usage(argv[0]); exit(0);
default: usage(argv[0]); exit(0);
}
/* Init */
srand(time(NULL));
bzero(glob_string, MAXPATH);
sprintf(glob_string, "%s*", DEFAULT_ASCII_DIR);
if(default_scrolltext == 1){
scroll_buffer = calloc(37, 1); /* Max load */
getloadavg(loadavg, 3);
sprintf(scroll_buffer, "Load average: %.2f, %.2f, %.2f ",
loadavg[0],
loadavg[1],
loadavg[2]);
}
screen_too_small = 0;
/* Get kernel information */
if(uname(&_uname) == -1){
perror("uname");
severe_error(NULL);
}
sprintf(name[UNAME].text, "%s %s %s",
_uname.sysname,
_uname.nodename,
_uname.release);
bzero(name[INFO].text, 128);
memset(name[INFO].text, 32, SCROLL_BOX_WIDTH);
/* Init curses to get screen dimensions*/
initscr();
screen_width = COLS;
screen_height = LINES;
endwin();
/* check files and directories */
if(!file_set){ /* Skip directory and file checks if user set ascii */
ret = glob(glob_string, GLOB_ERR|GLOB_MARK, NULL, &list);
if(ret != 0){
fprintf(stderr, "\nCouldn't read \"%s\".\n", DEFAULT_ASCII_DIR);
bzero(glob_string, strlen(glob_string));
sprintf(glob_string, "%s/.tss/*", getenv("HOME"));
ret = glob(glob_string, GLOB_ERR|GLOB_MARK, NULL, &list);
fflush(stderr);
if(ret != 0){
sprintf(_error_message, "Couldn't read \"%s/.tss/\".\n", getenv("HOME"));
severe_error(_error_message);
}
}
for(i = 0; i < list.gl_pathc; i++){
if(strncmp(&list.gl_pathv[i][strlen(list.gl_pathv[i]) - 1], "/", 1) == 0){
sprintf(_error_message, "Directories are not allowed in \"%s\".\n",
DEFAULT_ASCII_DIR);
severe_error(_error_message);
}
}
if(list.gl_pathc == 0){
sprintf(_error_message, "\"%s\" contains no files.\n", DEFAULT_ASCII_DIR);
severe_error(_error_message);
}
if(random)
sprintf(file_name, "%s", list.gl_pathv[rand()%list.gl_pathc]);
else{
glob_string[strlen(glob_string) - 1] = 0;
sprintf(file_name, "%s%s", glob_string, DEFAULT_ASCII);
}
}
fd_ascii = fopen(file_name, "rb");
if(!fd_ascii){
sprintf(_error_message, "\"%s\" could not be read.\n", file_name);
severe_error(_error_message);
}
if(lof(fd_ascii) == 0){
sprintf(_error_message, "\"%s\" is empty.\n", file_name);
severe_error(_error_message);
}
if(lof(fd_ascii) > MAX_ASCII_SIZE){
sprintf(_error_message,
"\"%s\" is too large(max %db allowed)\n",
file_name,
MAX_ASCII_SIZE);
severe_error(_error_message);
}
/* Read files */
/* Read ascii object */
ascii_obj.data = calloc(lof(fd_ascii), 1);
fread(ascii_obj.data, 1, lof(fd_ascii), fd_ascii);
/* Check first two bytes for controls */
if(lof(fd_ascii) > 2){
if(ascii_obj.data[0] == 27){
switch(ascii_obj.data[1]){
case 'n':
mirror = 0;
special = 1;
break;
case 'l':
forced_direction = -1;
special = 1;
break;
case 'r':
forced_direction = 1;
special = 1;
break;
}
if(special){
strncpy(ascii_obj.data, &ascii_obj.data[2], lof(fd_ascii) - 2);
ascii_obj.data[lof(fd_ascii) - 2] = '\0';
}
}
}
fclose(fd_ascii);
fd_ascii = NULL;
/* Load object in to buffers */
ascii_obj.width = 0;
ascii_obj.height = 0;
offset = 0;
for(i = 0; i < strlen(ascii_obj.data); i++){
if(ascii_obj.data[i] == '\n'){
/*ascii_obj.line[ascii_obj.height] = calloc(offset + 1, 1);*/
ascii_obj.line[ascii_obj.height] = calloc(512, 1);
memcpy(ascii_obj.line[ascii_obj.height],
&ascii_obj.data[i - offset],
offset);
obj_check[ascii_obj.height++] = offset;
offset = 0;
}else{
offset++;
}
}
free(ascii_obj.data);
ascii_obj.data = NULL;
/* Check widest line */
for(i = 0; i < ascii_obj.height; i++){
ansi_check[i] = obj_check[i];
for(a = 0; a < strlen(ascii_obj.line[i]); a++)
if(ascii_obj.line[i][a] == 27)
obj_check[i] -= 2;
}
for(i = 0; i < ascii_obj.height; i++)
for(a = 0; a <= i; a++)
if(obj_check[a] > ascii_obj.width)
ascii_obj.width = obj_check[a];
for(i = 0; i < ascii_obj.height; i++)
for(a = 0; a <= i; a++)
if(ansi_check[a] > ascii_obj.width_real)
ascii_obj.width_real = ansi_check[a];
if(ascii_obj.width == 0)
ascii_obj.width = strlen(ascii_obj.line[0]);
/* Autopad spacing and allocate blanking area*/
for(i = 0; i < ascii_obj.height; i++){
offset = ascii_obj.width - obj_check[i];
if(offset > 0){
ascii_obj.line[i] = realloc(ascii_obj.line[i], ansi_check[i] + offset + 1);
memset(&ascii_obj.line[i][ansi_check[i]], 32, offset);
ascii_obj.line[i][ansi_check[i] + offset] = '\0';
}
/* fprintf(stderr, "Padding line %2d %2d bytes. (%2db in total)\n", i, offset, ansi_check[i] + offset); */
ascii_obj.blank[i] = calloc(ascii_obj.width + 1, 1);
memset(ascii_obj.blank[i], 32, ascii_obj.width);
ascii_obj.blank[i][ascii_obj.width] = '\0';
}
/* FIXME: Needs to be in same place as nonexistent resizing handler */
/* Check if terminal is big enough */
if(screen_width <= ascii_obj.width + 1)
screen_too_small = 1;
if(screen_height <= ascii_obj.height + 1)
screen_too_small = 1;
if(screen_width < strlen(name[UNAME].text))
screen_too_small = 1;
if(lock){
if(screen_width <= 75) /* Smaller than max usernamee + pwdbox */
screen_too_small = 1;
if(screen_height <= 4) /* Smaller than pwdbox height */
screen_too_small = 1;
}
if(screen_too_small){
sprintf(_error_message,
"This terminal is currently too small.\n");
severe_error(_error_message);
}
for(i = 0; i < name_count; i++){
/* Set blanking areas */
bzero(name[i].blank, 128);
memset(name[i].blank, 32, strlen(name[i].text));
/* Init objs */
name[i].width = strlen(name[i].text);
name[i].height = 1;
name[i].max_x = (screen_width - name[i].width);
name[i].max_y = (screen_height - name[i].height);
name[i].x = 1 + rand()%(name[i].max_x - 2);
name[i].y = 1 + rand()%(name[i].max_y - 2);
}
name[UNAME].direction_x = rand()%2?-name[UNAME].speed:name[UNAME].speed;
name[UNAME].direction_y = rand()%2?-name[UNAME].speed:name[UNAME].speed;
name[INFO].direction_x = rand()%2?-name[INFO].speed:name[INFO].speed;
name[INFO].direction_y = rand()%2?-name[INFO].speed:name[INFO].speed;
ascii_obj.max_x = (screen_width - ascii_obj.width);
ascii_obj.max_y = (screen_height - ascii_obj.height);
ascii_obj.x = 1 + rand()%(ascii_obj.max_x - 1);
ascii_obj.y = 1 + rand()%(ascii_obj.max_y - 1);
ascii_obj.direction_x = rand()%2?-ascii_obj.speed:ascii_obj.speed;
ascii_obj.direction_y = rand()%2?-ascii_obj.speed:ascii_obj.speed;
if(forced_direction != 0)
if(ascii_obj.direction_x != forced_direction)
perform_mirror();
/* Reinit curses */
initscr();
if(has_colors()){
start_color(); /* VT100 Color init */
init_pair(1, COLOR_BLACK, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_BLACK);
init_pair(3, COLOR_GREEN, COLOR_BLACK);
init_pair(4, COLOR_YELLOW, COLOR_BLACK);
init_pair(5, COLOR_BLUE, COLOR_BLACK);
init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
init_pair(7, COLOR_CYAN, COLOR_BLACK);
init_pair(8, COLOR_WHITE, COLOR_BLACK);
}
curs_set(0);
raw();
nodelay(stdscr, TRUE);
noecho();
attron(A_BOLD);
/* Init locking if enabled */
if(lock){
if(geteuid() != 0){ /* I'm not suid */
sprintf(_error_message, "I need to be SUID for VT locking.\n");
severe_error(_error_message);
}
pwd = my_getpwuid(getuid()); /* SUID! */
sprintf(username, "%s", pwd->pw_name);
sprintf(userpass, "%s", pwd->pw_passwd);
if(strlen(userpass) < 13){ /* Pass strings are always >= 13b */
sprintf(_error_message,
"The password for %s is invalid, "
"I can't lock the screen.\n", username);
severe_error(_error_message);
}
/* Drop SUID */
setuid(getuid());
setgid(getgid());
vfd = open("/dev/tty", O_RDWR);
if(vfd < 0){
sprintf(_error_message, "Could not open /dev/tty.\n");
severe_error(_error_message);
}
c = ioctl(vfd, VT_GETMODE, &vtm);
if(c < 0){
sprintf(_error_message, "I can't lock this TTY.\n");
severe_error(_error_message);
}
/* Init signal handling */
sigprocmask(SIG_SETMASK, NULL, &sig);
sigdelset(&sig, SIGUSR1);
sigdelset(&sig, SIGUSR2);
sigaddset(&sig, SIGTSTP);
sigaddset(&sig, SIGTTIN);
sigaddset(&sig, SIGTTOU);
sigaddset(&sig, SIGHUP);
sigaddset(&sig, SIGCHLD);
sigaddset(&sig, SIGQUIT);
sigaddset(&sig, SIGINT);
sigprocmask(SIG_SETMASK, &sig, &osig); /* Old set in osig */
/* Clear old set and define callbacks */
sigemptyset(&(sig_action.sa_mask));
sig_action.sa_flags = SA_RESTART;
sig_action.sa_handler = vt_release;
sigaction(SIGUSR1, &sig_action, NULL);
/* Ignore normal signals */
sig_action.sa_handler = signal_ignorer; /* Do nothing */
sigaction(SIGHUP, &sig_action, NULL);
sigaction(SIGQUIT, &sig_action, NULL);
sigaction(SIGINT, &sig_action, NULL);
sigaction(SIGTSTP, &sig_action, NULL);
ovtm = vtm; /* backup for restore */
vtm.mode = VT_PROCESS;
vtm.relsig = SIGUSR1; /* Handled by vt_release() */
vtm.acqsig = SIGUSR1;
vtm.frsig = SIGUSR1;
if(ioctl(vfd, VT_SETMODE, &vtm)){ /* Set it */
sprintf(_error_message, "VT_SETMODE failed: %s", strerror(errno));
severe_error(_error_message);
}
/* Init terminal */
tcgetattr(STDIN_FILENO, &oterm);
term = oterm;
term.c_iflag &= ~BRKINT;
term.c_iflag |= IGNBRK;
term.c_lflag &= ~ISIG;
/* No autoflush */
/* term.c_lflag |= (ECHO & ECHOCTL); */
/* term.c_lflag &= ~(ECHO | ECHOCTL); otherwise */
tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
/* Init scroller */
scroll_length = strlen(scroll_buffer);
scroll_count = 0;
scroll_begin = tickcount();
/* Main run */
busy = 1;
while(busy){
/* Scroll check */
scroll_end = tickcount() - scroll_begin;
if(scroll_end >= scroll_delay){
scroll_begin = tickcount();
schedule_scroll_replace = 1;
}
/* Blank */
for(i = 0; i < name_count; i++)
mvprintw(name[i].y, name[i].x, "%s", name[i].blank);
for(i = 0; i < ascii_obj.height; i++)
mvprintw((ascii_obj.y + i), ascii_obj.x, "%s", ascii_obj.blank[i]);
/* Update vars */
for(i = 0; i < name_count; i++){
name[i].x += name[i].direction_x;
name[i].y += name[i].direction_y;
if(name[i].x < 1 || name[i].x >= name[i].max_x)
name[i].direction_x = -name[i].direction_x;
if(name[i].y < 1 || name[i].y >= name[i].max_y)
name[i].direction_y = -name[i].direction_y;
}
ascii_obj.x += ascii_obj.direction_x;
ascii_obj.y += ascii_obj.direction_y;
if(ascii_obj.x < 1 || ascii_obj.x >= ascii_obj.max_x){
ascii_obj.direction_x = -ascii_obj.direction_x;
/* Mirror ascii */
if(mirror)
perform_mirror();
}
if(ascii_obj.y < 1 || ascii_obj.y >= ascii_obj.max_y)
ascii_obj.direction_y = -ascii_obj.direction_y;
/* Draw */
for(i = 0; i < ascii_obj.height; i++)
colormvprintw((ascii_obj.y + i), ascii_obj.x, ascii_obj.line[i]);
for(i = 0; i < name_count; i++)
mvprintw(name[i].y, name[i].x, "%s", name[i].text);
refresh();
/* Rotate scrolltext */
if(name_count == 2){
for(i = 0; i < SCROLL_BOX_WIDTH; i++)
name[INFO].text[i] = scroll_buffer[(i + scroll_count) % scroll_length];
name[INFO].text[0] = '[';
name[INFO].text[SCROLL_BOX_WIDTH-1] = ']';
if(++scroll_count > scroll_length){
if(schedule_scroll_replace){
/* Get new text */
if(default_scrolltext == 1){
getloadavg(loadavg, 3);
sprintf(scroll_buffer, "Load average: %.2f, %.2f, %.2f ",
loadavg[0],
loadavg[1],
loadavg[2]);
}
scroll_length = strlen(scroll_buffer);
scroll_count = 0;
schedule_scroll_replace = 0;
}
scroll_count = 1;
}
}
usleep(delay);
if(getch() != EOF){
if(lock == 1)
busy = lock_screen(screen_width, screen_height);
else
busy = 0;
}
}
/* Restore signals and terminal if locked */
if(lock){
sigprocmask(SIG_SETMASK, &osig, NULL); /* Restore old signals */
restore_terminal();
}
endwin();
cleanup();
if(failed_logins > 0)
printf("%d failed login attempts.\n", failed_logins);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1