You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by bn...@apache.org on 2001/11/13 18:37:27 UTC

cvs commit: httpd-2.0/modules/arch/netware mod_nw_ssl.c

bnicholes    01/11/13 09:37:27

  Added:       modules/arch/netware mod_nw_ssl.c
  Log:
  Module that takes advantage of the built-in SSL functionality on the
  NetWare OS
  
  Revision  Changes    Path
  1.1                  httpd-2.0/modules/arch/netware/mod_nw_ssl.c
  
  Index: mod_nw_ssl.c
  ===================================================================
  /* ====================================================================
   * 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
  };