1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * based on mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
19 *
20 * This module gives Apache the ability to do SSL/TLS with a minimum amount
21 * of effort.  All of the SSL/TLS logic is already on NetWare versions 5 and
22 * above and is interfaced through WinSock on NetWare.  As you can see in
23 * the code below SSL/TLS sockets can be created with three WinSock calls.
24 *
25 * To load, simply place the module in the modules directory under the main
26 * apache tree.  Then add a "SecureListen" with two arguments.  The first
27 * argument is an address and/or port.  The second argument is the key pair
28 * name as created in ConsoleOne.
29 *
30 *  Examples:
31 *
32 *          SecureListen 443 "SSL CertificateIP"
33 *          SecureListen 123.45.67.89:443 mycert
34 *
35 * The module also supports RFC 2817 / TLS Upgrade for HTTP 1.1.
36 * For this add a "NWSSLUpgradeable" with two arguments.  The first
37 * argument is an address and/or port.  The second argument is the key pair
38 * name as created in ConsoleOne.
39 *
40 *  Examples:
41 *
42 *          NWSSLUpgradeable 8080 "SSL CertificateIP"
43 *          NWSSLUpgradeable 123.45.67.89:8080 mycert
44 *
45 */
46
47#define WS_SSL
48
49#define  MAX_ADDRESS  512
50#define  MAX_KEY       80
51
52
53#include "httpd.h"
54#include "http_config.h"
55#include "http_connection.h"
56#include "http_core.h"
57#include "http_log.h"
58#include "http_protocol.h"
59#include "http_request.h"
60#include "ap_listen.h"
61#include "apr_strings.h"
62#include "apr_portable.h"
63#include "apr_optional.h"
64
65#include <unilib.h>
66
67#ifndef SO_TLS_UNCLEAN_SHUTDOWN
68#define SO_TLS_UNCLEAN_SHUTDOWN 0
69#endif
70
71/* The ssl_var_lookup() optional function retrieves SSL environment
72 * variables. */
73APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
74                        (apr_pool_t *, server_rec *,
75                         conn_rec *, request_rec *,
76                         char *));
77
78/* An optional function which returns non-zero if the given connection
79 * is using SSL/TLS. */
80APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
81
82/* The ssl_proxy_enable() and ssl_engine_disable() optional functions
83 * are used by mod_proxy to enable use of SSL for outgoing
84 * connections. */
85APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
86APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
87
88#define strEQ(s1,s2)     (strcmp(s1,s2)        == 0)
89#define strNE(s1,s2)     (strcmp(s1,s2)        != 0)
90#define strEQn(s1,s2,n)  (strncmp(s1,s2,n)     == 0)
91#define strNEn(s1,s2,n)  (strncmp(s1,s2,n)     != 0)
92
93#define strcEQ(s1,s2)    (strcasecmp(s1,s2)    == 0)
94#define strcNE(s1,s2)    (strcasecmp(s1,s2)    != 0)
95#define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0)
96#define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0)
97
98#define strIsEmpty(s)    (s == NULL || s[0] == NUL)
99
100
101module AP_MODULE_DECLARE_DATA nwssl_module;
102
103typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
104typedef struct seclisten_rec seclisten_rec;
105typedef struct seclistenup_rec seclistenup_rec;
106typedef struct secsocket_data secsocket_data;
107
108struct seclisten_rec {
109    seclisten_rec *next;
110    struct sockaddr_in local_addr;   /* local IP address and port */
111    int fd;
112    int used;                        /* Only used during restart */
113    char key[MAX_KEY];
114    int mutual;
115    char *addr;
116    apr_port_t port;
117};
118
119struct seclistenup_rec {
120    seclistenup_rec *next;
121    char key[MAX_KEY];
122    char *addr;
123    apr_port_t port;
124};
125
126struct NWSSLSrvConfigRec {
127    apr_table_t *sltable;
128    apr_table_t *slutable;
129    apr_pool_t *pPool;
130};
131
132struct secsocket_data {
133    apr_socket_t* csd;
134    int is_secure;
135};
136
137static apr_array_header_t *certlist = NULL;
138static unicode_t** certarray = NULL;
139static int numcerts = 0;
140static seclisten_rec* ap_seclisteners = NULL;
141static seclistenup_rec* ap_seclistenersup = NULL;
142
143static ap_listen_rec *nw_old_listeners;
144
145#define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
146
147
148static void build_cert_list(apr_pool_t *p)
149{
150    int i;
151    char **rootcerts = (char **)certlist->elts;
152
153    numcerts = certlist->nelts;
154    certarray = apr_palloc(p, sizeof(unicode_t*)*numcerts);
155
156    for (i = 0; i < numcerts; ++i) {
157        unicode_t *unistr;
158        unistr = (unicode_t*)apr_palloc(p, strlen(rootcerts[i])*4);
159        loc2uni (UNI_LOCAL_DEFAULT, unistr, rootcerts[i], 0, 2);
160        certarray[i] = unistr;
161    }
162}
163
164/*
165 * Parses a host of the form <address>[:port]
166 * :port is permitted if 'port' is not NULL
167 */
168static unsigned long parse_addr(const char *w, unsigned short *ports)
169{
170    struct hostent *hep;
171    unsigned long my_addr;
172    char *p;
173
174    p = strchr(w, ':');
175    if (ports != NULL) {
176        *ports = 0;
177        if (p != NULL && strcmp(p + 1, "*") != 0)
178            *ports = atoi(p + 1);
179    }
180
181    if (p != NULL)
182        *p = '\0';
183    if (strcmp(w, "*") == 0) {
184        if (p != NULL)
185            *p = ':';
186        return htonl(INADDR_ANY);
187    }
188
189    my_addr = apr_inet_addr((char *)w);
190    if (my_addr != INADDR_NONE) {
191        if (p != NULL)
192            *p = ':';
193        return my_addr;
194    }
195
196    hep = gethostbyname(w);
197
198    if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
199        /* XXX Should be echoing by h_errno the actual failure, no?
200         * ap_log_error would be good here.  Better yet - APRize.
201         */
202        fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
203        exit(1);
204    }
205
206    if (hep->h_addr_list[1]) {
207        fprintf(stderr, "Host %s has multiple addresses ---\n", w);
208        fprintf(stderr, "you must choose one explicitly for use as\n");
209        fprintf(stderr, "a secure port.  Exiting!!!\n");
210        exit(1);
211    }
212
213    if (p != NULL)
214        *p = ':';
215
216    return ((struct in_addr *) (hep->h_addr))->s_addr;
217}
218
219static int find_secure_listener(seclisten_rec *lr)
220{
221    seclisten_rec *sl;
222
223    for (sl = ap_seclisteners; sl; sl = sl->next) {
224        if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
225            sl->used = 1;
226            return sl->fd;
227        }
228    }
229    return -1;
230}
231
232static char *get_port_key(conn_rec *c)
233{
234    seclistenup_rec *sl;
235
236    for (sl = ap_seclistenersup; sl; sl = sl->next) {
237        if ((sl->port == (c->local_addr)->port) &&
238            ((strcmp(sl->addr, "0.0.0.0") == 0) ||
239            (strcmp(sl->addr, c->local_ip) == 0))) {
240            return sl->key;
241        }
242    }
243    return NULL;
244}
245
246static int make_secure_socket(apr_pool_t *pconf,
247                              const struct sockaddr_in *server,
248                              char* key, int mutual, server_rec *sconf)
249{
250    int s;
251    char addr[MAX_ADDRESS];
252    struct sslserveropts opts;
253    unsigned int optParam;
254    WSAPROTOCOL_INFO SecureProtoInfo;
255
256    if (server->sin_addr.s_addr != htonl(INADDR_ANY))
257        apr_snprintf(addr, sizeof(addr), "address %s port %d",
258            inet_ntoa(server->sin_addr), ntohs(server->sin_port));
259    else
260        apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
261
262    /* note that because we're about to slack we don't use psocket */
263    memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
264
265    SecureProtoInfo.iAddressFamily = AF_INET;
266    SecureProtoInfo.iSocketType = SOCK_STREAM;
267    SecureProtoInfo.iProtocol = IPPROTO_TCP;
268    SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
269
270    s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
271                  (LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
272
273    if (s == INVALID_SOCKET) {
274        ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
275                     APLOGNO(02120)
276                     "make_secure_socket: failed to get a socket for %s",
277                     addr);
278        return -1;
279    }
280
281    if (!mutual) {
282        optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
283
284        if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
285            sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
286            ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
287                         APLOGNO(02121)
288                         "make_secure_socket: for %s, WSAIoctl: "
289                         "(SO_SSL_SET_FLAGS)", addr);
290            return -1;
291        }
292    }
293
294    opts.cert = key;
295    opts.certlen = strlen(key);
296    opts.sidtimeout = 0;
297    opts.sidentries = 0;
298    opts.siddir = NULL;
299
300    if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
301                 NULL, 0, NULL, NULL, NULL) != 0) {
302        ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
303                     APLOGNO(02122)
304                     "make_secure_socket: for %s, WSAIoctl: "
305                     "(SO_SSL_SET_SERVER)", addr);
306        return -1;
307    }
308
309    if (mutual) {
310        optParam = 0x07;  /* SO_SSL_AUTH_CLIENT */
311
312        if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam, sizeof(optParam),
313                     NULL, 0, NULL, NULL, NULL)) {
314            ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
315                         APLOGNO(02123)
316                         "make_secure_socket: for %s, WSAIoctl: "
317                         "(SO_SSL_SET_FLAGS)", addr);
318            return -1;
319        }
320    }
321
322    optParam = SO_TLS_UNCLEAN_SHUTDOWN;
323    WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam, sizeof(optParam),
324             NULL, 0, NULL, NULL, NULL);
325
326    return s;
327}
328
329static int convert_secure_socket(conn_rec *c, apr_socket_t *csd)
330{
331    int rcode;
332    struct tlsclientopts sWS2Opts;
333    struct nwtlsopts sNWTLSOpts;
334    struct sslserveropts opts;
335    unsigned long ulFlags;
336    SOCKET sock;
337    unicode_t keyFileName[60];
338
339    apr_os_sock_get(&sock, csd);
340
341    /* zero out buffers */
342    memset((char *)&sWS2Opts, 0, sizeof(struct tlsclientopts));
343    memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
344
345    /* turn on ssl for the socket */
346    ulFlags = (numcerts ? SO_TLS_ENABLE : SO_TLS_ENABLE | SO_TLS_BLIND_ACCEPT);
347    rcode = WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
348                     NULL, 0, NULL, NULL, NULL);
349    if (SOCKET_ERROR == rcode) {
350        ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, APLOGNO(02124)
351                     "Error: %d with WSAIoctl(flag SO_TLS_ENABLE)",
352                     WSAGetLastError());
353        return rcode;
354    }
355
356    ulFlags = SO_TLS_UNCLEAN_SHUTDOWN;
357    WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
358             NULL, 0, NULL, NULL, NULL);
359
360    /* setup the socket for SSL */
361    memset (&sWS2Opts, 0, sizeof(sWS2Opts));
362    memset (&sNWTLSOpts, 0, sizeof(sNWTLSOpts));
363    sWS2Opts.options = &sNWTLSOpts;
364
365    if (numcerts) {
366        sNWTLSOpts.walletProvider = WAL_PROV_DER;   /* the wallet provider defined in wdefs.h */
367        sNWTLSOpts.TrustedRootList = certarray;     /* array of certs in UNICODE format       */
368        sNWTLSOpts.numElementsInTRList = numcerts;  /* number of certs in TRList              */
369    }
370    else {
371        /* setup the socket for SSL */
372        unicpy(keyFileName, L"SSL CertificateIP");
373        sWS2Opts.wallet = keyFileName;              /* no client certificate */
374        sWS2Opts.walletlen = unilen(keyFileName);
375
376        sNWTLSOpts.walletProvider = WAL_PROV_KMO;   /* the wallet provider defined in wdefs.h */
377    }
378
379    /* make the IOCTL call */
380    rcode = WSAIoctl(sock, SO_TLS_SET_CLIENT, &sWS2Opts,
381                     sizeof(struct tlsclientopts), NULL, 0, NULL,
382                     NULL, NULL);
383
384    /* make sure that it was successful */
385    if (SOCKET_ERROR == rcode ) {
386    ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, APLOGNO(02125)
387                 "Error: %d with WSAIoctl(SO_TLS_SET_CLIENT)",
388                 WSAGetLastError());
389    }
390    return rcode;
391}
392
393static int SSLize_Socket(SOCKET socketHnd, char *key, request_rec *r)
394{
395    int rcode;
396    struct tlsserveropts sWS2Opts;
397    struct nwtlsopts    sNWTLSOpts;
398    unicode_t SASKey[512];
399    unsigned long ulFlag;
400
401    memset((char *)&sWS2Opts, 0, sizeof(struct tlsserveropts));
402    memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
403
404    ulFlag = SO_TLS_ENABLE;
405    rcode = WSAIoctl(socketHnd, SO_TLS_SET_FLAGS, &ulFlag,
406                     sizeof(unsigned long), NULL, 0, NULL, NULL, NULL);
407    if(rcode) {
408        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02126)
409                     "Error: %d with WSAIoctl(SO_TLS_SET_FLAGS, SO_TLS_ENABLE)",
410                     WSAGetLastError());
411        goto ERR;
412    }
413
414
415    ulFlag = SO_TLS_SERVER;
416    rcode = WSAIoctl(socketHnd, SO_TLS_SET_FLAGS, &ulFlag,
417                     sizeof(unsigned long),NULL, 0, NULL, NULL, NULL);
418
419    if (rcode) {
420        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02127)
421                     "Error: %d with WSAIoctl(SO_TLS_SET_FLAGS, SO_TLS_SERVER)",
422                     WSAGetLastError());
423        goto ERR;
424    }
425
426    loc2uni(UNI_LOCAL_DEFAULT, SASKey, key, 0, 0);
427
428    /* setup the tlsserveropts struct */
429    sWS2Opts.wallet = SASKey;
430    sWS2Opts.walletlen = unilen(SASKey);
431    sWS2Opts.sidtimeout = 0;
432    sWS2Opts.sidentries = 0;
433    sWS2Opts.siddir = NULL;
434    sWS2Opts.options = &sNWTLSOpts;
435
436    /* setup the nwtlsopts structure */
437
438    sNWTLSOpts.walletProvider               = WAL_PROV_KMO;
439    sNWTLSOpts.keysList                     = NULL;
440    sNWTLSOpts.numElementsInKeyList         = 0;
441    sNWTLSOpts.reservedforfutureuse         = NULL;
442    sNWTLSOpts.reservedforfutureCRL         = NULL;
443    sNWTLSOpts.reservedforfutureCRLLen      = 0;
444    sNWTLSOpts.reserved1                    = NULL;
445    sNWTLSOpts.reserved2                    = NULL;
446    sNWTLSOpts.reserved3                    = NULL;
447
448    rcode = WSAIoctl(socketHnd,
449                     SO_TLS_SET_SERVER,
450                     &sWS2Opts,
451                     sizeof(struct tlsserveropts),
452                     NULL,
453                     0,
454                     NULL,
455                     NULL,
456                     NULL);
457    if (SOCKET_ERROR == rcode) {
458        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02128)
459                     "Error: %d with WSAIoctl(SO_TLS_SET_SERVER)", WSAGetLastError());
460        goto ERR;
461    }
462
463ERR:
464    return rcode;
465}
466
467static const char *set_secure_listener(cmd_parms *cmd, void *dummy,
468                                       const char *ips, const char* key,
469                                       const char* mutual)
470{
471    NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
472    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
473    char *ports, *addr;
474    unsigned short port;
475    seclisten_rec *new;
476    ap_listen_rec **walk;
477    apr_sockaddr_t *sa;
478    int found_listener = 0;
479
480
481    if (err != NULL)
482        return err;
483
484    ports = strchr(ips, ':');
485
486    if (ports != NULL) {
487        if (ports == ips)
488            return "Missing IP address";
489        else if (ports[1] == '\0')
490            return "Address must end in :<port-number>";
491
492        *(ports++) = '\0';
493    }
494    else {
495        ports = (char*)ips;
496    }
497
498    new = apr_pcalloc(cmd->server->process->pool, sizeof(seclisten_rec));
499    new->local_addr.sin_family = AF_INET;
500
501    if (ports == ips) {
502        new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
503        addr = apr_pstrdup(cmd->server->process->pool, "0.0.0.0");
504    }
505    else {
506        new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
507        addr = apr_pstrdup(cmd->server->process->pool, ips);
508    }
509
510    port = atoi(ports);
511
512    if (!port)
513        return "Port must be numeric";
514
515    /* If the specified addr:port was created previously, put the listen
516       socket record back on the ap_listeners list so that the socket
517       will be reused rather than recreated */
518    for (walk = &nw_old_listeners; *walk;) {
519        sa = (*walk)->bind_addr;
520        if (sa) {
521            ap_listen_rec *new;
522            apr_port_t oldport;
523
524            oldport = sa->port;
525            /* If both ports are equivalent, then if their names are equivalent,
526             * then we will re-use the existing record.
527             */
528            if (port == oldport &&
529                ((!addr && !sa->hostname) ||
530                 ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
531                new = *walk;
532                *walk = new->next;
533                new->next = ap_listeners;
534                ap_listeners = new;
535                found_listener = 1;
536                continue;
537            }
538        }
539
540        walk = &(*walk)->next;
541    }
542
543    apr_table_add(sc->sltable, ports, addr);
544
545    /* If we found a pre-existing listen socket record, then there
546       is no need to create a new secure listen socket record. */
547    if (found_listener) {
548        return NULL;
549    }
550
551    new->local_addr.sin_port = htons(port);
552    new->fd = -1;
553    new->used = 0;
554    new->next = ap_seclisteners;
555    strcpy(new->key, key);
556    new->mutual = (mutual) ? 1 : 0;
557    new->addr = addr;
558    new->port = port;
559    ap_seclisteners = new;
560    return NULL;
561}
562
563static const char *set_secure_upgradeable_listener(cmd_parms *cmd, void *dummy,
564                                       const char *ips, const char* key)
565{
566    NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
567    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
568    char *ports, *addr;
569    unsigned short port;
570    seclistenup_rec *new;
571
572    if (err != NULL)
573        return err;
574
575    ports = strchr(ips, ':');
576
577    if (ports != NULL) {
578        if (ports == ips)
579            return "Missing IP address";
580        else if (ports[1] == '\0')
581            return "Address must end in :<port-number>";
582
583        *(ports++) = '\0';
584    }
585    else {
586        ports = (char*)ips;
587    }
588
589    if (ports == ips) {
590        addr = apr_pstrdup(cmd->pool, "0.0.0.0");
591    }
592    else {
593        addr = apr_pstrdup(cmd->pool, ips);
594    }
595
596    port = atoi(ports);
597
598    if (!port)
599        return "Port must be numeric";
600
601    apr_table_set(sc->slutable, ports, addr);
602
603    new = apr_pcalloc(cmd->pool, sizeof(seclistenup_rec));
604    new->next = ap_seclistenersup;
605    strcpy(new->key, key);
606    new->addr = addr;
607    new->port = port;
608    ap_seclistenersup = new;
609
610    return err;
611}
612
613static apr_status_t nwssl_socket_cleanup(void *data)
614{
615    ap_listen_rec* slr = (ap_listen_rec*)data;
616    ap_listen_rec* lr;
617
618    /* Remove our secure listener from the listener list */
619    for (lr = ap_listeners; lr; lr = lr->next) {
620        /* slr is at the head of the list */
621        if (lr == slr) {
622            ap_listeners = slr->next;
623            break;
624        }
625        /* slr is somewhere in between or at the end*/
626        if (lr->next == slr) {
627            lr->next = slr->next;
628            break;
629        }
630    }
631    return APR_SUCCESS;
632}
633
634static const char *set_trusted_certs(cmd_parms *cmd, void *dummy, char *arg)
635{
636    char **ptr = (char **)apr_array_push(certlist);
637
638    *ptr = apr_pstrdup(cmd->pool, arg);
639    return NULL;
640}
641
642static int nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
643                         apr_pool_t *ptemp)
644{
645    seclisten_rec* ap_old_seclisteners;
646    ap_listen_rec **walk;
647    seclisten_rec **secwalk;
648    apr_sockaddr_t *sa;
649    int found;
650
651    /* Pull all of the listeners that were created by mod_nw_ssl out of the
652       ap_listeners list so that the normal listen socket processing does
653       automatically close them */
654    nw_old_listeners = NULL;
655    ap_old_seclisteners = NULL;
656
657    for (secwalk = &ap_seclisteners; *secwalk;) {
658        found = 0;
659        for (walk = &ap_listeners; *walk;) {
660            sa = (*walk)->bind_addr;
661            if (sa) {
662                ap_listen_rec *new;
663                seclisten_rec *secnew;
664                apr_port_t oldport;
665
666                oldport = sa->port;
667                /* If both ports are equivalent, then if their names are equivalent,
668                 * then we will re-use the existing record.
669                 */
670                if ((*secwalk)->port == oldport &&
671                    ((!(*secwalk)->addr && !sa->hostname) ||
672                     (((*secwalk)->addr && sa->hostname) && !strcmp(sa->hostname, (*secwalk)->addr)))) {
673                    /* Move the listen socket from ap_listeners to nw_old_listeners */
674                    new = *walk;
675                    *walk = new->next;
676                    new->next = nw_old_listeners;
677                    nw_old_listeners = new;
678
679                    /* Move the secure socket record to ap_old_seclisterners */
680                    secnew = *secwalk;
681                    *secwalk = secnew->next;
682                    secnew->next = ap_old_seclisteners;
683                    ap_old_seclisteners = secnew;
684                    found = 1;
685                    break;
686                }
687            }
688
689            walk = &(*walk)->next;
690        }
691        if (!found && &(*secwalk)->next) {
692            secwalk = &(*secwalk)->next;
693        }
694    }
695
696    /* Restore the secure socket records list so that the post config can
697       process all of the sockets normally */
698    ap_seclisteners = ap_old_seclisteners;
699    ap_seclistenersup = NULL;
700    certlist = apr_array_make(pconf, 1, sizeof(char *));
701
702    /* Now that we have removed all of the mod_nw_ssl created socket records,
703       allow the normal listen socket handling to occur.
704       NOTE: If for any reason mod_nw_ssl is removed as a built-in module,
705       the following call must be put back into the pre-config handler of the
706       MPM.  It is only here to ensure that mod_nw_ssl fixes up the listen
707       socket list before anything else looks at it. */
708    ap_listen_pre_config();
709
710    return OK;
711}
712
713static int nwssl_pre_connection(conn_rec *c, void *csd)
714{
715
716    if (apr_table_get(c->notes, "nwconv-ssl")) {
717        convert_secure_socket(c, (apr_socket_t*)csd);
718    }
719    else {
720        secsocket_data *csd_data = apr_palloc(c->pool, sizeof(secsocket_data));
721
722        csd_data->csd = (apr_socket_t*)csd;
723        csd_data->is_secure = 0;
724        ap_set_module_config(c->conn_config, &nwssl_module, (void*)csd_data);
725    }
726
727    return OK;
728}
729
730static int nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
731                          apr_pool_t *ptemp, server_rec *s)
732{
733    seclisten_rec* sl;
734    ap_listen_rec* lr;
735    apr_socket_t*  sd;
736    apr_status_t status;
737    seclistenup_rec *slu;
738    int found;
739    ap_listen_rec *walk;
740    seclisten_rec *secwalk, *lastsecwalk;
741    apr_sockaddr_t *sa;
742
743    /* Walk the old listeners list and compare it to the secure
744       listeners list and remove any secure listener records that
745       are not being reused */
746    for (walk = nw_old_listeners; walk; walk = walk->next) {
747        sa = walk->bind_addr;
748        if (sa) {
749            ap_listen_rec *new;
750            apr_port_t oldport;
751
752            oldport = sa->port;
753            for (secwalk = ap_seclisteners, lastsecwalk = ap_seclisteners; secwalk; secwalk = lastsecwalk->next) {
754                unsigned short port = secwalk->port;
755                char *addr = secwalk->addr;
756                /* If both ports are equivalent, then if their names are equivalent,
757                 * then we will re-use the existing record.
758                 */
759                if (port == oldport &&
760                    ((!addr && !sa->hostname) ||
761                     ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
762                    if (secwalk == ap_seclisteners) {
763                        ap_seclisteners = secwalk->next;
764                    }
765                    else {
766                        lastsecwalk->next = secwalk->next;
767                    }
768                    apr_socket_close(walk->sd);
769                    walk->active = 0;
770                    break;
771                }
772                else {
773                    lastsecwalk = secwalk;
774                }
775            }
776        }
777    }
778
779    for (sl = ap_seclisteners; sl != NULL; sl = sl->next) {
780        /* If we find a pre-existing listen socket and it has already been
781           created, then no neeed to go any further, just reuse it. */
782        if (((sl->fd = find_secure_listener(sl)) >= 0) && (sl->used)) {
783            continue;
784        }
785
786        if (sl->fd < 0)
787            sl->fd = make_secure_socket(s->process->pool, &sl->local_addr, sl->key, sl->mutual, s);
788
789        if (sl->fd >= 0) {
790            apr_os_sock_info_t sock_info;
791
792            sock_info.os_sock = &(sl->fd);
793            sock_info.local = (struct sockaddr*)&(sl->local_addr);
794            sock_info.remote = NULL;
795            sock_info.family = APR_INET;
796            sock_info.type = SOCK_STREAM;
797
798            apr_os_sock_make(&sd, &sock_info, s->process->pool);
799
800            lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
801
802            if (lr) {
803                lr->sd = sd;
804                if ((status = apr_sockaddr_info_get(&lr->bind_addr, sl->addr, APR_UNSPEC, sl->port, 0,
805                                              s->process->pool)) != APR_SUCCESS) {
806                    ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf, APLOGNO(02129)
807                                 "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port);
808                    return HTTP_INTERNAL_SERVER_ERROR;
809                }
810                lr->next = ap_listeners;
811                ap_listeners = lr;
812                apr_pool_cleanup_register(s->process->pool, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
813            }
814        } else {
815            return HTTP_INTERNAL_SERVER_ERROR;
816        }
817    }
818
819    for (slu = ap_seclistenersup; slu; slu = slu->next) {
820        /* Check the listener list for a matching upgradeable listener */
821        found = 0;
822        for (lr = ap_listeners; lr; lr = lr->next) {
823            if (slu->port == lr->bind_addr->port) {
824                found = 1;
825                break;
826            }
827        }
828        if (!found) {
829            ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, plog, APLOGNO(02130)
830                         "No Listen directive found for upgradeable listener %s:%d", slu->addr, slu->port);
831        }
832    }
833
834    build_cert_list(s->process->pool);
835
836    return OK;
837}
838
839static void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
840{
841    NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
842    new->sltable = apr_table_make(p, 5);
843    new->slutable = apr_table_make(p, 5);
844    return new;
845}
846
847static void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
848{
849    NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
850    NWSSLSrvConfigRec *add  = (NWSSLSrvConfigRec *)addv;
851    NWSSLSrvConfigRec *merged  = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
852    return merged;
853}
854
855static int compare_ipports(void *rec, const char *key, const char *value)
856{
857    conn_rec *c = (conn_rec*)rec;
858
859    if (value &&
860        ((strcmp(value, "0.0.0.0") == 0) || (strcmp(value, c->local_ip) == 0)))
861    {
862        return 0;
863    }
864    return 1;
865}
866
867static int isSecureConnEx (const server_rec *s, const conn_rec *c, const apr_table_t *t)
868{
869    char port[8];
870
871    itoa((c->local_addr)->port, port, 10);
872    if (!apr_table_do(compare_ipports, (void*)c, t, port, NULL)) {
873        return 1;
874    }
875
876    return 0;
877}
878
879static int isSecureConn (const server_rec *s, const conn_rec *c)
880{
881    NWSSLSrvConfigRec *sc = get_nwssl_cfg(s);
882
883    return isSecureConnEx (s, c, sc->sltable);
884}
885
886static int isSecureConnUpgradeable (const server_rec *s, const conn_rec *c)
887{
888    NWSSLSrvConfigRec *sc = get_nwssl_cfg(s);
889
890    return isSecureConnEx (s, c, sc->slutable);
891}
892
893static int isSecure (const request_rec *r)
894{
895    return isSecureConn (r->server, r->connection);
896}
897
898static int isSecureUpgradeable (const request_rec *r)
899{
900    return isSecureConnUpgradeable (r->server, r->connection);
901}
902
903static int isSecureUpgraded (const request_rec *r)
904{
905    secsocket_data *csd_data = (secsocket_data*)ap_get_module_config(r->connection->conn_config, &nwssl_module);
906
907    return csd_data->is_secure;
908}
909
910static int nwssl_hook_Fixup(request_rec *r)
911{
912    if (!isSecure(r) && !isSecureUpgraded(r))
913        return DECLINED;
914
915    apr_table_setn(r->subprocess_env, "HTTPS", "on");
916
917    return DECLINED;
918}
919
920static const char *nwssl_hook_http_scheme(const request_rec *r)
921{
922    if (isSecure(r) && !isSecureUpgraded(r))
923        return "https";
924
925    return NULL;
926}
927
928static apr_port_t nwssl_hook_default_port(const request_rec *r)
929{
930    if (isSecure(r))
931        return DEFAULT_HTTPS_PORT;
932
933    return 0;
934}
935
936int ssl_proxy_enable(conn_rec *c)
937{
938    apr_table_setn(c->notes, "nwconv-ssl", "Y");
939
940    return 1;
941}
942
943int ssl_engine_disable(conn_rec *c)
944{
945    return 1;
946}
947
948static int ssl_is_https(conn_rec *c)
949{
950    secsocket_data *csd_data = (secsocket_data*)ap_get_module_config(c->conn_config, &nwssl_module);
951
952    return isSecureConn (c->base_server, c) || (csd_data && csd_data->is_secure);
953}
954
955/* This function must remain safe to use for a non-SSL connection. */
956char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
957{
958    NWSSLSrvConfigRec *mc = get_nwssl_cfg(s);
959    const char *result;
960    BOOL resdup;
961    apr_time_exp_t tm;
962
963    result = NULL;
964    resdup = TRUE;
965
966    /*
967     * When no pool is given try to find one
968     */
969    if (p == NULL) {
970        if (r != NULL)
971            p = r->pool;
972        else if (c != NULL)
973            p = c->pool;
974        else
975            p = mc->pPool;
976    }
977
978    /*
979     * Request dependent stuff
980     */
981    if (r != NULL) {
982        switch (var[0]) {
983        case 'H':
984        case 'h':
985            if (strcEQ(var, "HTTP_USER_AGENT"))
986                result = apr_table_get(r->headers_in, "User-Agent");
987            else if (strcEQ(var, "HTTP_REFERER"))
988                result = apr_table_get(r->headers_in, "Referer");
989            else if (strcEQ(var, "HTTP_COOKIE"))
990                result = apr_table_get(r->headers_in, "Cookie");
991            else if (strcEQ(var, "HTTP_FORWARDED"))
992                result = apr_table_get(r->headers_in, "Forwarded");
993            else if (strcEQ(var, "HTTP_HOST"))
994                result = apr_table_get(r->headers_in, "Host");
995            else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
996                result = apr_table_get(r->headers_in, "Proxy-Connection");
997            else if (strcEQ(var, "HTTP_ACCEPT"))
998                result = apr_table_get(r->headers_in, "Accept");
999            else if (strcEQ(var, "HTTPS")) {
1000                if (isSecure(r) || isSecureUpgraded(r))
1001                    result = "on";
1002                else
1003                    result = "off";
1004            }
1005            else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
1006                /* all other headers from which we are still not know about */
1007                result = apr_table_get(r->headers_in, var+5);
1008            break;
1009
1010        case 'R':
1011        case 'r':
1012            if (strcEQ(var, "REQUEST_METHOD"))
1013                result = r->method;
1014            else if (strcEQ(var, "REQUEST_SCHEME"))
1015                result = ap_http_scheme(r);
1016            else if (strcEQ(var, "REQUEST_URI"))
1017                result = r->uri;
1018            else if (strcEQ(var, "REQUEST_FILENAME"))
1019                result = r->filename;
1020            else if (strcEQ(var, "REMOTE_ADDR"))
1021                result = r->useragent_ip;
1022            else if (strcEQ(var, "REMOTE_HOST"))
1023                result = ap_get_remote_host(r->connection, r->per_dir_config,
1024                                            REMOTE_NAME, NULL);
1025            else if (strcEQ(var, "REMOTE_IDENT"))
1026                result = ap_get_remote_logname(r);
1027            else if (strcEQ(var, "REMOTE_USER"))
1028                result = r->user;
1029            break;
1030
1031        case 'S':
1032        case 's':
1033            if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
1034
1035            if (strcEQ(var, "SERVER_ADMIN"))
1036                result = r->server->server_admin;
1037            else if (strcEQ(var, "SERVER_NAME"))
1038                result = ap_get_server_name_for_url(r);
1039            else if (strcEQ(var, "SERVER_PORT"))
1040                result = apr_psprintf(p, "%u", ap_get_server_port(r));
1041            else if (strcEQ(var, "SERVER_PROTOCOL"))
1042                result = r->protocol;
1043            else if (strcEQ(var, "SCRIPT_FILENAME"))
1044                result = r->filename;
1045            break;
1046
1047        default:
1048            if (strcEQ(var, "PATH_INFO"))
1049                result = r->path_info;
1050            else if (strcEQ(var, "QUERY_STRING"))
1051                result = r->args;
1052            else if (strcEQ(var, "IS_SUBREQ"))
1053                result = (r->main != NULL ? "true" : "false");
1054            else if (strcEQ(var, "DOCUMENT_ROOT"))
1055                result = ap_document_root(r);
1056            else if (strcEQ(var, "AUTH_TYPE"))
1057                result = r->ap_auth_type;
1058            else if (strcEQ(var, "THE_REQUEST"))
1059                result = r->the_request;
1060            break;
1061        }
1062    }
1063
1064    /*
1065     * Connection stuff
1066     */
1067    if (result == NULL && c != NULL) {
1068        /* XXX-Can't get specific SSL info from NetWare */
1069        /* SSLConnRec *sslconn = myConnConfig(c);
1070        if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
1071            && sslconn && sslconn->ssl)
1072            result = ssl_var_lookup_ssl(p, c, var+4);*/
1073
1074        if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
1075            result = NULL;
1076    }
1077
1078    /*
1079     * Totally independent stuff
1080     */
1081    if (result == NULL) {
1082        if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
1083            result = NULL;
1084            /* XXX-Can't get specific SSL info from NetWare */
1085            /*result = ssl_var_lookup_ssl_version(p, var+12);*/
1086        else if (strcEQ(var, "SERVER_SOFTWARE"))
1087            result = ap_get_server_banner();
1088        else if (strcEQ(var, "API_VERSION")) {
1089            result = apr_itoa(p, MODULE_MAGIC_NUMBER);
1090            resdup = FALSE;
1091        }
1092        else if (strcEQ(var, "TIME_YEAR")) {
1093            apr_time_exp_lt(&tm, apr_time_now());
1094            result = apr_psprintf(p, "%02d%02d",
1095                                 (tm.tm_year / 100) + 19, tm.tm_year % 100);
1096            resdup = FALSE;
1097        }
1098#define MKTIMESTR(format, tmfield) \
1099            apr_time_exp_lt(&tm, apr_time_now()); \
1100            result = apr_psprintf(p, format, tm.tmfield); \
1101            resdup = FALSE;
1102        else if (strcEQ(var, "TIME_MON")) {
1103            MKTIMESTR("%02d", tm_mon+1)
1104        }
1105        else if (strcEQ(var, "TIME_DAY")) {
1106            MKTIMESTR("%02d", tm_mday)
1107        }
1108        else if (strcEQ(var, "TIME_HOUR")) {
1109            MKTIMESTR("%02d", tm_hour)
1110        }
1111        else if (strcEQ(var, "TIME_MIN")) {
1112            MKTIMESTR("%02d", tm_min)
1113        }
1114        else if (strcEQ(var, "TIME_SEC")) {
1115            MKTIMESTR("%02d", tm_sec)
1116        }
1117        else if (strcEQ(var, "TIME_WDAY")) {
1118            MKTIMESTR("%d", tm_wday)
1119        }
1120        else if (strcEQ(var, "TIME")) {
1121            apr_time_exp_lt(&tm, apr_time_now());
1122            result = apr_psprintf(p,
1123                        "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
1124                        (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
1125                        tm.tm_hour, tm.tm_min, tm.tm_sec);
1126            resdup = FALSE;
1127        }
1128        /* all other env-variables from the parent Apache process */
1129        else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
1130            result = apr_table_get(r->notes, var+4);
1131            if (result == NULL)
1132                result = apr_table_get(r->subprocess_env, var+4);
1133            if (result == NULL)
1134                result = getenv(var+4);
1135        }
1136    }
1137
1138    if (result != NULL && resdup)
1139        result = apr_pstrdup(p, result);
1140    if (result == NULL)
1141        result = "";
1142    return (char *)result;
1143}
1144
1145#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
1146#define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
1147#define CONNECTION_HEADER "Connection: Upgrade"
1148
1149static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
1150                                          apr_bucket_brigade *bb)
1151
1152{
1153    const char *upgrade;
1154    apr_bucket_brigade *upgradebb;
1155    request_rec *r = f->r;
1156    apr_socket_t *csd = NULL;
1157    char *key;
1158    int ret;
1159    secsocket_data *csd_data;
1160    apr_bucket *b;
1161    apr_status_t rv;
1162
1163    /* Just remove the filter, if it doesn't work the first time, it won't
1164     * work at all for this request.
1165     */
1166    ap_remove_output_filter(f);
1167
1168    if (!r) {
1169        /*
1170        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02131)
1171                     "Unable to get upgradeable socket handle");
1172        */
1173        return ap_pass_brigade(f->next, bb);
1174    }
1175
1176    /* No need to ensure that this is a server with optional SSL, the filter
1177     * is only inserted if that is true.
1178     */
1179
1180    upgrade = apr_table_get(r->headers_in, "Upgrade");
1181    if (upgrade == NULL
1182        || strcmp(ap_getword(r->pool, &upgrade, ','), "TLS/1.0")) {
1183            /* "Upgrade: TLS/1.0, ..." header not found, don't do Upgrade */
1184        return ap_pass_brigade(f->next, bb);
1185    }
1186
1187    apr_table_unset(r->headers_out, "Upgrade");
1188
1189    csd_data = (secsocket_data*)ap_get_module_config(r->connection->conn_config, &nwssl_module);
1190    csd = csd_data->csd;
1191
1192    /* Send the interim 101 response. */
1193    upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1194
1195    ap_fputstrs(f->next, upgradebb, SWITCH_STATUS_LINE, CRLF,
1196                UPGRADE_HEADER, CRLF, CONNECTION_HEADER, CRLF, CRLF, NULL);
1197
1198    b = apr_bucket_flush_create(f->c->bucket_alloc);
1199    APR_BRIGADE_INSERT_TAIL(upgradebb, b);
1200
1201    rv = ap_pass_brigade(f->next, upgradebb);
1202    if (rv) {
1203        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02132)
1204                      "could not send interim 101 Upgrade response");
1205        return AP_FILTER_ERROR;
1206    }
1207
1208    key = get_port_key(r->connection);
1209
1210    if (csd && key) {
1211        int sockdes;
1212        apr_os_sock_get(&sockdes, csd);
1213
1214
1215        ret = SSLize_Socket(sockdes, key, r);
1216        if (!ret) {
1217            csd_data->is_secure = 1;
1218        }
1219    }
1220    else {
1221        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02133)
1222                     "Upgradeable socket handle not found");
1223        return AP_FILTER_ERROR;
1224    }
1225
1226    ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, APLOGNO(02134)
1227                 "Awaiting re-negotiation handshake");
1228
1229    /* Now that we have initialized the ssl connection which added the ssl_io_filter,
1230       pass the brigade off to the connection based output filters so that the
1231       request can complete encrypted */
1232    return ap_pass_brigade(f->c->output_filters, bb);
1233}
1234
1235static void ssl_hook_Insert_Filter(request_rec *r)
1236{
1237    NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
1238
1239    if (isSecureUpgradeable (r)) {
1240        ap_add_output_filter("UPGRADE_FILTER", NULL, r, r->connection);
1241    }
1242}
1243
1244static const command_rec nwssl_module_cmds[] =
1245{
1246    AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF,
1247      "specify an address and/or port with a key pair name.\n"
1248      "Optional third parameter of MUTUAL configures the port for mutual authentication."),
1249    AP_INIT_TAKE2("NWSSLUpgradeable", set_secure_upgradeable_listener, NULL, RSRC_CONF,
1250      "specify an address and/or port with a key pair name, that can be upgraded to an SSL connection.\n"
1251      "The address and/or port must have already be defined using a Listen directive."),
1252    AP_INIT_ITERATE("NWSSLTrustedCerts", set_trusted_certs, NULL, RSRC_CONF,
1253        "Adds trusted certificates that are used to create secure connections to proxied servers"),
1254    {NULL}
1255};
1256
1257static void register_hooks(apr_pool_t *p)
1258{
1259    ap_register_output_filter ("UPGRADE_FILTER", ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
1260
1261    ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
1262    ap_hook_pre_connection(nwssl_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
1263    ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1264    ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
1265    ap_hook_http_scheme(nwssl_hook_http_scheme, NULL, NULL, APR_HOOK_MIDDLE);
1266    ap_hook_default_port(nwssl_hook_default_port, NULL, NULL, APR_HOOK_MIDDLE);
1267    ap_hook_insert_filter(ssl_hook_Insert_Filter, NULL, NULL, APR_HOOK_MIDDLE);
1268
1269    APR_REGISTER_OPTIONAL_FN(ssl_is_https);
1270    APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
1271
1272    APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
1273    APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
1274}
1275
1276AP_DECLARE_MODULE(nwssl) =
1277{
1278    STANDARD20_MODULE_STUFF,
1279    NULL,                       /* dir config creater */
1280    NULL,                       /* dir merger --- default is to override */
1281    nwssl_config_server_create, /* server config */
1282    nwssl_config_server_merge,  /* merge server config */
1283    nwssl_module_cmds,          /* command apr_table_t */
1284    register_hooks
1285};
1286
1287