]> granicus.if.org Git - apache/blob - modules/arch/netware/mod_nw_ssl.c
Fix alignment in a <highlight> block.
[apache] / modules / arch / netware / mod_nw_ssl.c
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. */
73 APR_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. */
80 APR_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. */
85 APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
86 APR_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
101 module AP_MODULE_DECLARE_DATA nwssl_module;
102
103 typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
104 typedef struct seclisten_rec seclisten_rec;
105 typedef struct seclistenup_rec seclistenup_rec;
106 typedef struct secsocket_data secsocket_data;
107
108 struct 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
119 struct seclistenup_rec {
120     seclistenup_rec *next;
121     char key[MAX_KEY];
122     char *addr;
123     apr_port_t port;
124 };
125
126 struct NWSSLSrvConfigRec {
127     apr_table_t *sltable;
128     apr_table_t *slutable;
129     apr_pool_t *pPool;
130 };
131
132 struct secsocket_data {
133     apr_socket_t* csd;
134     int is_secure;
135 };
136
137 static apr_array_header_t *certlist = NULL;
138 static unicode_t** certarray = NULL;
139 static int numcerts = 0;
140 static seclisten_rec* ap_seclisteners = NULL;
141 static seclistenup_rec* ap_seclistenersup = NULL;
142
143 static 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
148 static 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  */
168 static 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
219 static 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
232 static 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
246 static 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
329 static 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
393 static 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
463 ERR:
464     return rcode;
465 }
466
467 static 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
563 static 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
613 static 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
634 static const char *set_trusted_certs(cmd_parms *cmd, void *dummy, char *arg)
635 {
636     char **ptr = (char **)apr_array_push(certlist);
637
638     *ptr = arg;
639     return NULL;
640 }
641
642 static 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
713 static 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
730 static 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 need 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
839 static 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
847 static 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
855 static 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
867 static 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
879 static 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
886 static 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
893 static int isSecure (const request_rec *r)
894 {
895     return isSecureConn (r->server, r->connection);
896 }
897
898 static int isSecureUpgradeable (const request_rec *r)
899 {
900     return isSecureConnUpgradeable (r->server, r->connection);
901 }
902
903 static 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
910 static 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
920 static 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
928 static 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
936 int ssl_proxy_enable(conn_rec *c)
937 {
938     apr_table_setn(c->notes, "nwconv-ssl", "Y");
939
940     return 1;
941 }
942
943 int ssl_engine_disable(conn_rec *c)
944 {
945     return 1;
946 }
947
948 static 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. */
956 char *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_useragent_host(r, REMOTE_NAME, NULL);
1024             else if (strcEQ(var, "REMOTE_IDENT"))
1025                 result = ap_get_remote_logname(r);
1026             else if (strcEQ(var, "REMOTE_USER"))
1027                 result = r->user;
1028             break;
1029
1030         case 'S':
1031         case 's':
1032             if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
1033
1034             if (strcEQ(var, "SERVER_ADMIN"))
1035                 result = r->server->server_admin;
1036             else if (strcEQ(var, "SERVER_NAME"))
1037                 result = ap_get_server_name_for_url(r);
1038             else if (strcEQ(var, "SERVER_PORT"))
1039                 result = apr_psprintf(p, "%u", ap_get_server_port(r));
1040             else if (strcEQ(var, "SERVER_PROTOCOL"))
1041                 result = r->protocol;
1042             else if (strcEQ(var, "SCRIPT_FILENAME"))
1043                 result = r->filename;
1044             break;
1045
1046         default:
1047             if (strcEQ(var, "PATH_INFO"))
1048                 result = r->path_info;
1049             else if (strcEQ(var, "QUERY_STRING"))
1050                 result = r->args;
1051             else if (strcEQ(var, "IS_SUBREQ"))
1052                 result = (r->main != NULL ? "true" : "false");
1053             else if (strcEQ(var, "DOCUMENT_ROOT"))
1054                 result = ap_document_root(r);
1055             else if (strcEQ(var, "AUTH_TYPE"))
1056                 result = r->ap_auth_type;
1057             else if (strcEQ(var, "THE_REQUEST"))
1058                 result = r->the_request;
1059             break;
1060         }
1061     }
1062
1063     /*
1064      * Connection stuff
1065      */
1066     if (result == NULL && c != NULL) {
1067         /* XXX-Can't get specific SSL info from NetWare */
1068         /* SSLConnRec *sslconn = myConnConfig(c);
1069         if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
1070             && sslconn && sslconn->ssl)
1071             result = ssl_var_lookup_ssl(p, c, var+4);*/
1072
1073         if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
1074             result = NULL;
1075     }
1076
1077     /*
1078      * Totally independent stuff
1079      */
1080     if (result == NULL) {
1081         if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
1082             result = NULL;
1083             /* XXX-Can't get specific SSL info from NetWare */
1084             /*result = ssl_var_lookup_ssl_version(p, var+12);*/
1085         else if (strcEQ(var, "SERVER_SOFTWARE"))
1086             result = ap_get_server_banner();
1087         else if (strcEQ(var, "API_VERSION")) {
1088             result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR);
1089             resdup = FALSE;
1090         }
1091         else if (strcEQ(var, "TIME_YEAR")) {
1092             apr_time_exp_lt(&tm, apr_time_now());
1093             result = apr_psprintf(p, "%02d%02d",
1094                                  (tm.tm_year / 100) + 19, tm.tm_year % 100);
1095             resdup = FALSE;
1096         }
1097 #define MKTIMESTR(format, tmfield) \
1098             apr_time_exp_lt(&tm, apr_time_now()); \
1099             result = apr_psprintf(p, format, tm.tmfield); \
1100             resdup = FALSE;
1101         else if (strcEQ(var, "TIME_MON")) {
1102             MKTIMESTR("%02d", tm_mon+1)
1103         }
1104         else if (strcEQ(var, "TIME_DAY")) {
1105             MKTIMESTR("%02d", tm_mday)
1106         }
1107         else if (strcEQ(var, "TIME_HOUR")) {
1108             MKTIMESTR("%02d", tm_hour)
1109         }
1110         else if (strcEQ(var, "TIME_MIN")) {
1111             MKTIMESTR("%02d", tm_min)
1112         }
1113         else if (strcEQ(var, "TIME_SEC")) {
1114             MKTIMESTR("%02d", tm_sec)
1115         }
1116         else if (strcEQ(var, "TIME_WDAY")) {
1117             MKTIMESTR("%d", tm_wday)
1118         }
1119         else if (strcEQ(var, "TIME")) {
1120             apr_time_exp_lt(&tm, apr_time_now());
1121             result = apr_psprintf(p,
1122                         "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
1123                         (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
1124                         tm.tm_hour, tm.tm_min, tm.tm_sec);
1125             resdup = FALSE;
1126         }
1127         /* all other env-variables from the parent Apache process */
1128         else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
1129             result = apr_table_get(r->notes, var+4);
1130             if (result == NULL)
1131                 result = apr_table_get(r->subprocess_env, var+4);
1132             if (result == NULL)
1133                 result = getenv(var+4);
1134         }
1135     }
1136
1137     if (result != NULL && resdup)
1138         result = apr_pstrdup(p, result);
1139     if (result == NULL)
1140         result = "";
1141     return (char *)result;
1142 }
1143
1144 #define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
1145 #define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
1146 #define CONNECTION_HEADER "Connection: Upgrade"
1147
1148 static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
1149                                           apr_bucket_brigade *bb)
1150
1151 {
1152     const char *upgrade;
1153     apr_bucket_brigade *upgradebb;
1154     request_rec *r = f->r;
1155     apr_socket_t *csd = NULL;
1156     char *key;
1157     int ret;
1158     secsocket_data *csd_data;
1159     apr_bucket *b;
1160     apr_status_t rv;
1161
1162     /* Just remove the filter, if it doesn't work the first time, it won't
1163      * work at all for this request.
1164      */
1165     ap_remove_output_filter(f);
1166
1167     if (!r) {
1168         /*
1169         ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02131)
1170                      "Unable to get upgradeable socket handle");
1171         */
1172         return ap_pass_brigade(f->next, bb);
1173     }
1174
1175     /* No need to ensure that this is a server with optional SSL, the filter
1176      * is only inserted if that is true.
1177      */
1178
1179     upgrade = apr_table_get(r->headers_in, "Upgrade");
1180     if (upgrade == NULL
1181         || strcmp(ap_getword(r->pool, &upgrade, ','), "TLS/1.0")) {
1182             /* "Upgrade: TLS/1.0, ..." header not found, don't do Upgrade */
1183         return ap_pass_brigade(f->next, bb);
1184     }
1185
1186     apr_table_unset(r->headers_out, "Upgrade");
1187
1188     csd_data = (secsocket_data*)ap_get_module_config(r->connection->conn_config, &nwssl_module);
1189     csd = csd_data->csd;
1190
1191     /* Send the interim 101 response. */
1192     upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1193
1194     ap_fputs(f->next, upgradebb, SWITCH_STATUS_LINE CRLF
1195              UPGRADE_HEADER CRLF CONNECTION_HEADER CRLF CRLF);
1196
1197     b = apr_bucket_flush_create(f->c->bucket_alloc);
1198     APR_BRIGADE_INSERT_TAIL(upgradebb, b);
1199
1200     rv = ap_pass_brigade(f->next, upgradebb);
1201     if (rv) {
1202         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02132)
1203                       "could not send interim 101 Upgrade response");
1204         return AP_FILTER_ERROR;
1205     }
1206
1207     key = get_port_key(r->connection);
1208
1209     if (csd && key) {
1210         int sockdes;
1211         apr_os_sock_get(&sockdes, csd);
1212
1213
1214         ret = SSLize_Socket(sockdes, key, r);
1215         if (!ret) {
1216             csd_data->is_secure = 1;
1217         }
1218     }
1219     else {
1220         ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02133)
1221                      "Upgradeable socket handle not found");
1222         return AP_FILTER_ERROR;
1223     }
1224
1225     ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, APLOGNO(02134)
1226                  "Awaiting re-negotiation handshake");
1227
1228     /* Now that we have initialized the ssl connection which added the ssl_io_filter,
1229        pass the brigade off to the connection based output filters so that the
1230        request can complete encrypted */
1231     return ap_pass_brigade(f->c->output_filters, bb);
1232 }
1233
1234 static void ssl_hook_Insert_Filter(request_rec *r)
1235 {
1236     NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
1237
1238     if (isSecureUpgradeable (r)) {
1239         ap_add_output_filter("UPGRADE_FILTER", NULL, r, r->connection);
1240     }
1241 }
1242
1243 static const command_rec nwssl_module_cmds[] =
1244 {
1245     AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF,
1246       "specify an address and/or port with a key pair name.\n"
1247       "Optional third parameter of MUTUAL configures the port for mutual authentication."),
1248     AP_INIT_TAKE2("NWSSLUpgradeable", set_secure_upgradeable_listener, NULL, RSRC_CONF,
1249       "specify an address and/or port with a key pair name, that can be upgraded to an SSL connection.\n"
1250       "The address and/or port must have already be defined using a Listen directive."),
1251     AP_INIT_ITERATE("NWSSLTrustedCerts", set_trusted_certs, NULL, RSRC_CONF,
1252         "Adds trusted certificates that are used to create secure connections to proxied servers"),
1253     {NULL}
1254 };
1255
1256 static void register_hooks(apr_pool_t *p)
1257 {
1258     ap_register_output_filter ("UPGRADE_FILTER", ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
1259
1260     ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
1261     ap_hook_pre_connection(nwssl_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
1262     ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1263     ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
1264     ap_hook_http_scheme(nwssl_hook_http_scheme, NULL, NULL, APR_HOOK_MIDDLE);
1265     ap_hook_default_port(nwssl_hook_default_port, NULL, NULL, APR_HOOK_MIDDLE);
1266     ap_hook_insert_filter(ssl_hook_Insert_Filter, NULL, NULL, APR_HOOK_MIDDLE);
1267
1268     APR_REGISTER_OPTIONAL_FN(ssl_is_https);
1269     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
1270
1271     APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
1272     APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
1273 }
1274
1275 AP_DECLARE_MODULE(nwssl) =
1276 {
1277     STANDARD20_MODULE_STUFF,
1278     NULL,                       /* dir config creater */
1279     NULL,                       /* dir merger --- default is to override */
1280     nwssl_config_server_create, /* server config */
1281     nwssl_config_server_merge,  /* merge server config */
1282     nwssl_module_cmds,          /* command apr_table_t */
1283     register_hooks
1284 };
1285