mod_nw_ssl.c revision b9c702facf0e6ec00f9a777a8a896e906a01ecd9
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Copyright 2001-2004 Apache Software Foundation
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Licensed under the Apache License, Version 2.0 (the "License");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * you may not use this file except in compliance with the License.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * You may obtain a copy of the License at
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Unless required by applicable law or agreed to in writing, software
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distributed under the License is distributed on an "AS IS" BASIS,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * See the License for the specific language governing permissions and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * limitations under the License.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This module gives Apache the ability to do SSL/TLS with a minimum amount
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * of effort. All of the SSL/TLS logic is already on NetWare versions 5 and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * above and is interfaced through WinSock on NetWare. As you can see in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the code below SSL/TLS sockets can be created with three WinSock calls.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * To load, simply place the module in the modules directory under the main
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * apache tree. Then add a "SecureListen" with two arguments. The first
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * argument is an address and/or port. The second argument is the key pair
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * name as created in ConsoleOne.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SecureListen 443 "SSL CertificateIP"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SecureListen 123.45.67.89:443 mycert
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes struct sockaddr_in local_addr; /* local IP address and port */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int numcerts = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes certarray = apr_palloc(p, sizeof(unicode_t*)*numcerts);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0; i < numcerts; ++i) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unistr = (unicode_t*)apr_palloc(p, strlen(rootcerts[i])*4);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes loc2uni (UNI_LOCAL_DEFAULT, unistr, rootcerts[i], 0, 2);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Parses a host of the form <address>[:port]
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * :port is permitted if 'port' is not NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic unsigned long parse_addr(const char *w, unsigned short *ports)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned long my_addr;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX Should be echoing by h_errno the actual failure, no?
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ap_log_error would be good here. Better yet - APRize.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes fprintf(stderr, "Host %s has multiple addresses ---\n", w);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes fprintf(stderr, "you must choose one explicitly for use as\n");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return ((struct in_addr *) (hep->h_addr))->s_addr;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int make_secure_socket(apr_pool_t *pconf, const struct sockaddr_in *server,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned int optParam;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_snprintf(addr, sizeof(addr), "address %s port %d",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inet_ntoa(server->sin_addr), ntohs(server->sin_port));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* note that because we're about to slack we don't use psocket */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), sconf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "make_secure_socket: failed to get a socket for %s",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), sconf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "make_secure_socket: for %s, WSAIoctl: "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), sconf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "make_secure_socket: for %s, WSAIoctl: "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if(WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), sconf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "make_secure_socket: for %s, WSAIoctl: "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam, sizeof(optParam),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesint convert_secure_socket(conn_rec *c, apr_socket_t *csd)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned long ulFlags;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* zero out buffers */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes memset((char *)&sWS2Opts, 0, sizeof(struct tlsclientopts));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* turn on ssl for the socket */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ulFlags = (numcerts ? SO_TLS_ENABLE : SO_TLS_ENABLE | SO_TLS_BLIND_ACCEPT);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rcode = WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Error: %d with ioctlsocket(flag SO_TLS_ENABLE)", WSAGetLastError());
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* setup the socket for SSL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sNWTLSOpts.walletProvider = WAL_PROV_DER; //the wallet provider defined in wdefs.h
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sNWTLSOpts.TrustedRootList = certarray; //array of certs in UNICODE format
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sNWTLSOpts.numElementsInTRList = numcerts; //number of certs in TRList
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* setup the socket for SSL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sWS2Opts.wallet = keyFileName; /* no client certificate */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sNWTLSOpts.walletProvider = WAL_PROV_KMO; //the wallet provider defined in wdefs.h
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* make the IOCTL call */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rcode = WSAIoctl(sock, SO_TLS_SET_CLIENT, &sWS2Opts,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* make sure that it was successfull */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Error: %d with ioctl (SO_TLS_SET_CLIENT)", WSAGetLastError());
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *set_secure_listener(cmd_parms *cmd, void *dummy,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char* mutual)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned short port;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "Missing IP address";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "Address must end in :<port-number>";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new = apr_pcalloc(cmd->pool, sizeof(seclisten_rec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "Port must be numeric";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t nwssl_socket_cleanup(void *data)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Remove our secure listener from the listener list */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* slr is at the head of the list */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* slr is somewhere in between or at the end*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *set_trusted_certs(cmd_parms *cmd, void *dummy, char *arg)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes certlist = apr_array_make(pconf, 1, sizeof(char *));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int nwssl_pre_connection(conn_rec *c, void *csd)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (sl = ap_seclisteners; sl != NULL; sl = sl->next) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sl->fd = make_secure_socket(pconf, &sl->local_addr, sl->key, sl->mutual, s);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sock_info.local = (struct sockaddr*)&(sl->local_addr);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((status = apr_sockaddr_info_get(&lr->bind_addr, sl->addr, APR_UNSPEC, sl->port, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_pool_cleanup_register(pconf, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes NWSSLSrvConfigRec *add = (NWSSLSrvConfigRec *)addv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes NWSSLSrvConfigRec *merged = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes itoa(((r->connection)->local_addr)->port, port, 10);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *nwssl_hook_http_method (const request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "https";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_port_t nwssl_hook_default_port(const request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "specify an address and/or port with a key pair name.\n"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Optional third parameter of MUTUAL configures the port for mutual authentication."),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_INIT_ITERATE("NWSSLTrustedCerts", set_trusted_certs, NULL, RSRC_CONF,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Adds trusted certificates that are used to create secure connections to proxied servers"),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_pre_connection(nwssl_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_http_method(nwssl_hook_http_method, NULL,NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_default_port (nwssl_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes nwssl_config_server_merge, /* merge server config */