1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
60 * mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
62 * This module gives Apache the ability to do SSL/TLS with a minimum amount
63 * of effort. All of the SSL/TLS logic is already on NetWare versions 5 and
64 * above and is interfaced through WinSock on NetWare. As you can see in
65 * the code below SSL/TLS sockets can be created with three WinSock calls.
67 * To load, simply place the module in the modules directory under the main
68 * apache tree. Then add a "SecureListen" with two arguments. The first
69 * argument is an address and/or port. The second argument is the key pair
70 * name as created in ConsoleOne.
74 * SecureListen 443 "SSL CertificateIP"
75 * SecureListen 123.45.67.89:443 mycert
80 #define MAX_ADDRESS 512
85 #include "http_config.h"
87 #include "ap_listen.h"
88 #include "apr_strings.h"
89 #include "apr_portable.h"
91 module AP_MODULE_DECLARE_DATA nwssl_module;
93 typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
94 typedef struct seclisten_rec seclisten_rec;
96 struct seclisten_rec {
98 struct sockaddr_in local_addr; /* local IP address and port */
100 int used; /* Only used during restart */
107 struct NWSSLSrvConfigRec {
108 apr_table_t *sltable;
111 static seclisten_rec* ap_seclisteners = NULL;
113 #define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
116 * Parses a host of the form <address>[:port]
117 * :port is permitted if 'port' is not NULL
119 static unsigned long parse_addr(const char *w, unsigned short *ports)
122 unsigned long my_addr;
128 if (p != NULL && strcmp(p + 1, "*") != 0)
129 *ports = atoi(p + 1);
134 if (strcmp(w, "*") == 0) {
137 return htonl(INADDR_ANY);
140 my_addr = apr_inet_addr((char *)w);
141 if (my_addr != INADDR_NONE) {
147 hep = gethostbyname(w);
149 if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
150 /* XXX Should be echoing by r_errno the actual failure, no?
151 * ap_log_error would be good here.
153 fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
157 if (hep->h_addr_list[1]) {
158 fprintf(stderr, "Host %s has multiple addresses ---\n", w);
159 fprintf(stderr, "you must choose one explicitly for use as\n");
160 fprintf(stderr, "a secure port. Exiting!!!\n");
167 return ((struct in_addr *) (hep->h_addr))->s_addr;
170 static int find_secure_listener(seclisten_rec *lr)
174 for (sl = ap_seclisteners; sl; sl = sl->next) {
175 if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
184 static int make_secure_socket(apr_pool_t *pconf, const struct sockaddr_in *server,
185 char* key, int mutual, server_rec *server_conf)
189 char addr[MAX_ADDRESS];
190 struct sslserveropts opts;
191 unsigned int optParam;
192 WSAPROTOCOL_INFO SecureProtoInfo;
195 if (server->sin_addr.s_addr != htonl(INADDR_ANY))
196 apr_snprintf(addr, sizeof(addr), "address %s port %d",
197 inet_ntoa(server->sin_addr), ntohs(server->sin_port));
199 apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
201 /* note that because we're about to slack we don't use psocket */
202 memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
204 SecureProtoInfo.iAddressFamily = AF_INET;
205 SecureProtoInfo.iSocketType = SOCK_STREAM;
206 SecureProtoInfo.iProtocol = IPPROTO_TCP;
207 SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
209 s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
210 (LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
212 if (s == INVALID_SOCKET) {
213 errno = WSAGetLastError();
214 ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
215 "make_secure_socket: failed to get a socket for %s", addr);
220 optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
222 if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
223 sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
224 errno = WSAGetLastError();
225 ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
226 "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr);
232 opts.certlen = strlen(key);
237 if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
238 NULL, 0, NULL, NULL, NULL) != 0) {
239 errno = WSAGetLastError();
240 ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
241 "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_SERVER)", addr);
246 optParam = 0x07; // SO_SSL_AUTH_CLIENT
248 if(WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam,
249 sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
250 errno = WSAGetLastError();
251 ap_log_error( APLOG_MARK, APLOG_CRIT, errno, server_conf,
252 "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr );
260 static const char *set_secure_listener(cmd_parms *cmd, void *dummy,
261 const char *ips, const char* key,
264 NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
265 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
274 ports = strchr(ips, ':');
278 return "Missing IP address";
279 else if (ports[1] == '\0')
280 return "Address must end in :<port-number>";
288 new = apr_pcalloc(cmd->pool, sizeof(seclisten_rec));
289 new->local_addr.sin_family = AF_INET;
292 new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
293 addr = apr_pstrdup(cmd->pool, "0.0.0.0");
296 new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
297 addr = apr_pstrdup(cmd->pool, ips);
303 return "Port must be numeric";
305 apr_table_set(sc->sltable, ports, "T");
307 new->local_addr.sin_port = htons(port);
310 new->next = ap_seclisteners;
311 strcpy(new->key, key);
312 new->mutual = (mutual) ? 1 : 0;
315 ap_seclisteners = new;
319 static apr_status_t nwssl_socket_cleanup(void *data)
321 ap_listen_rec* slr = (ap_listen_rec*)data;
324 /* Remove our secure listener from the listener list */
325 for (lr = ap_listeners; lr; lr = lr->next) {
326 /* slr is at the head of the list */
328 ap_listeners = slr->next;
331 /* slr is somewhere in between or at the end*/
332 if (lr->next == slr) {
333 lr->next = slr->next;
340 static int nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
343 ap_seclisteners = NULL;
348 static int nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
349 apr_pool_t *ptemp, server_rec *s)
356 for (sl = ap_seclisteners; sl != NULL; sl = sl->next) {
357 sl->fd = find_secure_listener(sl);
360 sl->fd = make_secure_socket(pconf, &sl->local_addr, sl->key, sl->mutual, s);
363 apr_os_sock_info_t sock_info;
365 sock_info.os_sock = &(sl->fd);
366 sock_info.local = (struct sockaddr*)&(sl->local_addr);
367 sock_info.remote = NULL;
368 sock_info.family = APR_INET;
369 sock_info.type = SOCK_STREAM;
371 apr_os_sock_make(&sd, &sock_info, pconf);
373 lr = apr_pcalloc(pconf, sizeof(ap_listen_rec));
377 if ((status = apr_sockaddr_info_get(&lr->bind_addr, sl->addr, APR_UNSPEC, sl->port, 0,
378 pconf)) != APR_SUCCESS) {
379 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf,
380 "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port);
381 return HTTP_INTERNAL_SERVER_ERROR;
383 lr->next = ap_listeners;
385 apr_pool_cleanup_register(pconf, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
388 return HTTP_INTERNAL_SERVER_ERROR;
394 static void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
396 NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
397 new->sltable = apr_table_make(p, 5);
401 static void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
403 NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
404 NWSSLSrvConfigRec *add = (NWSSLSrvConfigRec *)addv;
405 NWSSLSrvConfigRec *merged = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
409 static int isSecure (const request_rec *r)
411 NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
412 const char *s_secure = NULL;
416 itoa(((r->connection)->local_addr)->port, port, 10);
417 s_secure = apr_table_get(sc->sltable, port);
424 static int nwssl_hook_Fixup(request_rec *r)
426 apr_table_t *e = r->subprocess_env;
430 apr_table_set(e, "HTTPS", "on");
435 static const char *nwssl_hook_http_method (const request_rec *r)
443 static const command_rec nwssl_module_cmds[] =
445 AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF,
446 "specify an address and/or port with a key pair name.\n"
447 "Optional third parameter of MUTUAL configures the port for mutual authentication."),
451 static void register_hooks(apr_pool_t *p)
453 ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
454 ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
455 ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
456 ap_hook_http_method(nwssl_hook_http_method, NULL,NULL, APR_HOOK_MIDDLE);
459 module AP_MODULE_DECLARE_DATA nwssl_module =
461 STANDARD20_MODULE_STUFF,
462 NULL, /* dir config creater */
463 NULL, /* dir merger --- default is to override */
464 nwssl_config_server_create, /* server config */
465 nwssl_config_server_merge, /* merge server config */
466 nwssl_module_cmds, /* command apr_table_t */