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