/* uulogin.c --- query the password of an anonymous UUCP user.

   Copyright (C) 1996, 1999 Ralph Schleicher  */

/* 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, 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; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
   Boston, MA 02111-1307, USA.  */


#define _GNU_SOURCE 1

#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>

#ifndef _PATH_UUCICO
#define _PATH_UUCICO "/usr/libexec/uucp/uucico"
#endif

/* Program name.  */
#define PROGRAM "uulogin"

/* Default user name.  */
#define USER "anonymous UUCP"

/* Password timeout in seconds.  */
#define TIMEOUT 60

/* Short program invocation name.  */
static char *program_name;

/* Argument vector for calling uucico(8).  Special argument "%u" is
   replaced by the user name.  */
static char *exec_arg[] =
  {
    _PATH_UUCICO, "-u", "%u", NULL,
  };

/* Terminal file descriptor.  */
static int term_desc = -1;

/* Original terminal mode.  */
static struct termios term_mode;

/* Forward declarations.  */
static void set_echo (int flag);
static void cleanup (int sig);


/* Program entry point.  */
int
main (int arg_count, char *arg_vec[])
{
  char *user, *pass, *end;
  int size, length;
  int result, i;

  if (arg_vec[0] == NULL)
    abort ();

  program_name = strrchr (arg_vec[0], '/');
  if (program_name == NULL)
    program_name = arg_vec[0];
  else
    ++program_name;
  if (*program_name == 0)
    program_name = PROGRAM;

  if (arg_count > 2)
    {
      fprintf (stderr, "Usage: %s [user]\n", program_name);

      exit (EXIT_FAILURE);
    }

  if (arg_count > 1)
    user = arg_vec[1];
  else
    user = USER;

  openlog (program_name, LOG_PID, LOG_AUTH);

  signal (SIGHUP, &cleanup);
  signal (SIGINT, &cleanup);
  signal (SIGQUIT, &cleanup);
  signal (SIGTERM, &cleanup);
  signal (SIGALRM, &cleanup);

  fprintf (stdout, "Please enter your email address as password.\n");
  fprintf (stdout, "Password: ");
  fflush (stdout);

  set_echo (0);
  alarm (TIMEOUT);
  pass = NULL;
  size = 0;

  result = getdelim (&pass, &size, '\n', stdin);

  set_echo (1);

  if (result < 1)
    exit (EXIT_FAILURE);

  length = strlen (pass);
  if (length < result)
    exit (EXIT_FAILURE);

  end = strchr (pass, '\n');
  if (end != NULL)
    *end = 0;
  else
    exit (EXIT_FAILURE);

  syslog (LOG_NOTICE, "User `%s' sent `%s' as password\n", user, pass);

  for (i = 1; exec_arg[i]; ++i)
    {
      if (strcmp (exec_arg[i], "%u") == 0)
	exec_arg[i] = user;
    }

  execv (exec_arg[0], exec_arg);

  syslog (LOG_ERR, "%s: %s\n", exec_arg[0], strerror (errno));

  exit (EXIT_FAILURE);
}


/* Turn character echoing on or off.  */
static void
set_echo (int flag)
{
  struct termios mode;
  int result;

  if (term_desc < 0)
    {
      term_desc = open ("/dev/tty", O_RDWR);
      if (term_desc < 0)
	{
	  fprintf (stderr, "%s:/dev/tty: %s\n",
		   program_name, strerror (errno));

	  exit (EXIT_FAILURE);
	}

      result = tcgetattr (term_desc, &term_mode);
      if (result < 0)
	{
	  fprintf (stderr, "%s:/dev/tty: %s\n",
		   program_name, strerror (errno));

	  exit (EXIT_FAILURE);
	}
    }

  memcpy (&mode, &term_mode, sizeof (struct termios));
  if (flag != 0)
    mode.c_lflag |= ECHO;
  else
    mode.c_lflag &= ~ ECHO;

  result = tcsetattr (term_desc, TCSAFLUSH, &mode);
  if (result < 0)
    {
      fprintf (stderr, "%s:/dev/tty: %s\n",
	       program_name, strerror (errno));

      exit (EXIT_FAILURE);
    }
}


/* Signal handler.  */
static void
cleanup (int sig)
{
  if (term_desc >= 0)
    tcsetattr (term_desc, TCSAFLUSH, &term_mode);

  syslog (LOG_NOTICE, ": Caught signal %d\n", sig);

  if (sig == SIGALRM)
    fprintf (stderr, "\nNow is the time for a timeout.\n");

  exit (EXIT_FAILURE);
}


/*
 * local variables:
 * compile-command: "gcc -g -Wall -W -o uulogin uulogin.c "
 * end:
 */
