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

/*****************************************************************************
 * COPYRIGHT AND PERMISSION NOTICE
 * 
 * Copyright (c) 2001-2003 The Queen in Right of Canada
 * 
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, and/or sell
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, provided that the above copyright notice(s) and this
 * permission notice appear in all copies of the Software and that both the
 * above copyright notice(s) and this permission notice appear in supporting
 * documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE 
 * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of a copyright holder shall not
 * be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization of the
 * copyright holder.
 ***************************************************************************/

/*
 * Generate a cookie and print to stdout
 * OR read a cookie from stdin and display it as credentials
 */

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

#include "dacs.h"
#include "dacs_api.h"

static MAYBE_UNUSED char *log_module_name = "dacscookie";

#ifndef PROG

static void
dacs_usage(void)
{

  fprintf(stderr, "Usage: dacscookie ");
  fprintf(stderr, "%s\n  [-decrypt|-encrypt] [-concise] [-i ident] [-user username] [-ip ipaddr] [-role role_str] [-for valid_for]\n", standard_command_line_usage);
  fprintf(stderr, "  [-expires date|+delta] [-ua str]\n");
  exit(1);
}

static Credentials *
decrypt_cookie(char *cookie_str)
{
  int is_dacs_cookie;
  Cookie *cookie;
  Credentials *cr;

  if ((cookie = cookie_parse(cookie_str, &is_dacs_cookie)) == NULL
	  || !is_dacs_cookie)
	return(NULL);

  if (!is_auth_cookie_name(cookie->name))
	return(NULL);

  if (cookie_to_credentials(cookie, NULL, &cr) == -1) {
	printf("Error while making credentials\n");
	exit(1);
  }

  return(cr);
}

int
dacscookie_main(int argc, char **argv, int do_init, void *main_out)
{
  int concise, decrypt, encrypt, i;
  char *expires, *ident, *username, *ip, *role_str;
  char *bp, *errmsg, *valid_for, *ua_str;
  Credentials *cr;

  errmsg = "Internal error";

  if (dacs_init(DACS_UTILITY, &argc, &argv, NULL, &errmsg) == -1)
	goto fail;

  decrypt = 0;
  encrypt = 0;
  concise = 0;
  username = NULL;
  role_str = NULL;
  ident = NULL;
  ip = NULL;
  expires = NULL;
  valid_for = AUTH_VALID_FOR_ACS;
  ua_str = NULL;

  for (i = 1; i < argc; i++) {
	if (streq(argv[i], "-decrypt")) {
	  decrypt = 1;
	  i++;
	  break;
	}

	encrypt = 1;
	if (streq(argv[i], "-create"))
	  continue;

	if (streq(argv[i], "-user")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing user parameter";
		goto fail;
	  }
	  username = argv[++i];
	}
	else if (streq(argv[i], "-ip")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing ip parameter";
		goto fail;
	  }
	  ip = argv[++i];
	}
	else if (streq(argv[i], "-i")) {
	  Simple_user sa;

	  if ((i + 1) == argc) {
		errmsg = "Usage: missing ident parameter";
		goto fail;
	  }
	  if (ident != NULL) {
		errmsg = "Usage: only one ident parameter allowed";
		goto fail;
	  }

	  ident = argv[++i];
	  if (parse_ident_string(ident, &sa) == -1) {
		errmsg = "Usage: error parsing ident parameter";
		goto fail;
	  }

	  /* Explicit flags override concise identity elements */
	  if (username == NULL)
		username = sa.user;
	  if (role_str == NULL)
		role_str = sa.groups;
	  if (expires == NULL)
		expires = sa.expires;
	  if (ip == NULL)
		ip = sa.ip_addr;
	}
	else if (streq(argv[i], "-role")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing role parameter";
		goto fail;
	  }
	  role_str = argv[++i];
	}
	else if (streq(argv[i], "-ua")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing UA string parameter";
		goto fail;
	  }
	  ua_str = argv[++i];
	}
	else if (streq(argv[i], "-for")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing valid_for parameter";
		goto fail;
	  }
	  if ((valid_for = is_valid_valid_for(argv[++i])) == NULL) {
		errmsg = "Usage: Invalid valid_for type";
		goto fail;
	  }
	}
	else if (streq(argv[i], "-expires")) {
	  if ((i + 1) == argc) {
		errmsg = "Usage: missing expires parameter";
		goto fail;
	  }
	  expires = argv[++i];
	}
	else {
	  errmsg = "Usage: unrecognized parameter";
	  goto fail;
	}
  }

  if (decrypt) {
	if (i < argc && streq(argv[i], "-concise")) {
	  concise = 1;
	  i++;
	}

	if (i != argc) {
	  errmsg = "Usage: Invalid argument follows -decrypt";
	  goto fail;
	}
  }

  if (encrypt && decrypt) {
	errmsg = "Usage: -decrypt is incompatible with identity arguments";
	goto fail;
  }

  if (decrypt) {
	char *buf;
	struct tm *tm;
	Ds *ds = ds_init(NULL);

	ds->delnl_flag = 1;
	if ((buf = ds_gets(ds, stdin)) == NULL) {
	  fprintf(stderr, "Read error\n");
	  return(-1);
	}
	if ((cr = decrypt_cookie(buf)) == NULL) {
	  fprintf(stderr, "Error decrypting cookie\n");
	  return(-1);
	}
	if (concise)
	  printf("%s\n", make_ident_from_credentials(cr));
	else {
	  printf("federation=\"%s\"\n", cr->federation);
	  printf("jurisdiction=\"%s\"\n", cr->home_jurisdiction);
	  printf("username=\"%s\"\n", cr->username);
	  printf("identity=\"%s\"\n", auth_identity_from_credentials(cr));
	  printf("concise_identity='%s'\n", make_ident_from_credentials(cr));
	  printf("ip_address=\"%s\"\n", cr->ip_address);
	  printf("roles=\"%s\"\n", cr->role_str);
	  tm = localtime(&cr->expires_secs);
	  printf("expires_secs=\"%lu\" (%s)\n",
			 (unsigned long) cr->expires_secs, make_local_date_string(tm, 1));
	  printf("auth_style=\"%s\"\n", auth_style_to_string(cr->auth_style));
	  printf("valid_for=\"%s\"\n", cr->valid_for);
	  printf("version=\"%s\"\n", cr->version);
	}

	return(0);
  }

  if (username == NULL) {
	errmsg = "Usage: username is required";
	goto fail;
  }

  if (!is_valid_auth_username(username)) {
	errmsg = "Usage: invalid username";
	goto fail;
  }

  if (expires != NULL && !is_signed_digit_string(expires)) {
	time_t et, now;

	now = time(NULL);
	/* Allow a date in the past... */
	if (utc_date_string_to_secs(&et, expires) == -1) {
	  errmsg = "Usage: Invalid expiry date";
	  goto fail;
	}
	expires = ds_xprintf("%lu", et - now);
  }

  if (role_str != NULL) {
	if (!is_valid_role_str(role_str)) {
	  errmsg = "Usage: invalid role string";
	  goto fail;
	}
  }

  /* XXX the user agent string for the ua_hash should be a command line arg */
  cr = make_credentials(NULL, NULL, username, ip, role_str, expires,
						AUTH_STYLE_GENERATED, valid_for, NULL, ua_str);

  if (verbose_level) {
	char *b;

	if (test_emit_format(EMIT_FORMAT_JSON)) {
	  fprintf(stderr, "JSON Credentials:\n");
	  make_json_credentials(cr, &b);
	}
	else {
	  fprintf(stderr, "XML Credentials:\n");
	  make_xml_credentials(cr, &b);
	}
	fprintf(stderr, "%s\n", b);
  }

  if (credentials_to_auth_cookies(cr, &bp) == -1)
	return(-1);

  printf("%s\n", bp);

  return(0);

 fail:
  fprintf(stderr, "%s\n", errmsg);
  dacs_usage();
  return(-1);
}

#else

int
main(int argc, char **argv)
{
  int rc;

  if ((rc = dacscookie_main(argc, argv, 1, NULL)) == 0)
	exit(0);

  exit(1);
}
#endif
