/* $Id: sessions.c,v 1.1 2004/03/14 13:15:31 thivillon Exp $ */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h>
#include <string.h>
#include <utmp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <netdb.h>
#include <time.h>

#include "../config.h"

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif 

#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif

#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif

#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif

#include "ssltun.h"
#include "session.h"

int wtmpfd = -1;

extern void initsetproctitle(int argc, char **argv, char **envp);

#ifndef HAVE_SETPROCTITLE
extern void setproctitle(char *fmt, ...);
#endif


void purge_wtmp(char *wtmpname, int pid)
{

  ssltunnel_utmp_t mywtmp;
  int wtmpfd = -1;
  struct flock locks;

  if ((wtmpfd = open (wtmpname , O_RDWR|O_CREAT, 
          S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH )) < 0) {
      fprintf (stderr, "Can not open %s : %s\n",
               wtmpname, strerror(errno));
      return;
  }

  memset (&locks, 0, sizeof(locks));
  locks.l_type = F_WRLCK;
  locks.l_whence = SEEK_SET;
  if (fcntl ( wtmpfd, F_SETLKW ,  &locks ) < 0) {
    fprintf (stderr, "Unable to lock %s : %s\n",
             wtmpname, strerror(errno));
    goto catch;
  }

  if (lseek ( wtmpfd, 0, SEEK_END) == -1) {
    fprintf (stderr,  "Unable to seek %s : %s\n",
              wtmpname, strerror(errno));
    close (wtmpfd);
    goto catch ;
  }

  memset (&mywtmp, 0, sizeof (ssltunnel_utmp_t));
  sprintf(mywtmp.ut_line, "%d", pid);
  time ( &mywtmp.ut_time);
  
  if (write (wtmpfd, &mywtmp, sizeof (ssltunnel_utmp_t)) < 0 ) {
    fprintf(stderr, "Unable to write %s : %s\n",
             wtmpname, strerror(errno));
  }
  fsync( wtmpfd );

catch:

  locks.l_type = F_UNLCK;
  fcntl ( wtmpfd, F_SETLKW ,  &locks );
  close (wtmpfd);
  return ;

}


struct pppsession *read_sessions (char *filename)
{

  struct pppsession *firstsession = NULL;
  struct pppsession *next,*lastrec,*last,*new;
  int num;
  ssltunnel_utmp_t mywtmp;
  int wtmpfd;
 
  if ((wtmpfd = open (filename , O_RDONLY,
          S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH )) < 0) {
      fprintf (stderr, "Can not open %s : %s\n",
               filename, strerror(errno));
      return NULL;
  }
  
  while ((num = read( wtmpfd, &mywtmp, sizeof (mywtmp))) == sizeof (mywtmp)) {

     next = firstsession;
     last = NULL;
     lastrec = NULL;
     for (next = firstsession ; next != NULL ; next = next->next) {
       if (!strcmp(next->pid,mywtmp.ut_line)) lastrec = next;
       if (next->next == NULL) last = next;
     }

     /* Stop */
     if ((lastrec != NULL) && (lastrec->stop == 0)) lastrec->stop = mywtmp.ut_time;

     if (mywtmp.ut_name[0] != 0 || mywtmp.ut_host[0] != 0) {

       /* New session  */

       new = malloc ( sizeof (struct pppsession) );
       memset ( new, 0 , sizeof (struct pppsession) );
       new->pid = strdup (mywtmp.ut_line);
       new->username = strdup (mywtmp.ut_name);
       new->host = strdup (mywtmp.ut_host);
       new->start = mywtmp.ut_time;
      
       if (last != NULL) last->next = new;
       else firstsession = new;

     }  

  }

  close (wtmpfd);
  
  return firstsession;

}

void dump_sessions (int all, int resolve, struct pppsession *sessions) {

  struct pppsession *next;
  char bufftime_stop[80],bufftime_start[80];
  char *hostname;
  struct hostent *myhost;
  struct in_addr pin;
  time_t session_time;
  char *ptr;

  next = sessions;
  while (next != NULL) {
   
    if (all || !(next->stop)) {
       strftime(bufftime_start, 79, "%m/%d %R", localtime(&next->start));
       bufftime_stop[0]= '\0';
       if (next->stop) {
          ptr = bufftime_stop;
          ptr += strftime(bufftime_stop, 79, "%R", localtime(&next->stop));
          session_time =  difftime(next->stop, next->start);
          if (session_time >= 86400) {
             snprintf(ptr, 79 - (ptr - bufftime_stop), " (%d+%02d:%02d)", 
                 (int) session_time / 86400, (int) (session_time % 86400)/3600, 
                 (int) (session_time % 3600)/60);
          }
          else {
             snprintf(ptr, 79 - (ptr - bufftime_stop), " (%02d:%02d)", 
                 (int) session_time/3600,
                 (int) (session_time % 3600)/60);
          }
       }
       hostname =  next->host;
       if (resolve) {
         inet_aton(next->host , &pin);
         myhost = gethostbyaddr ( (char *) &pin,
                             sizeof ( struct in_addr),
                             PF_INET );
         if (myhost && myhost->h_name) hostname = myhost->h_name;
       } 
       else hostname =  next->host;
       printf ("%-15.15s %8s %-25.25s %12.12s %s\n",
              next->username,
              next->pid,
              hostname,
              bufftime_start,
              bufftime_stop);
    }
    next = next->next;
 }
 
 return;

}

void clean_sessions(char *filename) {

  struct pppsession *next,*curr;
  int mypid;

  next = read_sessions (filename);
  while (next != NULL) {
    if (!next->stop) {
       /* Crashed */
       mypid = atoi(next->pid);
       update_wtmp(filename, "", mypid, "");
    }
    curr = next;
    next = next->next;
    free(curr);
  }
  return;
}

void update_wtmp(char *filename, char *user, int pid, char *host)
{

  ssltunnel_utmp_t mywtmp;
  char buffpid[32];
  char *cn=NULL;
  char *ptr;
  int foundcn = 0;
  struct flock locks;

  if (wtmpfd == -1) {
    if ((wtmpfd = open (filename , O_RDWR|O_CREAT, 
          S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH )) < 0) {
      syslog (LOG_ERR, "Can not open %s : %s",
               filename, strerror(errno));
      return;
    }
  }

  memset (&locks, 0, sizeof(locks));
  locks.l_type = F_WRLCK;
  locks.l_whence = SEEK_SET;
  if (fcntl ( wtmpfd, F_SETLKW ,  &locks ) < 0) {
    syslog (LOG_ERR, "Unable to lock %s : %s",
             filename, strerror(errno));
    return ;
  }

  if (lseek ( wtmpfd, 0, SEEK_END) == -1) {
    syslog (LOG_ERR, "Unable to seek %s : %s",
             filename, strerror(errno));
    goto catch ;
  }

  memset (&mywtmp, 0, sizeof (ssltunnel_utmp_t));
  sprintf(buffpid, "%d", pid);
  strncpy ( mywtmp.ut_line, buffpid, UT_LINESIZE -1) ;
  strncpy ( mywtmp.ut_host, host, UT_HOSTSIZE -1) ;
 
  cn = strdup(user);
  for (ptr = strtok(cn,"/"); ptr; ptr = strtok(NULL,"/")) {
    if (!strncasecmp(ptr,"cn=",3)) {
      strncpy ( mywtmp.ut_name, ptr+3, UT_NAMESIZE -1) ;
      setproctitle("server for %s", mywtmp.ut_name);
      foundcn=1;
    }
  }
  if (!foundcn) {
      strncpy ( mywtmp.ut_name, user, UT_NAMESIZE -1) ;
      setproctitle("server for %s", mywtmp.ut_name);
  }
  free(cn);

  time ( & mywtmp.ut_time);
  
  if (write (wtmpfd, &mywtmp, sizeof (ssltunnel_utmp_t)) < 0 ) {
    syslog (LOG_ERR, "Unable to write %s : %s",
             filename, strerror(errno));
    goto catch ;
  }
  fsync( wtmpfd );

catch:

  /* We unlock the file but keep it open to come back 
     at end of connection after privilege drop */
  locks.l_type = F_UNLCK;
  fcntl ( wtmpfd, F_SETLKW ,  &locks );
  return ;

}


/*# vim:set expandtab:set syntax=c:*/



syntax highlighted by Code2HTML, v. 0.9.1