/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* * based on mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner. * * This module gives Apache the ability to do SSL/TLS with a minimum amount * of effort. All of the SSL/TLS logic is already on NetWare versions 5 and * above and is interfaced through WinSock on NetWare. As you can see in * the code below SSL/TLS sockets can be created with three WinSock calls. * * To load, simply place the module in the modules directory under the main * apache tree. Then add a "SecureListen" with two arguments. The first * argument is an address and/or port. The second argument is the key pair * name as created in ConsoleOne. * * Examples: * * SecureListen 443 "SSL CertificateIP" * SecureListen 123.45.67.89:443 mycert * * The module also supports RFC 2817 / TLS Upgrade for HTTP 1.1. * For this add a "NWSSLUpgradeable" with two arguments. The first * argument is an address and/or port. The second argument is the key pair * name as created in ConsoleOne. * * Examples: * * NWSSLUpgradeable 8080 "SSL CertificateIP" * NWSSLUpgradeable 123.45.67.89:8080 mycert *
*/
/* An optional function which returns non-zero if the given connection
* is using SSL/TLS. */
APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
/* The ssl_proxy_enable() and ssl_engine_disable() optional functions * are used by mod_proxy to enable use of SSL for outgoing
* connections. */
APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
struct seclisten_rec {
seclisten_rec *next; struct sockaddr_in local_addr; /* local IP address and port */ int fd; int used; /* Only used during restart */ char key[MAX_KEY]; int mutual; char *addr;
apr_port_t port;
};
for (i = 0; i < numcerts; ++i) {
unicode_t *unistr;
unistr = (unicode_t*)apr_palloc(p, strlen(rootcerts[i])*4);
loc2uni (UNI_LOCAL_DEFAULT, unistr, rootcerts[i], 0, 2);
certarray[i] = unistr;
}
}
/* * Parses a host of the form <address>[:port] * :port is permitted if 'port' is not NULL
*/ staticunsignedlong parse_addr(constchar *w, unsignedshort *ports)
{ struct hostent *hep; unsignedlong my_addr; char *p;
p = strchr(w, ':'); if (ports != NULL) {
*ports = 0; if (p != NULL && strcmp(p + 1, "*") != 0)
*ports = atoi(p + 1);
}
if (p != NULL)
*p = '\0'; if (strcmp(w, "*") == 0) { if (p != NULL)
*p = ':'; return htonl(INADDR_ANY);
}
my_addr = apr_inet_addr((char *)w); if (my_addr != INADDR_NONE) { if (p != NULL)
*p = ':'; return my_addr;
}
hep = gethostbyname(w);
if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { /* XXX Should be echoing by h_errno the actual failure, no? * ap_log_error would be good here. Better yet - APRize.
*/
fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w); exit(1);
}
if (hep->h_addr_list[1]) {
fprintf(stderr, "Host %s has multiple addresses ---\n", w);
fprintf(stderr, "you must choose one explicitly for use as\n");
fprintf(stderr, "a secure port. Exiting!!!\n"); exit(1);
}
s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
(LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
if (s == INVALID_SOCKET) {
ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
APLOGNO(02120) "make_secure_socket: failed to get a socket for %s",
addr); return -1;
}
if (!mutual) {
optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
/* setup the socket for SSL */
memset (&sWS2Opts, 0, sizeof(sWS2Opts));
memset (&sNWTLSOpts, 0, sizeof(sNWTLSOpts));
sWS2Opts.options = &sNWTLSOpts;
if (numcerts) {
sNWTLSOpts.walletProvider = WAL_PROV_DER; /* the wallet provider defined in wdefs.h */
sNWTLSOpts.TrustedRootList = certarray; /* array of certs in UNICODE format */
sNWTLSOpts.numElementsInTRList = numcerts; /* number of certs in TRList */
} else { /* setup the socket for SSL */
unicpy(keyFileName, L"SSL CertificateIP");
sWS2Opts.wallet = keyFileName; /* no client certificate */
sWS2Opts.walletlen = unilen(keyFileName);
sNWTLSOpts.walletProvider = WAL_PROV_KMO; /* the wallet provider defined in wdefs.h */
}
/* make the IOCTL call */
rcode = WSAIoctl(sock, SO_TLS_SET_CLIENT, &sWS2Opts, sizeof(struct tlsclientopts), NULL, 0, NULL,
NULL, NULL);
/* make sure that it was successful */ if (SOCKET_ERROR == rcode ) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, APLOGNO(02125) "Error: %d with WSAIoctl(SO_TLS_SET_CLIENT)",
WSAGetLastError());
} return rcode;
}
/* If the specified addr:port was created previously, put the listen socket record back on the ap_listeners list so that the socket
will be reused rather than recreated */ for (walk = &nw_old_listeners; *walk;) {
sa = (*walk)->bind_addr; if (sa) {
ap_listen_rec *new;
apr_port_t oldport;
oldport = sa->port; /* If both ports are equivalent, then if their names are equivalent, * then we will re-use the existing record.
*/ if (port == oldport &&
((!addr && !sa->hostname) ||
((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) { new = *walk;
*walk = new->next;
new->next = ap_listeners;
ap_listeners = new;
found_listener = 1; continue;
}
}
walk = &(*walk)->next;
}
apr_table_add(sc->sltable, ports, addr);
/* If we found a pre-existing listen socket record, then there
is no need to create a new secure listen socket record. */ if (found_listener) { return NULL;
}
/* Remove our secure listener from the listener list */ for (lr = ap_listeners; lr; lr = lr->next) { /* slr is at the head of the list */ if (lr == slr) {
ap_listeners = slr->next; break;
} /* slr is somewhere in between or at the end*/ if (lr->next == slr) {
lr->next = slr->next; break;
}
} return APR_SUCCESS;
}
/* Pull all of the listeners that were created by mod_nw_ssl out of the ap_listeners list so that the normal listen socket processing does
automatically close them */
nw_old_listeners = NULL;
ap_old_seclisteners = NULL;
for (secwalk = &ap_seclisteners; *secwalk;) {
found = 0; for (walk = &ap_listeners; *walk;) {
sa = (*walk)->bind_addr; if (sa) {
ap_listen_rec *new;
seclisten_rec *secnew;
apr_port_t oldport;
oldport = sa->port; /* If both ports are equivalent, then if their names are equivalent, * then we will re-use the existing record.
*/ if ((*secwalk)->port == oldport &&
((!(*secwalk)->addr && !sa->hostname) ||
(((*secwalk)->addr && sa->hostname) && !strcmp(sa->hostname, (*secwalk)->addr)))) { /* Move the listen socket from ap_listeners to nw_old_listeners */ new = *walk;
*walk = new->next;
new->next = nw_old_listeners;
nw_old_listeners = new;
/* Move the secure socket record to ap_old_seclisterners */
secnew = *secwalk;
*secwalk = secnew->next;
secnew->next = ap_old_seclisteners;
ap_old_seclisteners = secnew;
found = 1; break;
}
}
walk = &(*walk)->next;
} if (!found && &(*secwalk)->next) {
secwalk = &(*secwalk)->next;
}
}
/* Restore the secure socket records list so that the post config can
process all of the sockets normally */
ap_seclisteners = ap_old_seclisteners;
ap_seclistenersup = NULL;
certlist = apr_array_make(pconf, 1, sizeof(char *));
/* Now that we have removed all of the mod_nw_ssl created socket records, allow the normal listen socket handling to occur. NOTE: If for any reason mod_nw_ssl is removed as a built-in module, the following call must be put back into the pre-config handler of the MPM. It is only here to ensure that mod_nw_ssl fixes up the listen
socket list before anything else looks at it. */
ap_listen_pre_config();
/* Walk the old listeners list and compare it to the secure listeners list and remove any secure listener records that
are not being reused */ for (walk = nw_old_listeners; walk; walk = walk->next) {
sa = walk->bind_addr; if (sa) {
ap_listen_rec *new;
apr_port_t oldport;
oldport = sa->port; for (secwalk = ap_seclisteners, lastsecwalk = ap_seclisteners; secwalk; secwalk = lastsecwalk->next) { unsignedshort port = secwalk->port; char *addr = secwalk->addr; /* If both ports are equivalent, then if their names are equivalent, * then we will re-use the existing record.
*/ if (port == oldport &&
((!addr && !sa->hostname) ||
((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) { if (secwalk == ap_seclisteners) {
ap_seclisteners = secwalk->next;
} else {
lastsecwalk->next = secwalk->next;
}
apr_socket_close(walk->sd);
walk->active = 0; break;
} else {
lastsecwalk = secwalk;
}
}
}
}
for (sl = ap_seclisteners; sl != NULL; sl = sl->next) { /* If we find a pre-existing listen socket and it has already been
created, then no need to go any further, just reuse it. */ if (((sl->fd = find_secure_listener(sl)) >= 0) && (sl->used)) { continue;
}
lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
if (lr) {
lr->sd = sd; if ((status = apr_sockaddr_info_get(&lr->bind_addr, sl->addr, APR_UNSPEC, sl->port, 0,
s->process->pool)) != APR_SUCCESS) {
ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf, APLOGNO(02129) "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port); return HTTP_INTERNAL_SERVER_ERROR;
}
lr->next = ap_listeners;
ap_listeners = lr;
apr_pool_cleanup_register(s->process->pool, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
}
} else { return HTTP_INTERNAL_SERVER_ERROR;
}
}
for (slu = ap_seclistenersup; slu; slu = slu->next) { /* Check the listener list for a matching upgradeable listener */
found = 0; for (lr = ap_listeners; lr; lr = lr->next) { if (slu->port == lr->bind_addr->port) {
found = 1; break;
}
} if (!found) {
ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, plog, APLOGNO(02130) "No Listen directive found for upgradeable listener %s:%d", slu->addr, slu->port);
}
}
return isSecureConn (c->base_server, c) || (csd_data && csd_data->is_secure);
}
/* This function must remain safe to use for a non-SSL connection. */ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
{
NWSSLSrvConfigRec *mc = get_nwssl_cfg(s); constchar *result; BOOL resdup;
apr_time_exp_t tm;
result = NULL;
resdup = TRUE;
/* * When no pool is given try to find one
*/ if (p == NULL) { if (r != NULL)
p = r->pool; elseif (c != NULL)
p = c->pool; else
p = mc->pPool;
}
/* * Request dependent stuff
*/ if (r != NULL) { switch (var[0]) { case'H': case'h': if (strcEQ(var, "HTTP_USER_AGENT"))
result = apr_table_get(r->headers_in, "User-Agent"); elseif (strcEQ(var, "HTTP_REFERER"))
result = apr_table_get(r->headers_in, "Referer"); elseif (strcEQ(var, "HTTP_COOKIE"))
result = apr_table_get(r->headers_in, "Cookie"); elseif (strcEQ(var, "HTTP_FORWARDED"))
result = apr_table_get(r->headers_in, "Forwarded"); elseif (strcEQ(var, "HTTP_HOST"))
result = apr_table_get(r->headers_in, "Host"); elseif (strcEQ(var, "HTTP_PROXY_CONNECTION"))
result = apr_table_get(r->headers_in, "Proxy-Connection"); elseif (strcEQ(var, "HTTP_ACCEPT"))
result = apr_table_get(r->headers_in, "Accept"); elseif (strcEQ(var, "HTTPS")) { if (isSecure(r) || isSecureUpgraded(r))
result = "on"; else
result = "off";
} elseif (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) /* all other headers from which we are still not know about */
result = apr_table_get(r->headers_in, var+5); break;
case'R': case'r': if (strcEQ(var, "REQUEST_METHOD"))
result = r->method; elseif (strcEQ(var, "REQUEST_SCHEME"))
result = ap_http_scheme(r); elseif (strcEQ(var, "REQUEST_URI"))
result = r->uri; elseif (strcEQ(var, "REQUEST_FILENAME"))
result = r->filename; elseif (strcEQ(var, "REMOTE_ADDR"))
result = r->useragent_ip; elseif (strcEQ(var, "REMOTE_HOST"))
result = ap_get_useragent_host(r, REMOTE_NAME, NULL); elseif (strcEQ(var, "REMOTE_IDENT"))
result = ap_get_remote_logname(r); elseif (strcEQ(var, "REMOTE_USER"))
result = r->user; break;
case'S': case's': if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
if (strcEQ(var, "SERVER_ADMIN"))
result = r->server->server_admin; elseif (strcEQ(var, "SERVER_NAME"))
result = ap_get_server_name_for_url(r); elseif (strcEQ(var, "SERVER_PORT"))
result = apr_psprintf(p, "%u", ap_get_server_port(r)); elseif (strcEQ(var, "SERVER_PROTOCOL"))
result = r->protocol; elseif (strcEQ(var, "SCRIPT_FILENAME"))
result = r->filename; break;
default: if (strcEQ(var, "PATH_INFO"))
result = r->path_info; elseif (strcEQ(var, "QUERY_STRING"))
result = r->args; elseif (strcEQ(var, "IS_SUBREQ"))
result = (r->main != NULL ? "true" : "false"); elseif (strcEQ(var, "DOCUMENT_ROOT"))
result = ap_document_root(r); elseif (strcEQ(var, "AUTH_TYPE"))
result = r->ap_auth_type; elseif (strcEQ(var, "THE_REQUEST"))
result = r->the_request; break;
}
}
/* * Connection stuff
*/ if (result == NULL && c != NULL) { /* XXX-Can't get specific SSL info from NetWare */ /* SSLConnRec *sslconn = myConnConfig(c); if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) && sslconn && sslconn->ssl)
result = ssl_var_lookup_ssl(p, c, var+4);*/
if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
result = NULL;
}
/* * Totally independent stuff
*/ if (result == NULL) { if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
result = NULL; /* XXX-Can't get specific SSL info from NetWare */ /*result = ssl_var_lookup_ssl_version(p, var+12);*/ elseif (strcEQ(var, "SERVER_SOFTWARE"))
result = ap_get_server_banner(); elseif (strcEQ(var, "API_VERSION")) {
result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR);
resdup = FALSE;
} elseif (strcEQ(var, "TIME_YEAR")) {
apr_time_exp_lt(&tm, apr_time_now());
result = apr_psprintf(p, "%02d%02d",
(tm.tm_year / 100) + 19, tm.tm_year % 100);
resdup = FALSE;
} #define MKTIMESTR(format, tmfield) \
apr_time_exp_lt(&tm, apr_time_now()); \
result = apr_psprintf(p, format, tm.tmfield); \
resdup = FALSE; elseif (strcEQ(var, "TIME_MON")) {
MKTIMESTR("%02d", tm_mon+1)
} elseif (strcEQ(var, "TIME_DAY")) {
MKTIMESTR("%02d", tm_mday)
} elseif (strcEQ(var, "TIME_HOUR")) {
MKTIMESTR("%02d", tm_hour)
} elseif (strcEQ(var, "TIME_MIN")) {
MKTIMESTR("%02d", tm_min)
} elseif (strcEQ(var, "TIME_SEC")) {
MKTIMESTR("%02d", tm_sec)
} elseif (strcEQ(var, "TIME_WDAY")) {
MKTIMESTR("%d", tm_wday)
} elseif (strcEQ(var, "TIME")) {
apr_time_exp_lt(&tm, apr_time_now());
result = apr_psprintf(p, "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
(tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
resdup = FALSE;
} /* all other env-variables from the parent Apache process */ elseif (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
result = apr_table_get(r->notes, var+4); if (result == NULL)
result = apr_table_get(r->subprocess_env, var+4); if (result == NULL)
result = getenv(var+4);
}
}
if (result != NULL && resdup)
result = apr_pstrdup(p, result); if (result == NULL)
result = ""; return (char *)result;
}
/* Now that we have initialized the ssl connection which added the ssl_io_filter, pass the brigade off to the connection based output filters so that the
request can complete encrypted */ return ap_pass_brigade(f->c->output_filters, bb);
}
if (isSecureUpgradeable (r)) {
ap_add_output_filter("UPGRADE_FILTER", NULL, r, r->connection);
}
}
staticconst command_rec nwssl_module_cmds[] =
{
AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF, "specify an address and/or port with a key pair name.\n" "Optional third parameter of MUTUAL configures the port for mutual authentication."),
AP_INIT_TAKE2("NWSSLUpgradeable", set_secure_upgradeable_listener, NULL, RSRC_CONF, "specify an address and/or port with a key pair name, that can be upgraded to an SSL connection.\n" "The address and/or port must have already be defined using a Listen directive."),
AP_INIT_ITERATE("NWSSLTrustedCerts", set_trusted_certs, NULL, RSRC_CONF, "Adds trusted certificates that are used to create secure connections to proxied servers"),
{NULL}
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.