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