/* utmp.c: routines to work with utmp and wtmp logs in their numerous
	incarnations.

Portions of this software are Copyright 1995 by Randall Atkinson and Dan
McDonald, All Rights Reserved. All Rights under this copyright are assigned
to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
License Agreement applies to this software.

	History:

	Modified at NRL for OPIE 2.1. Added HPUX PTY fixes.
	Written at NRL for OPIE 2.0.
*/

#include "opie_cfg.h"

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <string.h>
#include <time.h>

#include "opie.h"

#if DOUTMPX
#include <utmpx.h>
#endif	/* DOUTMPX */

#ifndef _PATH_UTMP
#ifdef UTMP_FILE
#define _PATH_UTMP	UTMP_FILE
#else /* UTMP_FILE */
#define _PATH_UTMP       "/etc/utmp"
#endif /* UTMP_FILE */
#endif

#ifndef _PATH_UTMPX
#define _PATH_UTMPX     "/etc/utmpx"
#endif	/* _PATH_UTMPX */

#ifndef _PATH_WTMP
#ifdef WTMP_FILE
#define _PATH_WTMP	WTMP_FILE
#else /* WTMP_FILE */
#define _PATH_WTMP      "/usr/adm/wtmp"
#endif /* WTMP_FILE */
#endif

#ifndef _PATH_WTMPX
#define _PATH_WTMPX     "/usr/adm/wtmpx"
#endif	/* _PATH_UTMPX */

#ifndef DOOURUTMP
#define DOOURUTMP 1
#endif /* DOOURUTMP */

void getutmpentry(line, utmp)
char *line;
struct UTMPX *utmp;
{
  struct UTMPX utmp2;
#if DOOURUTMP
  int i = 0, j = 0, f;
#else /* DOOURUTMP */
  struct UTMPX *utmp3;
#endif /* DOOURUTMP */
  char *line2;
#ifdef hpux
  char line3[9];
  strcpy(line3, "pty/\0\0\0\0\0");
#endif /* hpux */

  line2 = line;
  if (!strncmp(line, "/dev/", 5))
    line2 += 5;

#ifdef hpux
  strcpy(line3 + 4, line2);
#endif /* hpux */

#if DOOURUTMP
#if DOUTMPX
  if ((f = open(_PATH_UTMPX, O_RDONLY)) < 0) {
#else	/* DOUTMPX */
  if ((f = open(_PATH_UTMP, O_RDONLY)) < 0) {
#endif	/* DOUTMPX */
    perror("getutmp");
    return;
  }
  do {
    j = read(f, (char *) &utmp2, sizeof(struct UTMPX));
    if ((j == sizeof(struct UTMPX)) && (!strncmp(utmp2.ut_line, line,
		    sizeof(utmp2.ut_line)) || !strncmp(utmp2.ut_line, line2,
						  sizeof(utmp2.ut_line)))) {
      close(f);
      memcpy(utmp, &utmp2, sizeof(struct UTMPX));
#ifdef DEBUG
      fprintf(stderr, "getutmpentry: Found it!\n");
#endif	/* DEBUG */
      return;
    }
    i++;
  }
  while (j == sizeof(struct UTMPX));

  close(f);

#ifdef DEBUG
  fprintf(stderr, "getutmpentry: No matches\n");
#endif	/* DEBUG */
#else /* DOOURUTMP */
  memset(&utmp2, 0, sizeof(utmp2));

  strncpy(&(utmp2.ut_line), line, sizeof(utmp2.ut_line) - 1);
  utmp2.ut_line[sizeof(utmp2.ut_line) - 1] = 0;
#if DOUTMPX
  if (utmp3 = getutxline(utmp2))
#else /* DOUTMPX */
  if (utmp3 = getutline(utmp2))
#endif /* DOUTMPX */
    goto found;

  strncpy(&(utmp2.ut_line), line2, sizeof(utmp2.ut_line) - 1);
  utmp2.ut_line[sizeof(utmp2.ut_line) - 1] = 0;
#if DOUTMPX
  if (utmp3 = getutxline(utmp2))
#else /* DOUTMPX */
  if (utmp3 = getutline(utmp2))
#endif /* DOUTMPX */
    goto found;

#ifdef hpux
  strncpy(&(utmp2.ut_line), line3, sizeof(utmp2.ut_line) - 1);
  utmp2.ut_line[sizeof(utmp2.ut_line) - 1] = 0;
#if DOUTMPX
  if (utmp3 = getutxline(utmp2))
#else /* DOUTMPX */
  if (utmp3 = getutline(utmp2))
#endif /* DOUTMPX */
    goto found;
#endif /* hpux */

#ifdef DEBUG
  fprintf(stderr, "getutmpentry: No matches\n");
#endif	/* DEBUG */
  return;

 found:
  memcpy(utmp, utmp2, sizeof(utmp));
#ifdef DEBUG
  fprintf(stderr, "getutmpentry: Found it!\n");
#endif	/* DEBUG */
#endif /* DOOURUTMP */
}


#if DOUTMPX
void pututmpentry(line, utmpx)
char *line;
struct utmpx *utmpx;
#else	/* DOUTMPX */
void pututmpentry(line, utmp)
char *line;
struct utmp *utmp;
#endif	/* DOUTMPX */
{
  struct utmp utmp2, utmp3;
  int i, j, f;
  char *line2;

#if DOUTMPX
  struct utmpx utmp2x, utmp3x;
  struct utmp *utmp = (struct utmp *) malloc(sizeof(struct utmp));

  if (!utmp)
    return;
#endif	/* DOUTMPX */

  line2 = line;
  if (!strncmp(line, "/dev/", 5)) {
    line2 += 5;
    strncpy(UTMPX->ut_line, line2, sizeof(UTMPX->ut_line));
  }
#if DOUTMPX
  if ((f = open(_PATH_UTMPX, O_RDWR)) < 0) {
    perror("getutmp");
    goto l1;
  }
  gettimeofday(&utmpx->ut_tv);

  i = 0;

#if HAVETTYSLOT
  if ((i = ttyslot()) < 0)
    i = lseek(f, 0, 2) / sizeof(struct utmpx);

  lseek(f, (i * sizeof(struct utmpx)), 0);
  write(f, (char *) utmpx, sizeof(struct utmpx));

#else	/* HAVETTYSLOT */
  do {
    j = read(f, (char *) &utmp2x, sizeof(struct utmpx));
    if ((j == sizeof(struct utmpx)) && (!strncmp(utmp2x.ut_line, line,
		  sizeof(utmp2x.ut_line)) || !strncmp(utmp2x.ut_line, line2,
#ifdef hpux
		  sizeof(utmp2x.ut_line)) || !strncmp(utmp2x.ut_line, line3,
#endif /* hpux */
		  sizeof(utmp2x.ut_line)))
#ifdef LOGIN_PROCESS
	&& (utmp2x.ut_type == LOGIN_PROCESS)
#endif	/* LOGIN_PROCESS */
      ) {
#ifdef DEBUG
      fprintf(stderr, "Using utmpx slot %d.\n", i);
#endif	/* DEBUG */
      lseek(f, (i * sizeof(struct utmpx)), 0);
      write(f, (char *) utmpx, sizeof(struct utmpx));

      goto l1;
    }
    i++;
  }
  while (j == sizeof(struct utmpx));

#endif	/* HAVETTYSLOT */
  write(f, (char *) utmpx, sizeof(struct utmpx));

l1:
  close(f);

  strncpy(utmp->ut_name, utmpx->ut_name, sizeof(utmp->ut_name));
  strncpy(utmp->ut_id, utmpx->ut_id, sizeof(utmp->ut_id));
  strncpy(utmp->ut_line, utmpx->ut_line, sizeof(utmp->ut_line));
  utmp->ut_pid = utmpx->ut_pid;
  utmp->ut_type = utmpx->ut_type;
  memcpy(&utmp->ut_exit, &utmpx->ut_exit, sizeof(utmp->ut_exit));
#endif	/* DOUTMPX */

  if ((f = open(_PATH_UTMP, O_RDWR)) < 0) {
    perror("getutmp");
    goto l2;
  }
  time(&utmp->ut_time);

#if HAVETTYSLOT
#if !DOUTMPX
  if ((i = ttyslot()) < 0)
    i = lseek(f, 0, 2) / sizeof(struct utmp);
#endif

  lseek(f, (i * sizeof(struct utmp)), 0);
  write(f, (char *) utmp, sizeof(struct utmp));
#else	/* HAVETTYSLOT */
  i = 0;

  do {
    j = read(f, (char *) &utmp2, sizeof(struct utmp));
    if ((j == sizeof(struct utmp)) && (!strncmp(utmp2.ut_line, line,
		    sizeof(utmp2.ut_line)) || !strncmp(utmp2.ut_line, line2,
						     sizeof(utmp2.ut_line)))
#ifdef LOGIN_PROCESS
	&& (utmp2.ut_type == LOGIN_PROCESS)
#endif	/* LOGIN_PROCESS */
      ) {
#ifdef DEBUG
      fprintf(stderr, "Using utmp slot %d.\n", i);
#endif	/* DEBUG */
      lseek(f, (i * sizeof(struct utmp)), 0);
      write(f, (char *) utmp, sizeof(struct utmp));

      goto l2;
    }
    i++;
  }
  while (j == sizeof(struct utmp));

  write(f, (char *) utmp, sizeof(struct utmp));

#endif	/* HAVETTYSLOT */
l2:
  close(f);

#if DOUTMPX
  if ((f = open(_PATH_WTMPX, O_RDWR)) < 0) {
    perror("getutmp");
    goto l3;
  }
  if ((i = lseek(f, 0, 2)) < 0)
    goto l3;

  i -= (i % sizeof(struct utmpx)) + sizeof(struct utmpx);

  do {
    lseek(f, i, 0);
    j = read(f, (char *) &utmp3x, sizeof(struct utmpx));
    if ((j == sizeof(struct utmpx)) && !memcmp(&utmp3x, &utmp2x,
					       sizeof(struct utmpx))) {
      lseek(f, i, 0);
      write(f, (char *) utmpx, sizeof(struct utmpx));

      goto l3;
    }
    i -= sizeof(struct utmpx);
  }
  while (j == sizeof(struct utmpx));

  lseek(f, 0, 2);
  write(f, (char *) utmpx, sizeof(struct utmpx));

l3:
  close(f);
#endif	/* DOUTMPX */

  if ((f = open(_PATH_WTMP, O_RDWR)) < 0) {
    perror("getutmp");
    goto l4;
  }
  if ((i = lseek(f, 0, 2)) < 0)
    goto l4;

  i -= (i % sizeof(struct utmp)) + sizeof(struct utmp);

  do {
    lseek(f, i, 0);
    j = read(f, (char *) &utmp3, sizeof(struct utmp));
    if ((j == sizeof(struct utmp)) && !memcmp(&utmp3, &utmp2,
					      sizeof(struct utmp))) {
      lseek(f, i, 0);
      write(f, (char *) utmp, sizeof(struct utmp));

      goto l4;
    }
    i -= sizeof(struct utmp);
  }
  while (j == sizeof(struct utmp));

  lseek(f, 0, 2);
  write(f, (char *) utmp, sizeof(struct utmp));

l4:
  close(f);

#if DOUTMPX
  free(utmp);
#endif	/* DOUTMPX */

  return;
}
