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

#ifdef SSL_COMPAT

#include "mod_ssl.h"

/*  _________________________________________________________________
**
**  Backward Compatibility
**  _________________________________________________________________
*/

/*
 * The mapping of obsolete directives to official ones...
 */

static char *ssl_compat_SSLRequireCipher(pool *p, const char *oline);
static char *ssl_compat_SSLBanCipher(pool *p, const char *oline);
static char *ssl_compat_words2list(pool *p, const char *oline);

static struct {
    enum { CRM_END, CRM_TXTSUB, CRM_TXTMSG, CRM_PATFCT } nType;
    char *cpMatch;
    void *vpSubst;
} ssl_cmd_rewrite_map[] = {
    /* 
     * Apache-SSL 1.x & mod_ssl 2.0.x backward compatibility
     */
    { CRM_TXTSUB, "SSLEnable",                   "SSLEngine on"                },
    { CRM_TXTSUB, "SSLDisable",                  "SSLEngine off"               },
    { CRM_TXTSUB, "SSLLogFile",                  "SSLLog"                      },
    { CRM_TXTSUB, "SSLRequiredCiphers",          "SSLCipherSuite"              },
    { CRM_PATFCT, "SSLRequireCipher",            ssl_compat_SSLRequireCipher   },
    { CRM_PATFCT, "SSLBanCipher",                ssl_compat_SSLBanCipher       },
    { CRM_TXTSUB, "SSLFakeBasicAuth",            "SSLOptions +FakeBasicAuth"   },
    { CRM_TXTSUB, "SSLExportClientCertificates", "SSLOptions +ExportCertData"  },
    { CRM_TXTMSG, "SSLCacheServerPath",          "Use SSLSessionCache instead" },
    { CRM_TXTMSG, "SSLCacheServerPort",          "Use SSLSessionCache instead" },
    { CRM_TXTMSG, "SSLCacheServerRunDir",        "Not needed for mod_ssl"      },
    /* 
     * Sioux 1.x backward compatibility
     */
    { CRM_TXTSUB, "SSL_CertFile",           "SSLCertificateFile"               },
    { CRM_TXTSUB, "SSL_KeyFile",            "SSLCertificateKeyFile"            },
    { CRM_TXTSUB, "SSL_CipherSuite",        "SSLCipherSuite"                   },
    { CRM_TXTSUB, "SSL_X509VerifyDir",      "SSLCACertificatePath"             },
    { CRM_TXTSUB, "SSL_Log",                "SSLLogFile"                       },
    { CRM_TXTSUB, "SSL_Connect"             "SSLEngine"                        },
    { CRM_TXTSUB, "SSL_ClientAuth"          "SSLVerifyClient"                  },
    { CRM_TXTSUB, "SSL_X509VerifyDepth"     "SSLVerifyDepth"                   },
    { CRM_TXTMSG, "SSL_FetchKeyPhraseFrom", "Use SSLPassPhraseDialog instead"  },
    { CRM_TXTMSG, "SSL_SessionDir",         "Use SSLSessionCache instead"      },
    { CRM_TXTMSG, "SSL_Require",            "Use SSLRequire instead (Syntax!)" },
    { CRM_TXTMSG, "SSL_CertFileType",       "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSL_KeyFileType",        "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSL_X509VerifyPolicy",   "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSL_LogX509Attributes",  "Not supported by mod_ssl"         },
    /* 
     * Stronghold 2.x backward compatibility
     */
    { CRM_TXTSUB, "SSLFlag",                   "SSLEngine"                        },
    { CRM_TXTSUB, "SSLSessionLockFile",        "SSLMutex"                         },
    { CRM_TXTSUB, "SSLLogFile",                "SSLLog"                           },
    { CRM_TXTSUB, "RequireSSL",                "SSLRequireSSL"                    },
    { CRM_TXTSUB, "SSLCipherList",             "SSLCipherSuite"                   },
    { CRM_TXTMSG, "SSLErrorFile",              "Not needed for mod_ssl"           },
    { CRM_TXTMSG, "SSLProtocol",               "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLRoot",                   "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSL_CertificateLogDir",     "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "AuthCertDir",               "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSL_Group",                 "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyMachineCertPath",   "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyMachineCertFile",   "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyCACertificatePath", "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyCACertificateFile", "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyVerifyDepth",       "Not supported by mod_ssl"         },
    { CRM_TXTMSG, "SSLProxyCipherList",        "Not supported by mod_ssl"         },
    /*
     * End of map.
     */
    { CRM_END, NULL, NULL }
};

static char *ssl_compat_SSLRequireCipher(pool *p, const char *oline)
{
    return ap_pstrcat(p, "SSLRequire %{SSL_CIPHER} in (", 
                          ssl_compat_words2list(p, oline),
                          ")", NULL); 
}

static char *ssl_compat_SSLBanCipher(pool *p, const char *oline)
{
    return ap_pstrcat(p, "SSLRequire not (%{SSL_CIPHER} in (", 
                          ssl_compat_words2list(p, oline),
                          "))", NULL); 
}

static char *ssl_compat_words2list(pool *p, const char *oline)
{
    char *line;
    char *cpI;
    char *cpO;
    char n;

    for (cpI = (char *)oline, n = 1; *cpI != NUL; )
        if ((*cpI == ' ' || *cpI == '\t') && 
            (cpI > oline && *(cpI-1) != ' ' && *(cpI-1) != '\t'))
            n++;
    line = ap_palloc(p, strlen(oline)+(n*2)+n+1);
    cpI = (char *)oline;
    cpO = line;
    *cpO++ = '"';
    while (*cpI != NUL) {
        if (*cpI == ' ' || *cpI == '\t') {
            *cpO++ = '"';
            *cpO++ = ',';
        }
        if ((*cpI != ' ' && *cpI != '\t') && 
             cpI > oline && (*(cpI-1) == ' ' || *(cpI-1) == '\t')) {
            *cpO++ = '"';
        }
        *cpO++ = *cpI++;
    }
    *cpO++ = '"';
    *cpO++ = NUL;
    return line;
}

char *ssl_compat_directive(server_rec *s, pool *p, const char *oline)
{
    int i;
    char *line;
    char *cp;

    /*
     * Skip comment lines
     */
    cp = (char *)oline;
    while ((*cp == ' ' || *cp == '\t' || *cp == '\n') && (*cp != NUL))
        cp++;
    if (*cp == '#' || *cp == NUL)
        return NULL;

    /*
     * Apply rewriting map to directives
     */
    line = NULL;
    for (i = 0; ssl_cmd_rewrite_map[i].nType != CRM_END; i++) {
        if (ssl_cmd_rewrite_map[i].nType == CRM_TXTSUB) {
            if ((cp = strstr(oline, ssl_cmd_rewrite_map[i].cpMatch)) != NULL) {
                line = ssl_util_ptxtsub(p, oline, ssl_cmd_rewrite_map[i].cpMatch,
                                        (char *)(ssl_cmd_rewrite_map[i].vpSubst));
                break;
            }
        }
        if (ssl_cmd_rewrite_map[i].nType == CRM_TXTMSG) {
            if ((cp = strstr(oline, ssl_cmd_rewrite_map[i].cpMatch)) != NULL) {
                ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, s, 
                             "mod_ssl: Obsolete/unsupported directive: %s",
                             oline);
                ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, s, 
                             "mod_ssl: Hint: %s",
                             (char *)(ssl_cmd_rewrite_map[i].vpSubst));
                line = "";
                break;
            }
        }
        else if (ssl_cmd_rewrite_map[i].nType == CRM_PATFCT) {
            if (ap_fnmatch(ssl_cmd_rewrite_map[i].cpMatch, oline, 0) == 0) {
                line = ((char *(*)(pool *, const char *))
                        (ssl_cmd_rewrite_map[i].vpSubst))(p, oline);
                break;
            }
        }
    }
    return line;
}

/*
 * The mapping of obsolete environment variables to official ones...
 */

static struct {
    enum { VRM_END, VRM_SUB, VRM_MSG } nType;
    char *cpOld;
    char *cpNew;
} ssl_var_rewrite_map[] = {
    /* 
     * Apache-SSL 1.x, mod_ssl 2.0.x, Sioux 1.x and Stronghold 2.x backward compatibility
     */
    { VRM_SUB, "SSL_PROTOCOL_VERSION",          "SSL_PROTOCOL"              },
    { VRM_SUB, "SSLEAY_VERSION",                "SSL_VERSION_LIBRARY"       },
    { VRM_SUB, "HTTPS_SECRETKEYSIZE",           "SSL_CIPHER_USEKEYSIZE"     },
    { VRM_SUB, "HTTPS_KEYSIZE",                 "SSL_CIPHER_ALGKEYSIZE"     },
    { VRM_SUB, "HTTPS_CIPHER",                  "SSL_CIPHER"                },
    { VRM_SUB, "HTTPS_EXPORT",                  "SSL_CIPHER_EXPORT"         },
    { VRM_SUB, "SSL_SERVER_KEY_SIZE",           "SSL_CIPHER_ALGKEYSIZE"     },
    { VRM_SUB, "SSL_SERVER_CERTIFICATE",        "SSL_SERVER_CERT"           },
    { VRM_SUB, "SSL_SERVER_CERT_START",         "SSL_SERVER_V_START"        },
    { VRM_SUB, "SSL_SERVER_CERT_END",           "SSL_SERVER_V_END"          },
    { VRM_SUB, "SSL_SERVER_CN",                 "SSL_SERVER_S_DN_CN"        },
    { VRM_SUB, "SSL_SERVER_EMAIL",              "SSL_SERVER_S_DN_Email"     },
    { VRM_SUB, "SSL_SERVER_O",                  "SSL_SERVER_S_DN_O"         },
    { VRM_SUB, "SSL_SERVER_OU",                 "SSL_SERVER_S_DN_OU"        },
    { VRM_SUB, "SSL_SERVER_C",                  "SSL_SERVER_S_DN_C"         },
    { VRM_SUB, "SSL_SERVER_SP",                 "SSL_SERVER_S_DN_SP"        },
    { VRM_SUB, "SSL_SERVER_L",                  "SSL_SERVER_S_DN_L"         },
    { VRM_SUB, "SSL_SERVER_ICN",                "SSL_SERVER_I_DN_CN"        },
    { VRM_SUB, "SSL_SERVER_IEMAIL",             "SSL_SERVER_I_DN_Email"     },
    { VRM_SUB, "SSL_SERVER_IO",                 "SSL_SERVER_I_DN_O"         },
    { VRM_SUB, "SSL_SERVER_IOU",                "SSL_SERVER_I_DN_OU"        },
    { VRM_SUB, "SSL_SERVER_IC",                 "SSL_SERVER_I_DN_C"         },
    { VRM_SUB, "SSL_SERVER_ISP",                "SSL_SERVER_I_DN_SP"        },
    { VRM_SUB, "SSL_SERVER_IL",                 "SSL_SERVER_I_DN_L"         },
    { VRM_SUB, "SSL_CLIENT_CERTIFICATE",        "SSL_CLIENT_CERT"           },
    { VRM_SUB, "SSL_CLIENT_CERT_START",         "SSL_CLIENT_V_START"        },
    { VRM_SUB, "SSL_CLIENT_CERT_END",           "SSL_CLIENT_V_END"          },
    { VRM_SUB, "SSL_CLIENT_CN",                 "SSL_CLIENT_S_DN_CN"        },
    { VRM_SUB, "SSL_CLIENT_EMAIL",              "SSL_CLIENT_S_DN_Email"     },
    { VRM_SUB, "SSL_CLIENT_O",                  "SSL_CLIENT_S_DN_O"         },
    { VRM_SUB, "SSL_CLIENT_OU",                 "SSL_CLIENT_S_DN_OU"        },
    { VRM_SUB, "SSL_CLIENT_C",                  "SSL_CLIENT_S_DN_C"         },
    { VRM_SUB, "SSL_CLIENT_SP",                 "SSL_CLIENT_S_DN_SP"        },
    { VRM_SUB, "SSL_CLIENT_L",                  "SSL_CLIENT_S_DN_L"         },
    { VRM_SUB, "SSL_CLIENT_ICN",                "SSL_CLIENT_I_DN_CN"        },
    { VRM_SUB, "SSL_CLIENT_IEMAIL",             "SSL_CLIENT_I_DN_Email"     },
    { VRM_SUB, "SSL_CLIENT_IO",                 "SSL_CLIENT_I_DN_O"         },
    { VRM_SUB, "SSL_CLIENT_IOU",                "SSL_CLIENT_I_DN_OU"        },
    { VRM_SUB, "SSL_CLIENT_IC",                 "SSL_CLIENT_I_DN_C"         },
    { VRM_SUB, "SSL_CLIENT_ISP",                "SSL_CLIENT_I_DN_SP"        },
    { VRM_SUB, "SSL_CLIENT_IL",                 "SSL_CLIENT_I_DN_L"         },
    { VRM_MSG, "SSL_SERVER_KEY_EXP",            "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_KEY_ALGORITHM",      "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_SIGNATURE_ALGORITHM","Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_SESSIONDIR",         "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_CERTIFICATELOGDIR",  "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_CERTFILE",           "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_KEYFILE",            "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_SERVER_KEYFILETYPE",        "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_CLIENT_KEY_EXP",            "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_CLIENT_KEY_ALGORITHM",      "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_CLIENT_KEY_SIZE",           "Not supported by mod_ssl"  },
    { VRM_MSG, "SSL_CLIENT_SIGNATURE_ALGORITHM","Not supported by mod_ssl"  },
    /*
     * End of map.
     */
    { VRM_END, NULL, NULL }
};

void ssl_compat_variables(request_rec *r)
{
    char *cpOld;
    char *cpNew;
    char *cpVal;
    int i;

    for (i = 0; ssl_var_rewrite_map[i].nType != VRM_END; i++) {
        cpOld = ssl_var_rewrite_map[i].cpOld;
        cpNew = ssl_var_rewrite_map[i].cpNew;
        if (ssl_var_rewrite_map[i].nType == VRM_SUB) {
            cpVal = ssl_var_lookup(r->pool, r->server, r->connection, r, cpNew);
            if (!strIsEmpty(cpVal))
                ap_table_set(r->subprocess_env, cpOld, cpVal);
            break;
        }
        else if (ssl_var_rewrite_map[i].nType == VRM_MSG) {
            ap_table_set(r->subprocess_env, cpOld, cpNew);
            break;
        }
    }
    return;
}

#endif /* SSL_COMPAT */
