--- /dev/null
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/*
+ * 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
+ */
+
+#define WS_SSL
+
+#define MAX_ADDRESS 512
+#define MAX_KEY 80
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "ap_listen.h"
+#include "apr_strings.h"
+
+module AP_MODULE_DECLARE_DATA nwssl_module;
+
+typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
+typedef struct seclisten_rec seclisten_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;
+ int port;
+};
+
+struct NWSSLSrvConfigRec {
+ apr_table_t *sltable;
+};
+
+static seclisten_rec* ap_seclisteners = NULL;
+
+#define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
+
+/*
+ * Parses a host of the form <address>[:port]
+ * :port is permitted if 'port' is not NULL
+ */
+static unsigned long parse_addr(const char *w, unsigned short *ports)
+{
+ struct hostent *hep;
+ unsigned long 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])) {
+ 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);
+ }
+
+ if (p != NULL)
+ *p = ':';
+
+ return ((struct in_addr *) (hep->h_addr))->s_addr;
+}
+
+static int find_secure_listener(seclisten_rec *lr)
+{
+ seclisten_rec *sl;
+
+ for (sl = ap_seclisteners; sl; sl = sl->next) {
+ if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
+ sl->used = 1;
+ return sl->fd;
+ }
+ }
+ return -1;
+}
+
+
+static int make_secure_socket(apr_pool_t *pconf, const struct sockaddr_in *server,
+ char* key, int mutual, server_rec *server_conf)
+{
+ int s;
+ int one = 1;
+ char addr[MAX_ADDRESS];
+ struct sslserveropts opts;
+ unsigned int optParam;
+ WSAPROTOCOL_INFO SecureProtoInfo;
+ int no = 1;
+
+ if (server->sin_addr.s_addr != htonl(INADDR_ANY))
+ apr_snprintf(addr, sizeof(addr), "address %s port %d",
+ inet_ntoa(server->sin_addr), ntohs(server->sin_port));
+ else
+ apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
+
+ /* note that because we're about to slack we don't use psocket */
+ memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
+
+ SecureProtoInfo.iAddressFamily = AF_INET;
+ SecureProtoInfo.iSocketType = SOCK_STREAM;
+ SecureProtoInfo.iProtocol = IPPROTO_TCP;
+ SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
+
+ s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+ (LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
+
+ if (s == INVALID_SOCKET) {
+ errno = WSAGetLastError();
+ ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
+ "make_secure_socket: failed to get a socket for %s", addr);
+ return -1;
+ }
+
+ if (!mutual) {
+ optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
+
+ if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
+ sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
+ errno = WSAGetLastError();
+ ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
+ "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr);
+ return -1;
+ }
+ }
+
+ opts.cert = key;
+ opts.certlen = strlen(key);
+ opts.sidtimeout = 0;
+ opts.sidentries = 0;
+ opts.siddir = NULL;
+
+ if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
+ NULL, 0, NULL, NULL, NULL) != 0) {
+ errno = WSAGetLastError();
+ ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
+ "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_SERVER)", addr);
+ return -1;
+ }
+
+ if (mutual) {
+ optParam = 0x07; // SO_SSL_AUTH_CLIENT
+
+ if(WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam,
+ sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
+ errno = WSAGetLastError();
+ ap_log_error( APLOG_MARK, APLOG_CRIT, errno, server_conf,
+ "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr );
+ return -1;
+ }
+ }
+
+ return s;
+}
+
+static const char *set_secure_listener(cmd_parms *cmd, void *dummy,
+ const char *ips, const char* key,
+ const char* mutual)
+{
+ NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ char *ports, *addr;
+ unsigned short port;
+ seclisten_rec *new;
+
+
+ if (err != NULL)
+ return err;
+
+ ports = strchr(ips, ':');
+
+ if (ports != NULL) {
+ if (ports == ips)
+ return "Missing IP address";
+ else if (ports[1] == '\0')
+ return "Address must end in :<port-number>";
+
+ *(ports++) = '\0';
+ }
+ else {
+ ports = (char*)ips;
+ }
+
+ new = apr_pcalloc(cmd->pool, sizeof(seclisten_rec));
+ new->local_addr.sin_family = AF_INET;
+
+ if (ports == ips) {
+ new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr = apr_pstrdup(cmd->pool, "0.0.0.0");
+ }
+ else {
+ new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
+ addr = apr_pstrdup(cmd->pool, ips);
+ }
+
+ port = atoi(ports);
+
+ if (!port)
+ return "Port must be numeric";
+
+ apr_table_set(sc->sltable, ports, "T");
+
+ new->local_addr.sin_port = htons(port);
+ new->fd = -1;
+ new->used = 0;
+ new->next = ap_seclisteners;
+ strcpy(new->key, key);
+ new->mutual = (mutual) ? 1 : 0;
+ new->addr = addr;
+ new->port = port;
+ ap_seclisteners = new;
+ return NULL;
+}
+
+static apr_status_t nwssl_socket_cleanup(void *data)
+{
+ ap_listen_rec* slr = (ap_listen_rec*)data;
+ ap_listen_rec* lr;
+
+ /* 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;
+}
+
+static void nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ ap_seclisteners = NULL;
+}
+
+static void nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ seclisten_rec* sl;
+ ap_listen_rec* lr;
+ apr_socket_t* sd;
+ apr_status_t status;
+
+ for (sl = ap_seclisteners; sl != NULL; sl = sl->next) {
+ sl->fd = find_secure_listener(sl);
+
+ if (sl->fd < 0)
+ sl->fd = make_secure_socket(pconf, &sl->local_addr, sl->key, sl->mutual, s);
+
+ if (sl->fd >= 0) {
+ apr_os_sock_info_t sock_info;
+
+ sock_info.os_sock = &(sl->fd);
+ sock_info.local = (struct sockaddr*)&(sl->local_addr);
+ sock_info.remote = NULL;
+ sock_info.family = APR_INET;
+ sock_info.type = SOCK_STREAM;
+
+ apr_os_sock_make(&sd, &sock_info, pconf);
+
+ lr = apr_pcalloc(pconf, 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,
+ pconf)) != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf,
+ "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port);
+ exit(1);
+ }
+ lr->next = ap_listeners;
+ ap_listeners = lr;
+ apr_pool_cleanup_register(pconf, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
+ }
+ } else {
+ exit(1);
+ }
+ }
+}
+
+static void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
+{
+ NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
+ new->sltable = apr_table_make(p, 5);
+ return new;
+}
+
+static void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
+{
+ NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
+ NWSSLSrvConfigRec *add = (NWSSLSrvConfigRec *)addv;
+ NWSSLSrvConfigRec *merged = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
+ return merged;
+}
+
+static int isSecure (const request_rec *r)
+{
+ NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
+ const char *s_secure = NULL;
+ char port[8];
+ int ret = 0;
+
+ itoa(((r->connection)->local_addr)->port, port, 10);
+ s_secure = apr_table_get(sc->sltable, port);
+ if (s_secure)
+ ret = 1;
+
+ return ret;
+}
+
+static int nwssl_hook_Fixup(request_rec *r)
+{
+ apr_table_t *e = r->subprocess_env;
+ if (!isSecure(r))
+ return DECLINED;
+
+ apr_table_set(e, "HTTPS", "on");
+
+ return DECLINED;
+}
+
+static const char *nwssl_hook_http_method (const request_rec *r)
+{
+ if (isSecure(r))
+ return "https";
+
+ return NULL;
+}
+
+static const 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."),
+ {NULL}
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_http_method(nwssl_hook_http_method, NULL,NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA nwssl_module =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ nwssl_config_server_create, /* server config */
+ nwssl_config_server_merge, /* merge server config */
+ nwssl_module_cmds, /* command apr_table_t */
+ register_hooks
+};
+