/* ====================================================================
 * Copyright (c) 1998 Ralf S. Engelschall. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by 
 *     Ralf S. Engelschall <rse@engelschall.com> for use in the
 *     mod_ssl project (http://www.engelschall.com/sw/mod_ssl/)."
 *
 * 4. The names "mod_ssl" must not be used to endorse or promote
 *    products derived from this software without prior written
 *    permission. For written permission, please contact
 *    rse@engelschall.com.
 *
 * 5. Products derived from this software may not be called "mod_ssl"
 *    nor may "mod_ssl" appear in their names without prior
 *    written permission of Ralf S. Engelschall.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by 
 *     Ralf S. Engelschall <rse@engelschall.com> for use in the
 *     mod_ssl project (http://www.engelschall.com/sw/mod_ssl/)."
 *
 * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR
 * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes software developed by Ben Laurie
 * for use in the Apache-SSL HTTP server project.
 */

/*                      _             _ 
**  _ __ ___   ___   __| |    ___ ___| |  
** | '_ ` _ \ / _ \ / _` |   / __/ __| |  
** | | | | | | (_) | (_| |   \__ \__ \ | mod_ssl - Apache Interface to SSLeay
** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.engelschall.com/sw/mod_ssl/
**                      |_____|         
*/

#ifndef MOD_SSL_H
#define MOD_SSL_H 1

/*
 * Provide reasonable default for some defines
 */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE  !FALSE
#endif
#ifndef UNSET
#define UNSET -1
#endif
#ifndef NUL
#define NUL   '\0'
#endif

/*
 * Provide reasonable defines for some types
 */
#ifndef BOOL
#define BOOL bool
typedef unsigned int bool;
#endif
#ifndef UCHAR
#define UCHAR uchar
typedef unsigned char uchar;
#endif

/*
 * Provide useful shorthands
 */
#define strEQ(s1,s2)     strcmp(s1,s2)        == 0
#define strNE(s1,s2)     strcmp(s1,s2)        != 0
#define strEQn(s1,s2,n)  strncmp(s1,s2,n)     == 0
#define strNEn(s1,s2,n)  strncmp(s1,s2,n)     != 0

#define strcEQ(s1,s2)    strcasecmp(s1,s2)    == 0
#define strcNE(s1,s2)    strcasecmp(s1,s2)    != 0
#define strcEQn(s1,s2,n) strncasecmp(s1,s2,n) == 0
#define strcNEn(s1,s2,n) strncasecmp(s1,s2,n) != 0

#define cfgMerge(el,unset)  new->el = add->el == unset ? base->el : add->el
#define cfgMergeTable(el)   new->el = ap_overlay_tables(p, add->el, base->el)
#define cfgMergeString(el)  cfgMerge(el, NULL)
#define cfgMergeBool(el)    cfgMerge(el, UNSET)
#define cfgMergeInt(el)     cfgMerge(el, 0)

#define mySrvConfig(srv) (SSLConfigRec *)ap_get_module_config(srv->module_config,  &ssl_module)
#define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module)

/* 
 * Set to TRUE if you want to allow SSL to be disabled on a per-request basis
 * (useful for subrequests) 
 */
#define SSL_IS_OPTIONAL FALSE  
#if SSL_IS_OPTIONAL
#define OPTIONAL_SSL    (!r->connection->client->ssl)
#else
#define OPTIONAL_SSL    FALSE
#endif

/*
 * Give an error if SSLeay below 0.8.0 is used 
 */
#if SSLEAY_VERSION_NUMBER < 0x0800
#error "SSLeay versions below 0.8.0 are not supported"
#endif

/*
 * Correct a typo in SSLeay 
 */
#if SSLEAY_VERSION_NUMBER < 0x900
#define SSL3_TXT_ADH_DES_192_CBC_SHA SSL3_TXT_ADH_DES_196_CBC_SHA
#endif

/*
 * Define the SSL verify levels
 */
typedef enum {
    VERIFY_UNSET           = UNSET,
    VERIFY_NONE            = 0,
    VERIFY_OPTIONAL        = 1,
    VERIFY_REQUIRE         = 2,
    VERIFY_OPTIONAL_NO_CA  = 3
} VerifyType;

/*
 * Define the mod_ssl per-server configuration structure 
 */
typedef struct {
    BOOL       bDisabled;
    char      *szCertificateFile;
    char      *szKeyFile;
    char      *szCACertificatePath;
    char      *szCACertificateFile;
    char      *szLogFile;
    char      *szReqCiphers;
    int        nVerifyDepth;
    VerifyType nVerifyClient;
    BOOL       bFakeBasicAuth;
    time_t     tSessionCacheTimeout;
    FILE      *fileLogFile;
    X509      *px509Certificate;
    RSA       *prsaKey;
    SSL_CTX   *pSSLCtx;
} SSLConfigRec;

/*
 * Define the mod_ssl per-directory configuration structure 
 */
typedef struct {
    table *tbRequiredCiphers;
    table *tbBannedCiphers;
    BOOL   bSSLRequired;
} SSLDirConfigRec;

/*
 * Provide an empty define to be able to mark SSLeay symbols
 */
#define __SSLeay

/*  
 *  function prototypes
 */

/*  API glue structures  */
module MODULE_VAR_EXPORT ssl_module;

/*  configuration handling   */
static void        *config_server_create(pool *, server_rec *);
static void        *config_server_merge(pool *, void *, void *);
static void        *config_perdir_create(pool *, char *);
static void        *config_perdir_merge(pool *, void *, void *);

static const char  *cmd_PolySetSlotString(cmd_parms *, char *, char *);
static const char  *cmd_PolySetSlotInt(cmd_parms *, char *, char *);
static const char  *cmd_PolySetSlotTrue(cmd_parms *, char *);
static const char  *cmd_PolySetSlotFalse(cmd_parms *, char *);
static const char  *cmd_SSLRequireCipher(cmd_parms *, SSLDirConfigRec *, char *);
static const char  *cmd_SSLBanCipher(cmd_parms *, SSLDirConfigRec *, char *);
static const char  *cmd_SSLRequireSSL(cmd_parms *, SSLDirConfigRec *, char *);
static const char  *cmd_SSLCacheServerPort(cmd_parms *, char *, char *);
static const char  *cmd_SSLCacheServerPath(cmd_parms *, char *, char *);
static const char  *cmd_SSLVerifyClient(cmd_parms *, char *, char *);

/*  module initialization  */
static void         init_Module(server_rec *, pool *);
static void         init_SSLeay(server_rec *, pool *);
static void         init_GetCertAndKey(server_rec *, pool *, SSLConfigRec *);
static void         init_GetPrivateKey(server_rec *, pool *, SSLConfigRec *, const char *);
static int          init_VerifyFlags(SSLConfigRec *);

/*  Apache API hooks  */
/*NONSTATIC*/ int   SSL_HOOK_SetupConnection(conn_rec *);
static void         SSL_HOOK_CloseConnection(void *);
static int          ssl_hook_Auth(request_rec *);
static int          ssl_hook_Access(request_rec *);
static int          ssl_hook_Fixup(request_rec *);

/*  SSLeay callbacks */
static RSA         *ssl_callback_TmpRSA(SSL *, int);
static int          ssl_callback_SSLVerify(int, X509_STORE_CTX *);
static int          ssl_callback_NewSessionCache(SSL *, SSL_SESSION *);
static SSL_SESSION *ssl_callback_GetSessionCache(SSL *, unsigned char *, int, int *);

/*  SSL internals  */
static void         ssl_int_ExpandCert(table *, char *, char *);
static BOOL         ssl_int_SetCertStuff(conn_rec *);
static void         ssl_int_SetupVerify(conn_rec *);

/*  Session Cache Support  */
static void         LaunchCache(server_rec *, pool *);
static int          CacheLauncher(void *, child_info *);
static void         SendSessionToServer(SSL_SESSION *);
static SSL_SESSION *GetSessionFromServer(uchar *, int);

/*  Logfile Support  */
static void         ssl_log_own(SSLConfigRec *, const char *, ...);
static void         ssl_log_ssleay2apache(server_rec *);

/*  Utility Functions  */
static void         util_strupper(char *);
static void         util_uuencode(char *, const char *);

#endif /* MOD_SSL_H */
