/*
 * Copyright (c) 2003-2014
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: conf.h 2712 2014-09-04 23:16:19Z brachman $
 */

/*****************************************************************************
 * 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.
 ***************************************************************************/

#ifndef _DACS_CONF_H_
#define _DACS_CONF_H_

#include "http.h"

typedef enum {
  CONF_CONTEXT_GLOBAL   = 0,		/* Directives outside of any clause. */
  CONF_CONTEXT_AUTH     = 1,		/* Within an Auth clause. */
  CONF_CONTEXT_ROLES    = 2,		/* Within a Roles clause. */
  CONF_CONTEXT_TRANSFER = 3			/* Within a Transfer clause. */
} Conf_context;

/*
 * Internal names for configuration directives.
 * Each directive needs a unique non-negative integer identifier,
 * although they need not be consecutive.
 * See conf.c for additional info, such as how these integer identifiers
 * are mapped into corresponding external string names.
 */
enum {
  CONF_PASSWORD_OPS_NEED_PASSWORD             =  0,
  CONF_JURISDICTION_NAME                      =  1,
  CONF_FEDERATION_DOMAIN                      =  2,
  CONF_PASSWORD_SALT_PREFIX                   =  3,
  CONF_AUTH_ERROR_HANDLER                     =  4,
  CONF_HTTP_PROG                              =  5,
  CONF_VERIFY_IP                              =  6,
  CONF_AUTH_SUCCESS_HANDLER                   =  7,
  CONF_AUTH_CREDENTIALS_DEFAULT_LIFETIME_SECS =  8,
  CONF_FEDERATION_NAME                        =  9,
  CONF_DTD_BASE_URL                           = 10,
  CONF_XSD_BASE_URL                           = 11,
  CONF_PASSWORD_DIGEST                        = 12,
  CONF_SSL_PROG                               = 13,
  CONF_SSL_PROG_CA_CRT                        = 14,
  CONF_SIGNOUT_HANDLER                        = 15,

  CONF_PROXY_EXEC_MAPPER_LOG_FILE             = 16,
  CONF_PROXY_EXEC_MAPPER_LOGGING              = 17,
  CONF_PROXY_EXEC_MAPPER_RULES_FILE           = 18,
  CONF_PROXY_EXEC_MAPPER_DEFAULT_ACTION       = 19,
  CONF_PROXY_EXEC_PROG_URI                    = 20,
  CONF_PROXY_EXEC_DOCUMENT_ROOT               = 21,

  CONF_TRACE_LEVEL                            = 22,
  CONF_VERBOSE_LEVEL                          = 23,
  CONF_ALLOW_HTTP_COOKIE                      = 24,
  CONF_AUTH_FAIL_DELAY_SECS                   = 25,
  CONF_TEMP_DIRECTORY                         = 26,
  CONF_PERMIT_CHAINING                        = 27,
  CONF_ACS_ERROR_HANDLER                      = 28,
  CONF_SECURE_MODE                            = 29,
  CONF_COOKIE_PATH                            = 30,
  CONF_ACS_POST_BUFFER_LIMIT                  = 31,
  CONF_ACS_AUTHENTICATED_ONLY                 = 32,
  CONF_ACS_ACCESS_TOKEN_ENABLE                = 33,
  CONF_ACS_ACCESS_TOKEN_LIFETIME_LIMIT        = 34,
  CONF_ACS_ACCESS_TOKEN_LIFETIME_SECS         = 35,
  CONF_NAME_COMPARE                           = 36,
  CONF_LOG_FILE                               = 37,
  CONF_LOG_FILTER                             = 38,
  CONF_LOG_LEVEL						      = 39,
  CONF_LOG_SENSITIVE                          = 40,
  CONF_LOGINGEN_FILE                          = 41,
  CONF_LOGINGEN_PROG                          = 42,
  CONF_SSL_PROG_CLIENT_CRT                    = 43,
  CONF_SSL_PROG_ARGS                          = 44,
  CONF_ADMIN_IDENTITY                         = 45,

  CONF_NOTICES_ACCEPT_HANDLER                 = 46,
  CONF_NOTICES_DECLINE_HANDLER                = 47,
  CONF_NOTICES_ACK_HANDLER				      = 48,
  CONF_NOTICES_SECURE_HANDLER			      = 49,
  CONF_NOTICES_WORKFLOW_LIFETIME_SECS	      = 50,
  CONF_NOTICES_NAT_NAME_PREFIX			      = 51,

  CONF_VFS                                    = 52,
  CONF_AUTH_AGENT_ALLOW_ADMIN_IDENTITY        = 53,
  CONF_AUTH_SUCCESS                           = 54,
  CONF_COOKIE_HTTPONLY                        = 55,
  CONF_AUTH_FAIL                              = 56,
  CONF_ACS_SUCCESS                            = 57,
  CONF_LOG_FORMAT                             = 58,
  CONF_COMPAT_MODE                            = 59,
  CONF_STATUS_LINE                            = 60,
  CONF_COOKIE_NO_DOMAIN                       = 61,
  CONF_CSS_PATH                               = 62,
  CONF_AUTH_TRANSFER_EXPORT                   = 63,
  CONF_AUTH_TRANSFER_TOKEN_LIFETIME_SECS      = 64,
  CONF_ACCEPT_ALIEN_CREDENTIALS               = 65,
  CONF_HTTP_AUTH                              = 66,
  CONF_HTTP_AUTH_ENABLE                       = 67,
  CONF_ACS_PRE_AUTH                           = 68,
  CONF_ACS_FAIL                               = 69,
  CONF_RLINK                                  = 70,
  CONF_PASSWORD_CONSTRAINTS                   = 71,
  CONF_ROLE_STRING_MAX_LENGTH                 = 72,
  CONF_VERIFY_UA                              = 73,
  CONF_UNAUTH_ROLES                           = 74,
  CONF_ACS_CREDENTIALS_LIMIT                  = 75,
  CONF_PAMD_HOST                              = 76,
  CONF_PAMD_PORT                              = 77,
  CONF_AUTH_SINGLE_COOKIE                     = 78,
  CONF_UPROXY_APPROVED                        = 79,
  CONF_ACS_EMIT_APPROVAL                      = 80,
  CONF_EVAL                                   = 81,
  CONF_AUTH_CREDENTIALS_ADMIN_LIFETIME_SECS   = 82,

  CONF_INFOCARD_DIGEST                        = 83,
  CONF_INFOCARD_USERNAME_SELECTOR             = 84,
  CONF_INFOCARD_MEX_URL                       = 85,
  CONF_INFOCARD_TOKEN_ISSUER                  = 86,
  CONF_INFOCARD_STS_URL                       = 87,
  CONF_INFOCARD_STS_AUTH_TYPE                 = 88,
  CONF_INFOCARD_IP_PRIVACY_URL                = 89,
  CONF_INFOCARD_STS_KEYFILE                   = 90,
  CONF_INFOCARD_STS_KEYFILE_PASSWORD          = 91,
  CONF_INFOCARD_STS_CERTFILE                  = 92,
  CONF_INFOCARD_STS_CACERTFILE                = 93,
  CONF_INFOCARD_CARD_LIFETIME_SECS            = 94,
  CONF_INFOCARD_CARD_DATETIME_EXPIRES         = 95,
  CONF_INFOCARD_CARD_IMAGE_BASE_URL           = 96,
  CONF_INFOCARD_CARD_OUTPUTDIR                = 97,
  CONF_INFOCARD_CARD_DEFS_URL                 = 98,
  CONF_INFOCARD_CARD_FILL_URL                 = 99,
  CONF_INFOCARD_CARD_VERSION                  = 100,
  CONF_INFOCARD_CARDID_BASE_URL               = 101,
  CONF_INFOCARD_CARDID_SUFFIX                 = 102,
  CONF_INFOCARD_TOKEN_LIFETIME_SECS           = 103,
  CONF_INFOCARD_AUDIENCE                      = 104,
  CONF_INFOCARD_STRONG_RP_IDENTITY            = 105,
  CONF_INFOCARD_ISSUER_INFO_ENTRY             = 106,
  CONF_INFOCARD_STS_PASSWORD_METHOD           = 107,
  CONF_INFOCARD_IP_PRIVACY_VERSION            = 108,
  CONF_INFOCARD_REQUIRE_APPLIES_TO            = 109,
  CONF_INFOCARD_AUDIENCE_RESTRICTION          = 110,
  CONF_INFOCARD_STS_RP_ENDPOINT               = 111,
  CONF_INFOCARD_TOKEN_MAX_LENGTH              = 112,
  CONF_INFOCARD_TOKEN_DRIFT_SECS              = 113,

  CONF_ACS_POST_EXCEPTION_MODE                = 114,
  CONF_ACS_TRACK_ACTIVITY                     = 115,
  CONF_ACS_INACTIVITY_LIMIT_SECS              = 116,

  CONF_REGISTER_USE_CODEWORD                  = 117,
  CONF_REGISTER_CODEWORD_TEMPLATE             = 118,
  CONF_REGISTER_EMAIL_TEMPLATE_FILE           = 119,
  CONF_REGISTER_SUCCESS_HANDLER               = 120,
  CONF_REGISTER_EMAIL_SUCCESS_HANDLER         = 121,
  CONF_REGISTER_ERROR_HANDLER                 = 122,
  CONF_REGISTER_CODEWORD_HANDLER              = 123,
  CONF_REGISTER_LINK_LIFETIME_SECS            = 124,
  CONF_REGISTER_ITEM_TYPE                     = 125,
  CONF_REGISTER_NICKNAMES                     = 126,
  CONF_REGISTER_USE_QUESTION                  = 127,
  CONF_TOKEN_REQUIRES_PIN                     = 128,
  CONF_TOKEN_HOTP_ACCEPT_WINDOW               = 129,
  CONF_COOKIE_NAME_TERMINATORS                = 130
};

enum {
  CONF_AUTH_URL                               = 200,
  CONF_AUTH_STYLE                             = 201,
  CONF_AUTH_CONTROL                           = 202,
  CONF_AUTH_FLAGS                             = 203,
  CONF_AUTH_PREDICATE                         = 204,
  CONF_AUTH_OPTION                            = 205,
  CONF_AUTH_OPTION_EVAL                       = 206,
  CONF_AUTH_URL_EVAL                          = 207,
  CONF_AUTH_INIT_EVAL                         = 208,
  CONF_AUTH_EXIT_EVAL                         = 209,
  CONF_AUTH_CREDENTIALS_LIFETIME_SECS         = 210,
  CONF_AUTH_LDAP_USERNAME_URL                 = 211,
  CONF_AUTH_LDAP_USERNAME_URL_EVAL            = 212,
  CONF_AUTH_LDAP_ADMIN_URL                    = 213,
  CONF_AUTH_LDAP_ADMIN_PASSWORD               = 214,
  CONF_AUTH_LDAP_SEARCH_ROOT_DN               = 215,
  CONF_AUTH_LDAP_SEARCH_FILTER                = 216,
  CONF_AUTH_LDAP_SEARCH_FILTER_EVAL           = 217,
  CONF_AUTH_LDAP_ROLES_SELECTOR_EVAL          = 218,
  CONF_AUTH_LDAP_USERNAME_EXPR_EVAL           = 219,
  CONF_AUTH_LDAP_BIND_METHOD                  = 220,
  CONF_AUTH_LDAP_TIMEOUT_SECS                 = 221,
  CONF_AUTH_CERT_DUMP_CLIENT                  = 222,
  CONF_AUTH_CERT_OPENSSL_PATH                 = 223,
  CONF_AUTH_CERT_CA_PATH                      = 224,
  CONF_AUTH_CERT_NAME_ATTR                    = 225,
  CONF_AUTH_EXPR                              = 226,
  CONF_AUTH_PASSWORD_AUDIT                    = 227,
#ifdef NOTDEF
  CONF_AUTH_VFS_ITEM_TYPE                     = 228,
#endif
  CONF_AUTH_AUTH_ID                           = 229,
  CONF_AUTH_EVAL                              = 230
};

enum {
  CONF_ROLES_URL                      = 300,
  CONF_ROLES_URL_EVAL                 = 301,
  CONF_ROLES_EXPR                     = 302,
  CONF_ROLES_INIT_EVAL                = 303,
  CONF_ROLES_EXIT_EVAL                = 304,
  CONF_ROLES_PREDICATE                = 305,
  CONF_ROLES_OPTION                   = 306,
  CONF_ROLES_OPTION_EVAL              = 307,
  CONF_ROLES_ROLES_ID                 = 308,
  CONF_ROLES_EVAL                     = 309
};

enum {
  CONF_TRANSFER_IMPORT_FROM               = 400,
  CONF_TRANSFER_REFEDERATE                = 401,
  CONF_TRANSFER_PREDICATE                 = 402,
  CONF_TRANSFER_CREDENTIALS_LIFETIME_SECS = 403,
  CONF_TRANSFER_IMPORT_ROLES              = 404,
  CONF_TRANSFER_IMPORT_URL                = 405,
  CONF_TRANSFER_SUCCESS_URL               = 406,
  CONF_TRANSFER_ERROR_URL                 = 407,
  CONF_TRANSFER_ROLES_EVAL                = 408,
  CONF_TRANSFER_EXIT_EVAL                 = 409,
  CONF_TRANSFER_TRANSFER_ID               = 410,
  CONF_TRANSFER_EVAL                      = 411
};

typedef struct Auth_conf Auth_conf;
typedef struct Roles_conf Roles_conf;
typedef struct Transfer_conf Transfer_conf;
typedef struct Jurisdiction_conf Jurisdiction_conf;

struct Auth_conf {
  char *id;
  Ds string;
  Auth_conf *next;
};

struct Roles_conf {
  char *id;
  Ds string;
  Roles_conf *next;
};

struct Transfer_conf {
  char *id;
  Ds string;
  Transfer_conf *next;
};

struct Jurisdiction_conf {
  char *uri_expr;
  char *uri;
  Uri *parsed_uri;
  Ds string;
  Auth_conf *auth_conf;
  Roles_conf *roles_conf;
  Transfer_conf *transfer_conf;
  Jurisdiction_conf *next;
};

typedef struct Configuration {
  Ds default_conf_string;
  Auth_conf *default_auth_conf;
  Roles_conf *default_roles_conf;
  Transfer_conf *default_transfer_conf;
  Jurisdiction_conf *jurisdiction_conf_head;
} Configuration;

typedef struct Site {
  Configuration *site_conf;
  Kwv *kwv_conf;
  Kwv *kwv_dacs;
  Kwv *kwv_site;
} Site;

typedef struct DACS_conf {
  char *uri_expr;
  char *uri;
  Uri *parsed_uri;
  char *site_conf;
  char *dacs_conf;
  Kwv_vartab *conf_vartab;
  Dsvec *auth_vartab;
  Dsvec *roles_vartab;
  Dsvec *transfer_vartab;
  Var_ns *conf_var_ns;
  Site *site;
  Kwv *default_kwv;
  Kwv *jurisdiction_kwv;
} DACS_conf;

extern DACS_conf *dacs_conf;

static inline MAYBE_UNUSED Kwv_pair *
conf_vartab_var(Kwv_vartab *vt, int id)
{
  int i;

  if (vt == NULL)
	return(NULL);

  for (i = 0; vt[i].id != KWV_VARTAB_END_ID; i++) {
	if (vt[i].id == id)
	  return(vt[i].pair);
  }

  return(NULL);
}

static inline MAYBE_UNUSED char *
conf_vartab_val(Kwv_vartab *vt, int id)
{
  Kwv_pair *pair;

  if ((pair = conf_vartab_var(vt, id)) == NULL)
	return(NULL);

  return(pair->val);
}

static inline MAYBE_UNUSED char *
conf_val(int id)
{

  if (dacs_conf == NULL)
	return(NULL);
  return(conf_vartab_val(dacs_conf->conf_vartab, id));
}

static inline MAYBE_UNUSED int
conf_vartab_val_eq(Kwv_vartab *vt, int id, char *val)
{
  char *v;

  if ((v = conf_vartab_val(vt, id)) != NULL && strcaseeq(v, val))
	return(1);
  return(0);
}

/*
 * Return 1 if directive ID is defined and has the value VAL,
 * case-insensitively; return 0 otherwise.
 */
static inline MAYBE_UNUSED int
conf_val_eq(int id, char *val)
{
  char *v;

  if ((v = conf_val(id)) != NULL && strcaseeq(v, val))
	return(1);
  return(0);
}

/*
 * Return 0 if directive ID is undefined (and not required), "no", or "off".
 * Return 1 if it is defined and "yes" or "on".
 * Return -1 if it is any other value or is undefined but required.
 */
static inline MAYBE_UNUSED int
conf_val_enabled(int id, Kwv_vartab_type type)
{
  char *v;

  if ((v = conf_val(id)) == NULL) {
	if (type == KWV_REQUIRED || type == KWV_REQUIRED1)
	  return(-1);
	return(0);
  }

  if (strcaseeq(v, "yes") || strcaseeq(v, "on"))
	return(1);
  if (strcaseeq(v, "no") || strcaseeq(v, "off"))
	return(0);
  return(-1);
}

/*
 * If directive ID is defined and is not the empty string, it is expected
 * to be an unsigned long integer and will be stored in UL.
 * Return 0 if ID is undefined, 1 if it is and is valid, and -1 otherwise.
 */
static inline MAYBE_UNUSED int
conf_val_ulong(int id, unsigned long *ul)
{
  char *endp, *v;

  if ((v = conf_val(id)) == NULL || *v == '\0')
	return(0);

  errno = 0;
  *ul = strtoul(v, &endp, 10);
  if (*endp != '\0' || errno == ERANGE)
	return(-1);

  return(1);
}

/*
 * If directive ID is defined and is not the empty string, it is expected
 * to be an unsigned integer and will be stored in UIP.
 * Return 0 if ID is undefined, 1 if it is and is valid, and -1 otherwise.
 */
static inline MAYBE_UNUSED int
conf_val_uint(int id, unsigned int *uip)
{
  int st;
  unsigned int ui;
  unsigned long ul;

  if ((st = conf_val_ulong(id, &ul)) != 1)
	return(st);

  ui = (unsigned int) ul;
  if (ui != ul)
	return(-1);

  *uip = ui;

  return(1);
}

static inline MAYBE_UNUSED Kwv_pair *
conf_var(int id)
{

  if (dacs_conf != NULL)
	return(conf_vartab_var(dacs_conf->conf_vartab, id));
  return(NULL);
}

static inline MAYBE_UNUSED Kwv_vartab *
conf_auth_vartab(unsigned int tabnum)
{
  Kwv_vartab *vt;

  if (dacs_conf == NULL || dacs_conf->auth_vartab == NULL)
	return(NULL);

  if (tabnum >= dsvec_len(dacs_conf->auth_vartab))
	return(NULL);

  if ((vt = dsvec_ptr(dacs_conf->auth_vartab, tabnum, Kwv_vartab *)) == NULL)
	return(NULL);

  return(vt);
}

static inline MAYBE_UNUSED Kwv_vartab *
conf_roles_vartab(unsigned int tabnum)
{
  Kwv_vartab *vt;

  if (dacs_conf == NULL || dacs_conf->roles_vartab == NULL)
	return(NULL);

  if (tabnum >= dsvec_len(dacs_conf->roles_vartab))
	return(NULL);

  if ((vt = dsvec_ptr(dacs_conf->roles_vartab, tabnum, Kwv_vartab *)) == NULL)
	return(NULL);

  return(vt);
}

static inline MAYBE_UNUSED Kwv_vartab *
conf_transfer_vartab(unsigned int tabnum)
{
  Kwv_vartab *vt;

  if (dacs_conf == NULL || dacs_conf->transfer_vartab == NULL)
	return(NULL);

  if (tabnum >= dsvec_len(dacs_conf->transfer_vartab))
	return(NULL);

  if ((vt = dsvec_ptr(dacs_conf->transfer_vartab, tabnum, Kwv_vartab *))
	  == NULL)
	return(NULL);

  return(vt);
}

static inline MAYBE_UNUSED char *
conf_auth_val(int tabnum, int id)
{
  Kwv_vartab *vt;

  if ((vt = conf_auth_vartab(tabnum)) == NULL)
	return(NULL);

  return(conf_vartab_val(vt, id));
}

static inline MAYBE_UNUSED char *
conf_roles_val(int tabnum, int id)
{
  Kwv_vartab *vt;

  if ((vt = conf_roles_vartab(tabnum)) == NULL)
	return(NULL);

  return(conf_vartab_val(vt, id));
}

static inline MAYBE_UNUSED char *
conf_transfer_val(int tabnum, int id)
{
  Kwv_vartab *vt;

  if ((vt = conf_transfer_vartab(tabnum)) == NULL)
	return(NULL);

  return(conf_vartab_val(vt, id));
}

static inline MAYBE_UNUSED int
dacs_secure_mode(void)
{

  if (conf_val_eq(CONF_SECURE_MODE, "no")
	  || conf_val_eq(CONF_SECURE_MODE, "off"))
	return(0);
  return(1);
}

#ifdef __cplusplus
extern "C" {
#endif

extern DACS_conf *conf_init(char *conf_file, char *site_conf_file,
							char *service_uri, Kwv_vartab *vartab);
extern DACS_conf *conf_init_by_jurisdiction(char *conf_file,
											char *site_conf_file,
											char *jurisdiction,
											Kwv_vartab *vartab);
extern int conf_set_directive(Kwv *kwv_conf, char *directive, char *value);
extern Kwv_vartab *conf_auth_vartab_by_id(char *auth_id);
extern Kwv_vartab *conf_roles_vartab_by_id(char *roles_id);
extern int conf_derive(Kwv *kwv, Kwv_vartab *vartab, void *derive_arg);
extern char *conf_map_directive(char *directive, Kwv *kwv, char ***args);
extern DACS_conf *new_dacs_conf(char *site_conf, char *dacs_conf,
								Jurisdiction_conf *j, Kwv_vartab *vartab,
								Var_ns *var_ns);
extern Dsvec *conf_sort_directives(Kwv_vartab *vartab);

#ifdef __cplusplus
}
#endif

#endif
