/*
 * Copyright (c) 2003-2013
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: local.h 2646 2013-02-27 20:10:40Z 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 _LOCAL_H_
#define _LOCAL_H_

/*
 * This is stuff that is included by all DACS source files.
 */

#include "dacs_config.h"

#if defined(DACS_OS_CYGWIN) || defined(DACS_OS_LINUX) || defined(DACS_OS_SOLARIS)
#include <crypt.h>
#endif

#ifdef DACS_OS_MACOSX
#include <Availability.h>
#endif

#include <sys/types.h>
#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>

/* Define this to get strptime() on some platforms */
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif

#ifdef DACS_OS_SOLARIS
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE		199309L
#endif

#ifndef __EXTENSIONS__
#define __EXTENSIONS__
#endif
#endif

#include <time.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

#include "dacs_version.h"
#include "misc.h"
#include "ds.h"
#include "str.h"
#include "range.h"
#include "kwv.h"
#include "net.h"
#include "http.h"
#include "cgiparse.h"
#include "mime.h"
#include "xml.h"
#include "html.h"
#include "vfs.h"
#include "mkargv.h"
#include "var.h"
#include "log.h"

#ifndef EAGAIN
#define EAGAIN  EWOULDBLOCK
#endif

#ifndef HAVE_IN_PORT_T
#ifdef HAVE_UINT16_T
/* See IEEE Std 1003.1, 2004 Edition. */
typedef uint16_t in_port_t;
#else
/* A guess. */
typedef unsigned short in_port_t;
#endif
#endif

/*
 * The name of a DACS cookie looks like:
 * DACS:<Federation Name>::<Jurisdiction>:<Username>
 * No colons are allowed in any of these name components.
 * <Federation Name> is the config variable FEDERATION_NAME.
 */

#define GROUPS_FILE_MODE			0600
#define JURISDICTION_NAME_SEP_CHAR	':'
#define GROUP_NAME_PREFIX_CHAR		'%'
#define GROUPS_PRIVATE_MODE_BIT		S_IXUSR
#define GROUP_FILE_SUFFIX			".grp"
#define DTD_FILE_SUFFIX				".dtd"
#define XSD_FILE_SUFFIX				".xsd"
#define XMLNS_PREFIX				"http://fedroot.com/dacs"
#define XMLNS_SEP_CHAR				'|'
#define XMLNS_XSI					"http://www.w3.org/2001/XMLSchema-instance"

#ifndef LOG_FILE_MODE
#define LOG_FILE_MODE				0660
#endif

/* Return a pointer to space for one OBJ. */
#define ALLOC(OBJ)			((OBJ *) malloc(sizeof(OBJ)))

/* Return a pointer to space for a vector of N objects, each an OBJ. */
#define ALLOC_N(OBJ, N)		((OBJ *) malloc(sizeof(OBJ) * (N)))

/*
 * The string that is used to separate multiple cookies in a Set-Cookie
 * response header.  The Netscape spec says it's a semi-colon but RFC 2109
 * says it's a comma (4.2.2 & 10.1.1).
 * We follow the Netscape spec.
 */
#define COOKIE_SEP_STR	"; "

enum {
#ifdef NGROUPS
  MAX_UNIX_GROUPS = NNGROUPS
#else
  MAX_UNIX_GROUPS = 20
#endif
};

#ifndef DEFAULT_EDITOR
#define DEFAULT_EDITOR		"/usr/bin/vi"
#endif

/*
 * Default location for temporary files and lock files.
 * If there's no initial slash, it will be relative to DACS_HOME.
 * Note that this directory may be used by "make test", so it needs to
 * exist (or be created) before DACS is installed.
 */
#ifndef DEFAULT_TEMP_DIRECTORY
#define DEFAULT_TEMP_DIRECTORY			"/tmp"
#endif

/*
 * Sometimes an IP address is needed for the current jurisdiction but
 * we don't really care what it is.
 */
#ifndef DEFAULT_IP_ADDR
#define DEFAULT_IP_ADDR				"127.0.0.1"
#endif

/* Number of random bytes used for suffixes by create_temp_filename() */
#define TEMP_FILENAME_RANDOM_LENGTH		6
/* Character prepended to the filename suffix by create_temp_filename() */
#define TEMP_FILENAME_SEP_CHAR			'.'

enum {
  /* For testing only, you can make the cookie persistent. */
  DACS_USE_PERSISTENT_COOKIE = 0,
  DACS_DEFAULT_SSL_PORT      = 443
};

enum {
  INIT_CGI_KWV = 10
};

typedef enum {
  DACS_USER_NAME			= 0,
  DACS_GROUP_NAME 			= 1,
  DACS_JURISDICTION_NAME	= 2,
  DACS_FEDERATION_NAME      = 3,
  DACS_IP_NAME				= 4,
  DACS_UNKNOWN_NAME			= 5
} DACS_name_type;

typedef enum {
  DACS_NAME_CMP_CASE    = 0,
  DACS_NAME_CMP_NOCASE  = 1,
  DACS_NAME_CMP_CONFIG  = 2,
  DACS_NAME_CMP_STRING  = 3,
  DACS_NAME_CMP_UNKNOWN = 4,
  DACS_NAME_CMP_DEFAULT = DACS_NAME_CMP_CASE
} DACS_name_cmp;

typedef struct DACS_name {
  char *federation;
  char *jurisdiction;
  char *username;
  DACS_name_type type;
} DACS_name;

typedef struct Group_name {
  char *jurisdiction;
  char *username;
} Group_name;

/*
 * All app types examine their command line arguments, but some accept
 * general DACS flags (dacsoptions) first, followed by application-specific
 * flags.  Also, configuration of logging depends on how the program is run.
 * DACS configuration file processing may be required, optional, or not
 * performed, depending on the app type.
 */
typedef enum {
  DACS_WEB_SERVICE        = 0,   /* Invoked by a user through a web server */
  DACS_LOCAL_SERVICE      = 1,   /* Invoked by DACS through a web server */
  DACS_UTILITY            = 2,   /* Invoked by an administrator as a command */
  DACS_UTILITY_OPT        = 3,	 /* Like DACS_UTILITY, but config is optional */
  DACS_UTILITY_PROC       = 4,	 /* A subprocess, config is optional */
  DACS_ACS                = 5,   /* DACS ACS, invoked by a web server */
  DACS_STANDALONE         = 6,	 /* Like DACS_UTILITY, except no config */
  DACS_STANDALONE_NOARGS  = 7,	 /* Like DACS_STANDALONE, except no args */
  DACS_STANDALONE_SERVICE = 8,	 /* Like DACS_WEB_SERVICE, except no config */
  DACS_SERVER             = 9,   /* A server process; e.g., started by inetd */
  DACS_UNKNOWN_APP        = 99   /* Undefined state */
} DACS_app_type;

typedef struct Mime_desc {
  Http_method method;
  char *content_type;
  Mime_content_type *ct;
  Mime_encoding encoding;
  unsigned long content_length;
  unsigned long length;
  Ds *body;
} Mime_desc;

typedef struct DACS_app_args {
  int argc;
  char **argv;
  Kwv *kwv;
  char *errmsg;
  Http_method method;
  Mime_desc *mime_desc;
} DACS_app_args;

/* This is the level in effect before the configuration file is read. */
#ifndef LOG_STARTUP_LEVEL
#define LOG_STARTUP_LEVEL		LOG_WARN_LEVEL
#endif

/*
 * This is used before configuration is complete or if no LOG_FORMAT
 * directive is provided.
 */
#ifndef LOG_FORMAT_DEFAULT_WEB
#define LOG_FORMAT_DEFAULT_WEB	"[%t] [%l] [%p,%c,%F] [%sp:\"%sm\",%sf:%sl]"
#endif

#ifndef LOG_FORMAT_DEFAULT_CMD
#define LOG_FORMAT_DEFAULT_CMD	"%a[%l]:"
#endif

#ifndef LOG_DEFAULT_LEVEL
#define LOG_DEFAULT_LEVEL		LOG_NOTICE_LEVEL
#endif

typedef enum {
  /* XXX Eventually assign a code number to each type of error */
  DACS_ERROR_INTERNAL = 999
} DACS_error_code;

typedef enum {
  EMIT_FORMAT_UNKNOWN   = 0,
  EMIT_FORMAT_HTML      = 1,
  EMIT_FORMAT_PLAIN     = 2,
  EMIT_FORMAT_XML       = 3,
  EMIT_FORMAT_XMLDTD    = 4,
  EMIT_FORMAT_XMLSIMPLE = 5,
  EMIT_FORMAT_XMLSCHEMA = 6,
  EMIT_FORMAT_PHP       = 7,
  EMIT_FORMAT_FILE      = 8,	/* Output is returned as a MIME type. */
  EMIT_FORMAT_TEXT      = 9,	/* Output is to tty. */
  EMIT_FORMAT_JSON      = 10
} Emit_format;

#ifndef EMIT_FORMAT_DEFAULT
#define EMIT_FORMAT_DEFAULT EMIT_FORMAT_HTML
#endif

/*
 * After installation, this is where the DACS style sheet files can be found
 * relative to the /usr/local/dacs/www directory.
 * That is, we assume that Apache is configured with:
 *   Alias /css "/usr/local/dacs/www/css/"
 * The style files in that directory are used by default by HTML produced by
 * DACS web services.
 */
#define CSS_DIR		"/css"

/* XXX This is actually part HTTP and part HTML */
typedef struct Html_header_conf {
  int no_cache;
  int html;
  int html_body;
  char *css;
  char *bgcolor;
  char *title;
  char *redirect_url;
  char *status_code;
  char *status_reason;
  Dsvec *headers;
} Html_header_conf;

typedef struct Common_status {
  char *context;
  char *code;
  char *message;
} Common_status;

extern Parse_attr_tab common_status_attr_tab[];

/*
 * If DEFAULT_NAMESPACE is defined, then it is the namespace to use
 * in variable references where the namespace is omitted.
 * It must be syntactically valid and cannot be a reserved namespace.
 *
 * If you prefer not having a default, do not define this symbol and variables
 * like ${foo} will raise an error condition.
 */
#ifndef DEFAULT_NAMESPACE
#define DEFAULT_NAMESPACE	"Temp"
#endif

typedef struct Directory_list {
  Dsvec *dsv;
  int exclude_dot_files;
} Directory_list;

/* This is a list of all predefined/reserved item types. */
#define ITEM_TYPE_ACLS							"acls"
#define ITEM_TYPE_AUTH_AGENT_FEDERATIONS		"auth_agent_federations"
/* The following is a special case... */
#define ITEM_TYPE_AUTH_AGENT_FEDERATION_PREFIX	"auth_agent_federation_"
#define ITEM_TYPE_AUTH_AGENT_LOCAL				"auth_agent_local"
#define ITEM_TYPE_AUTH_GRID						"auth_grid"
#define ITEM_TYPE_AUTH_GRID_KEYS				"auth_grid_keys"
#define ITEM_TYPE_AUTH_STATUS					"auth_status"
#define ITEM_TYPE_AUTH_TOKEN					"auth_token"
#define ITEM_TYPE_AUTH_HOTP_TOKEN				"auth_hotp_token"
#define ITEM_TYPE_AUTH_TOTP_TOKEN				"auth_totp_token"
#define ITEM_TYPE_AUTH_TOKEN_KEYS				"auth_token_keys"
#define ITEM_TYPE_AUTH_TRANSFER					"auth_transfer"
#define ITEM_TYPE_CERTNAMEMAP					"certnamemap"
#define ITEM_TYPE_DACS_ACLS						"dacs_acls"
#define ITEM_TYPE_DELTAS						"deltas"
#define ITEM_TYPE_DTDS							"dtds"
#define ITEM_TYPE_FEDERATION_KEYS				"federation_keys"
#define ITEM_TYPE_GROUPS						"groups"
#define ITEM_TYPE_INFOCARDS						"infocards"
#define ITEM_TYPE_JURISDICTION_KEYS				"jurisdiction_keys"
#define ITEM_TYPE_LOCAL_PAM_AUTHENTICATE		"locate_pam_authenticate"
#define ITEM_TYPE_NOTICES						"notices"
#define ITEM_TYPE_PASSWDS						"passwds"
#define ITEM_TYPE_REVOCATIONS					"revocations"
#define ITEM_TYPE_RLINKS						"rlinks"
#define ITEM_TYPE_ROLES							"roles"
#define ITEM_TYPE_SIMPLE						"simple"
#define ITEM_TYPE_TOKENS						"tokens"
#define ITEM_TYPE_USER_INFO						"user_info"

#define ITEM_TYPE_NAMES	ITEM_TYPE_ACLS, ITEM_TYPE_AUTH_AGENT_FEDERATIONS,\
	ITEM_TYPE_AUTH_AGENT_LOCAL, ITEM_TYPE_AUTH_GRID, ITEM_TYPE_AUTH_GRID_KEYS,\
	ITEM_TYPE_AUTH_STATUS, ITEM_TYPE_AUTH_TOKEN, \
	ITEM_TYPE_AUTH_HOTP_TOKEN, ITEM_TYPE_AUTH_TOTP_TOKEN, \
	ITEM_TYPE_AUTH_TOKEN_KEYS,											\
	ITEM_TYPE_AUTH_TRANSFER, ITEM_TYPE_CERTNAMEMAP, ITEM_TYPE_DACS_ACLS,\
	ITEM_TYPE_DELTAS, ITEM_TYPE_DTDS, ITEM_TYPE_FEDERATION_KEYS,\
	ITEM_TYPE_GROUPS, ITEM_TYPE_INFOCARDS, ITEM_TYPE_JURISDICTION_KEYS,\
	ITEM_TYPE_LOCAL_PAM_AUTHENTICATE, ITEM_TYPE_NOTICES, ITEM_TYPE_PASSWDS,\
	ITEM_TYPE_REVOCATIONS, ITEM_TYPE_RLINKS, ITEM_TYPE_ROLES,\
	ITEM_TYPE_SIMPLE, ITEM_TYPE_TOKENS, ITEM_TYPE_USER_INFO

#define PROC_LOCK_GRID			"dacsgrid.lock"
#define PROC_LOCK_INFOCARD		"dacsinfocard.lock"
#define PROC_LOCK_PASSWD		"dacspasswd.lock"
#define PROC_LOCK_REGISTER		"dacsregister.lock"
#define PROC_LOCK_TOKEN			"dacstoken.lock"

typedef struct Proc_lock {
  char *lock_file;
  int fd;
  int type;
} Proc_lock;

typedef enum {
  SEGMENT_CREAT   = 0x01,
  SEGMENT_CREATE  = 0x01,
  SEGMENT_TRUNC   = 0x02,
  SEGMENT_RDONLY  = 0x04,
  SEGMENT_WRONLY  = 0x08,
  SEGMENT_RDWR    = 0x10
} Segment_mode;

typedef enum {
  SEGMENT_EXISTS  = 0,		/* Opened segment was not created. */
  SEGMENT_NEW     = 1,		/* Opened segment was created. */
  SEGMENT_UNKNOWN = -1
} Segment_status;

/* A shared memory segment descriptor. */
typedef struct Segment {
  Segment_status status;
  int fd_shm;
  int fd_lock;
  char *path;				/* Unique pathname for the segment. */
  char *name;				/* Name of segment (Linux semantics) */
  char *lock_path;			/* Pathname for corresponding lock file. */
  size_t length;			/* Actual segment length, in bytes. */
  size_t req_length;		/* Requested segment length, in bytes. */
  mode_t mode;				/* Shared object file mode. */
  void *ptr;				/* Pointer to LENGTH bytes of shared memory. */
  char *errmsg;				/* If non-NULL, a descriptive error message. */
} Segment;

#ifndef HAVE_DLFUNC
typedef void *dlfunc_t;
#endif

#ifdef __cplusplus
extern "C" {
#endif

extern Common_status *init_common_status(Common_status *status, char *context,
										 char *code, char *message);
#ifdef __cplusplus
}
#endif

static MAYBE_UNUSED char *
non_null(char *s)
{

  return((s != NULL) ? s : "");
}

static MAYBE_UNUSED char *
pluralize(char *word, char *ext, int count)
{

  /* XXX only correct sometimes... */
  return(ds_xprintf("%s%s", word, (count == 1) ? "" : ext));
}

static MAYBE_UNUSED int
dacs_is_https_request(void)
{
  char *p;

  return((p = getenv("HTTPS")) != NULL && strcaseeq(p, "on"));
}

static inline MAYBE_UNUSED void *
safe_inline_malloc(size_t size, const char *log_module_name)
{
  void *p;

  if ((p = malloc(size)) == NULL) {
	log_msg((LOG_ALERT_LEVEL, "malloc failed, exiting"));
	exit(1);
  }

  return(p);
}
#define safe_malloc(SIZE)		safe_inline_malloc(SIZE, log_module_name)

static inline MAYBE_UNUSED void
safe_free(void *ptr)
{
  free(ptr);
}

static inline MAYBE_UNUSED void *
safe_inline_calloc(size_t number, size_t size, const char *log_module_name)
{
  void *p;

  if ((p = calloc(number, size)) == NULL) {
	log_msg((LOG_ALERT_LEVEL, "calloc failed, exiting"));
	exit(1);
  }

  return(p);
}
#define safe_calloc(NUMBER, SIZE) \
		safe_inline_calloc(NUMBER, SIZE, log_module_name)

static inline MAYBE_UNUSED void *
safe_inline_realloc(void *ptr, size_t size, const char *log_module_name)
{
  void *p;

  if ((p = realloc(ptr, size)) == NULL) {
	log_msg((LOG_ALERT_LEVEL, "realloc failed, exiting"));
	exit(1);
  }
  return(p);
}
#define safe_realloc(PTR, SIZE)	\
	safe_inline_realloc(PTR, SIZE, log_module_name)

static inline MAYBE_UNUSED char *
safe_inline_strdup(const char *str, const char *log_module_name)
{
  size_t len;
  void *p;

  len = strlen(str) + 1;
  p = safe_malloc(len);
  memcpy(p, str, len);
  return((char *) p);
}
#define safe_strdup(STR)	safe_inline_strdup(STR, log_module_name)

#undef malloc
#undef calloc
#undef free
#undef realloc
#undef reallocf
#undef strdup

#define malloc(X)		safe_malloc(X)
#define calloc(X, Y)	safe_calloc(X, Y)
#define free(X)			safe_free(X)
#define realloc(X, Y)	safe_realloc(X, Y)
#define reallocf(X, Y)	safe_realloc(X, Y)
#define strdup(X)		safe_strdup(X)

#define dacs_fatal(B)	\
  { \
	log_set_args(log_module_name, __FILE__, __func__, __LINE__, 0, B); \
	dacs_abort(NULL); \
	/*NOTREACHED*/ \
  }

#include "conf.h"

extern DACS_app_type dacs_app_type; 
extern int should_use_argv;
extern char *dacs_service_uri;
extern char *dacs_effective_service_uri;
extern char *dacs_conf_path_spec;
extern char *dacs_site_conf_path_spec;
extern char *dacs_logfile_path;
extern Kwv *dacs_kwv_args;

extern unsigned long trace_level;
extern unsigned long verbose_level;
extern int quiet_flag;
extern Kwv *kwv_dacsoptions;
extern char *standard_command_line_usage;
extern int dacs_init_allow_dups_default;
extern Emit_format emit_format_default;
extern char *emit_html_attrname_color;
extern int emit_content_type_header;
extern int dacs_no_conf_flag;
extern int dacs_saw_command_line_log_level;
extern int dacs_saw_command_line_format;
extern char *dacs_compatibility_mode;
extern char *dacs_version_number;
extern char *dacs_version_release;
extern int dacs_enable_rule_patterns;
extern int ssl_verify; extern int use_ssl;
extern int forward_proxy_jurisdiction;
extern char *dacs_log_format_default;
extern char *dacs_log_format;

#ifdef __cplusplus
extern "C" {
#endif

#ifndef INADDR_NONE
/* SunOS 5.8 doesn't have inet_aton() and doesn't define INADDR_NONE... */
/* SunOS 5.10 has inet_aton() (libresolv) but doesn't define INADDR_NONE... */
#define INADDR_NONE		((in_addr_t) (-1))
#endif

#ifdef DACS_OS_MACOSX
/*
  #define _ANSI_SOURCE
  #define _POSIX_C_SOURCE     199309L
  #define _BSD_SOURCE
*/
#endif

#ifndef HAVE_CLOCK_GETTIME
/*
 * MAC OS X does not have clock_gettime() (IEEE Std 1003.1b-1993)
 */

typedef enum {
  CLOCK_REALTIME           = 0,	
  CLOCK_MONOTONIC          = 1,	
  CLOCK_PROCESS_CPUTIME_ID = 2,
  CLOCK_THREAD_CPUTIME_ID  = 3
} clockid_t;

extern int clock_gettime(clockid_t clock_id, struct timespec *tp);
#endif

#ifndef HAVE_INET_ATON
extern int inet_aton(const char *cp, struct in_addr *addr);
#endif

#ifndef HAVE_LOCKF
enum {
  F_ULOCK = 1,
  F_LOCK  = 2,
  F_TLOCK = 3,
  F_TEST  = 4
};

extern int lockf(int fd, int func, off_t size);
#endif

extern void dacs_atexit(void (*func)(void *arg), void *arg);

extern int proc_lock_set(Proc_lock *lock);
extern Proc_lock *proc_lock_create(char *name);
extern int proc_lock_unset(Proc_lock *lock);
extern int proc_lock_delete(Proc_lock *lock);

extern char *hexdump(unsigned char *buf, unsigned int len);
extern void text_html(FILE *fp, char *buf);
extern void env_html(FILE *fp);
extern void hex_html(FILE *fp, unsigned char *buf, unsigned int len,
					 unsigned int ncolumns);
extern char *html_encode(char *str);

extern char *create_temp_filename(char *suffix);
extern FILE *create_temp_file(char *filename);
extern int set_lock(char *lockfile, unsigned int maxage_secs,
					unsigned int *remaining_secs);
extern int check_lock(char *lockfile, unsigned int maxage_secs,
					  unsigned int *remaining_secs);
extern int remove_lock(char *lockfile);
extern int edit_file(char *filename);
extern int show_license(int argc, char **argv, int, void *main_out);
extern int load_from_store(char *store_name, char *path, char **buf,
						   size_t *size);
extern int load_dtd(char *dtd_name, char **buf);
extern int file_exists(char *path);
extern int is_directory(char *path);
extern Dsvec *keyword_scan(char *filename);
extern char *get_dacs_app_name(void);
extern char *set_dacs_app_name(char *app_name);

extern void element_hl(FILE *fp, char *s);
extern void attribute_hl(FILE *fp, char *p, char *n, char *v);
extern int emit_html_header(FILE *fp, Html_header_conf *conf);
extern Html_header_conf *emit_html_header_conf(Html_header_conf *new_conf);
extern int emit_html_header_status_line(FILE *fp, char *code, char *reason);
extern int emit_html_header_redirect(FILE *fp, Html_header_conf *hc,
									 char *url, char *reason);

extern int emit_http_header_status(FILE *fp, char *code, char *reason);
extern int emit_http_header_redirect(FILE *fp, char *url);

extern int emit_html_trailer(FILE *fp);
extern int emit_json_header(FILE *fp, char *object_name);
extern int emit_json_trailer(FILE *fp);
extern int emit_plain_header(FILE *fp);
extern int emit_plain_trailer(FILE *fp);
extern int emit_xml_header(FILE *fp, char *dtd_name);
extern int emit_xml_trailer(FILE *fp);
extern char *get_emit_format(void);
extern int set_emit_format(char *format);
extern int test_emit_format(Emit_format fmt);
extern int test_emit_xml_format(void);
extern Ds *html_form(Ds *ods, char *url, Http_method method,
					 int no_action_args, int use_url_encoding,
					 char *form_attrs, char *submit_attrs,
					 char *cancel_attrs, Kwv *args);

extern int looks_like_domain_name(const char *str);
extern int is_valid_hostname(char *str);
extern int rfc822_parse_simple_address(char *addr, char **local_partp,
									   char **domainp);
extern int rfc822_parse_address(char *addr, char **local_partp, char **domainp);

extern int name_eq(const char *n1, const char *n2, DACS_name_cmp mode, ...);
extern DACS_name_cmp get_name_cmp_mode(void);
extern DACS_name_cmp set_name_cmp_mode(DACS_name_cmp cmp_mode);
extern DACS_name_cmp lookup_name_cmp(char *str);

extern int write_buffer(int fd, char *buf, size_t buflen);
extern ssize_t read_buffer(int fd, char *buf, size_t buflen, int noblock);
extern int is_compatible_dacs_version(char *version);
extern char *make_error_url(Kwv *kwv);
extern char *current_uri(Ds *ods);
extern char *current_uri_no_query(Ds *ods);
extern char *current_uri_sa(Ds *ods);
extern char *current_uri_prog(void);
extern char *current_uri_script(void);
extern char *current_uri_pqf(char **path, char **query, char **fragment);
extern char *set_dacs_service_uri(char *uri);
extern int current_uri_is_proxied(char *uri);

extern int is_internet_explorer(char *user_agent);
extern char *ul_str(unsigned long val);

extern int filterthru(char **argv, char **env, int *read_fd, int *write_fd,
					  int *error_fd, pid_t *pidp);
extern Dsvec *uri_path_parse(char *path);

extern DACS_name_type parse_dacs_name(char *name, DACS_name *dacs_name);
extern int is_ip_addr(const char *str, struct in_addr *addr);
extern int parse_ip_expr(char *ip_expr, struct in_addr *addrp,
						 struct in_addr *maskp);
extern int match_ip_domain_name(const char *ip, char *domain_name);
extern int match_domain_name_ip(char *domain_name, struct in_addr match_addr,
								struct in_addr match_mask);
extern int match_ip(const char *ip, struct in_addr match_addr,
					struct in_addr match_mask);
extern int match_domain_names(char *dn1, char *dn2);
extern int match_subdomain_name(const char *subdomain, const char *domain);
extern int match_ip_addr_range(char *addr_pattern, char *remote_addr);
extern int is_from_address(char *address, char *remote_addr, char *remote_host,
						   char **errmsg);

extern int get_unix_group_membership(const char *name, gid_t basegid,
									 gid_t *groups, int *ngroups);
extern int get_unix_roles(char *username, char **role_str);
extern char *directory_name_interpolate(char *format, char *hostname,
										char *port);
extern int directory_list(char *dirname, Directory_list *dl);
extern int get_logging_stream(char *file, FILE **fp, char **path,
							  char **errmsg);
extern int set_dacsdir(char *path);
extern char *get_dacsdir(void);
extern int cookie_tail_match(char *url_domain, char *cookie_domain);
extern int cookie_path_match(char *url_path, char *cookie_path);
extern int get_app_cookies(char *cookie_str, Dsvec **cookies);

extern void envdump(void);
extern void dacs_version(FILE *);
extern char *dacs_version_string(void);
extern char *dacs_component_versions_string(void);
extern char *dacs_build_os_string(void);
extern char *dacs_runtime_os_string(void);
extern char *dacs_current_jurisdiction(void);
extern char *dacs_current_jurisdiction_domain(char **jurisdiction_subdomain_prefix, char **domain_name);
extern char *get_current_log_format(void);

extern char *expand_dacs_url(char *jname, char *dacs_url);

extern int is_leap_year(int year);

extern char *encrypt_kwv(Kwv *kwv);
extern Kwv *decrypt_kwv(char *kwv_str);

extern int segment_open(char *path, int flags, size_t length, mode_t mode,
						Segment *segment);
extern int segment_extend(Segment *segment, size_t new_length);
extern int segment_close(Segment *segment);
extern int segment_delete(Segment *segment);
extern int segment_init(void);

extern char *ustamp_clock(char *hid, char *vfs_uri);
extern int ustamp_get_seqno(char *ntp_host, char **seqno_str);
extern char *ustamp_ntpclock(char *hid, char *vfs_uri, char *ntp_host);
extern char *ustamp_user(char *hid, char *vfs_uri, char *user_unique);

extern void dacs_abort(char *mesg) __attribute__ ((noreturn));
extern void dacs_disable_dump(void);

extern void *dynload_load(char *path, char **err);
extern dlfunc_t dynload_func_symbol(void *handle, char *symbol, char **err);
extern void *dynload_symbol(void *handle, char *symbol, char **err);
extern int dynload_unload(void *handle, char **err);
extern int dynload_register(void *handle, char *symbol, char **err);

extern int conf_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsauth_main(int, char **, int do_init, void *main_out);
extern int dacsacl_main(int, char **, int do_init, void *main_out);
extern int dacscheck_main(int argc, char **argv, int do_init, void *main_out);
extern int dacscookie_main(int, char **, int do_init, void *main_out);
extern int dacscred_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsemail_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsexpr_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsgrid_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsinfocard_main(int argc, char **argv, int do_init,
							 void *main_out);
extern int dacskey_main(int argc, char **argv, int do_init, void *main_out);
extern int dacslist_main(int argc, char **argv, int do_init, void *main_out);
extern int dacspasswd_main(int argc, char **argv, int do_init, void *main_out);
extern int dacstoken_main(int argc, char **argv, int do_init, void *main_out);
extern int dacstransform_main(int argc, char **argv, int do_init,
							  void *main_out);
extern int dacsversion_main(int argc, char **argv, int do_init, void *main_out);
extern int dacsvfs_main(int argc, char **argv, int do_init, void *main_out);
extern int dacshttp_main(int argc, char **argv, int do_init, void *main_out);
extern int rlink_main(int argc, char **argv, int do_init, void *main_out);
extern int sslclient_main(int argc, char **argv, int do_init, void *main_out);

#ifdef __cplusplus
}
#endif

#endif
