/*
 * Copyright (c) 2003-2012
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 */

/*
 * DACS simple authentication - no password is required, only a recognized
 * and valid username
 * The account file is maintained by dacspasswd and must be run-time
 * accessible by this CGI program.
 */

#ifndef lint
static const char copyright[] =
"Copyright (c) 2003-2012\n\
Distributed Systems Software.  All rights reserved.";
static const char revid[] =
  "$Id: local_simple_auth.c 2594 2012-10-19 17:28:49Z brachman $";
#endif

#include "dacs.h"

static const char *log_module_name = "local_simple_authenticate";

/*
 * Simple account-name authentication
 * Return 0 if authentication succeeds, -1 otherwise.
 */
int
local_simple_auth(char *username, char *given_passwd, char *aux)
{
  int st;
  char *digest_name;
  Passwd_digest_alg alg;
  Pw_entry *pw;
  Vfs_handle *h;

  if (username == NULL)
	return(-1);

  if (given_passwd == NULL || given_passwd[0] == '\0')
	log_msg((LOG_INFO_LEVEL, "No password provided"));
  else
	log_msg((LOG_INFO_LEVEL | LOG_SENSITIVE_FLAG,
			 "Password provided: \"%s\"", given_passwd));

  if ((h = vfs_open_item_type("simple")) == NULL) {
	log_msg((LOG_ALERT_LEVEL, "Can't open item type \"simple\""));
	return(-1);
  }

  digest_name = NULL;
  if (passwd_get_digest_algorithm(&digest_name, &alg) == -1) {
	log_msg((LOG_ERROR_LEVEL, "Can't get digest algorithm"));
	vfs_close(h);
	return(-1);
  }

  if ((pw = pw_read_entry(h, username)) == NULL) {
	log_msg((LOG_DEBUG_LEVEL, "Lookup of username '%s' failed", username));
	vfs_close(h);
	return(-1);
  }

  if (vfs_close(h) == -1)
	log_msg((LOG_ERROR_LEVEL, "vfs_close() failed"));

  st = -1;
  if (pw->state == PW_DISABLED)
	log_msg((LOG_NOTICE_LEVEL, "Account is disabled for username \"%s\"",
			 username));
  else if ((st = passwd_check_digest(alg, "", pw)) != 1)
	log_msg((LOG_NOTICE_LEVEL,
			 "Password comparison failed for username \"%s\"", username));
  else {
	log_msg((LOG_INFO_LEVEL, "Password comparison ok for username \"%s\"",
			 username));
	st = 0;
  }

  return(st);
}

#ifdef PROG
int
main(int argc, char **argv)
{
  int emitted_dtd;
  unsigned int ui;
  char *errmsg, *jurisdiction, *username, *password, *aux;
  Auth_reply_ok ok;
  Kwv *kwv;

  emitted_dtd = 0;
  errmsg = "Internal error";
  username = password = aux = jurisdiction = NULL;

  if (dacs_init(DACS_LOCAL_SERVICE, &argc, &argv, &kwv, &errmsg) == -1) {
	/* If we fail here, we may not have a DTD with which to reply... */
  fail:
	if (password != NULL)
	  strzap(password);
	if (aux != NULL)
	  strzap(aux);
	if (emitted_dtd) {
	  printf("%s\n", make_xml_auth_reply_failed(NULL, NULL));
	  emit_xml_trailer(stdout);
	}
	log_msg((LOG_ERROR_LEVEL, "Failed: reason=%s", errmsg));

	exit(1);
  }

  /* This must go after initialization. */
  emitted_dtd = emit_xml_header(stdout, "auth_reply");

  if (argc > 1) {
	errmsg = "Usage: unrecognized parameter";
	goto fail;
  }

  for (ui = 0; ui < kwv->nused; ui++) {
	if (streq(kwv->pairs[ui]->name, "USERNAME") && username == NULL)
	  username = kwv->pairs[ui]->val;
	else if (streq(kwv->pairs[ui]->name, "PASSWORD") && password == NULL)
	  password = kwv->pairs[ui]->val;
	else if (streq(kwv->pairs[ui]->name, "AUXILIARY") && aux == NULL)
	  aux = kwv->pairs[ui]->val;
	else if (streq(kwv->pairs[ui]->name, "DACS_JURISDICTION")
			 && jurisdiction == NULL)
	  jurisdiction = kwv->pairs[ui]->val;
	else if (streq(kwv->pairs[ui]->name, "DACS_VERSION"))
	  ;
	else
	  log_msg((LOG_DEBUG_LEVEL, "Parameter: '%s'", kwv->pairs[ui]->name));
  }

  /* Verify that we're truly responsible for DACS_JURISDICTION */
  if (dacs_verify_jurisdiction(jurisdiction) == -1) {
	log_msg((LOG_ERROR_LEVEL, "Missing or incorrect DACS_JURISDICTION"));
	goto fail;
  }

  if (local_simple_auth(username, password, aux) == -1) {
	errmsg = "Username/Password incorrect";
	goto fail;
  }

  if (password != NULL)
	strzap(password);
  if (aux != NULL)
	strzap(aux);

  ok.username = username;
  /* If this wasn't specified, dacs_authenticate will use the default. */
  ok.lifetime = kwv_lookup_value(kwv, "CREDENTIALS_LIFETIME_SECS");
  ok.roles_reply = NULL;

  printf("%s\n", make_xml_auth_reply_ok(&ok));

  emit_xml_trailer(stdout);
  exit(0);
}
#endif
