]> granicus.if.org Git - apache/commitdiff
Module that takes advantage of the built-in SSL functionality on the
authorBradley Nicholes <bnicholes@apache.org>
Tue, 13 Nov 2001 17:37:27 +0000 (17:37 +0000)
committerBradley Nicholes <bnicholes@apache.org>
Tue, 13 Nov 2001 17:37:27 +0000 (17:37 +0000)
NetWare OS

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@91904 13f79535-47bb-0310-9956-ffa450edef68

modules/arch/netware/mod_nw_ssl.c [new file with mode: 0644]

diff --git a/modules/arch/netware/mod_nw_ssl.c b/modules/arch/netware/mod_nw_ssl.c
new file mode 100644 (file)
index 0000000..c29d6bd
--- /dev/null
@@ -0,0 +1,462 @@
+/* ====================================================================
+ * 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
+};
+