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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * based on mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
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.
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.
32 * SecureListen 443 "SSL CertificateIP"
33 * SecureListen 123.45.67.89:443 mycert
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.
42 * NWSSLUpgradeable 8080 "SSL CertificateIP"
43 * NWSSLUpgradeable 123.45.67.89:8080 mycert
49 #define MAX_ADDRESS 512
54 #include "http_config.h"
55 #include "http_connection.h"
56 #include "http_core.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"
67 #ifndef SO_TLS_UNCLEAN_SHUTDOWN
68 #define SO_TLS_UNCLEAN_SHUTDOWN 0
71 /* The ssl_var_lookup() optional function retrieves SSL environment
73 APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
74 (apr_pool_t *, server_rec *,
75 conn_rec *, request_rec *,
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 *));
82 /* The ssl_proxy_enable() and ssl_engine_disable() optional functions
83 * are used by mod_proxy to enable use of SSL for outgoing
85 APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
86 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
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)
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)
98 #define strIsEmpty(s) (s == NULL || s[0] == NUL)
101 module AP_MODULE_DECLARE_DATA nwssl_module;
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;
108 struct seclisten_rec {
110 struct sockaddr_in local_addr; /* local IP address and port */
112 int used; /* Only used during restart */
119 struct seclistenup_rec {
120 seclistenup_rec *next;
126 struct NWSSLSrvConfigRec {
127 apr_table_t *sltable;
128 apr_table_t *slutable;
132 struct secsocket_data {
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;
143 static ap_listen_rec *nw_old_listeners;
145 #define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
148 static void build_cert_list(apr_pool_t *p)
151 char **rootcerts = (char **)certlist->elts;
153 numcerts = certlist->nelts;
154 certarray = apr_palloc(p, sizeof(unicode_t*)*numcerts);
156 for (i = 0; i < numcerts; ++i) {
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;
165 * Parses a host of the form <address>[:port]
166 * :port is permitted if 'port' is not NULL
168 static unsigned long parse_addr(const char *w, unsigned short *ports)
171 unsigned long my_addr;
177 if (p != NULL && strcmp(p + 1, "*") != 0)
178 *ports = atoi(p + 1);
183 if (strcmp(w, "*") == 0) {
186 return htonl(INADDR_ANY);
189 my_addr = apr_inet_addr((char *)w);
190 if (my_addr != INADDR_NONE) {
196 hep = gethostbyname(w);
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.
202 fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
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");
216 return ((struct in_addr *) (hep->h_addr))->s_addr;
219 static int find_secure_listener(seclisten_rec *lr)
223 for (sl = ap_seclisteners; sl; sl = sl->next) {
224 if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
232 static char *get_port_key(conn_rec *c)
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))) {
246 static int make_secure_socket(apr_pool_t *pconf,
247 const struct sockaddr_in *server,
248 char* key, int mutual, server_rec *sconf)
251 char addr[MAX_ADDRESS];
252 struct sslserveropts opts;
253 unsigned int optParam;
254 WSAPROTOCOL_INFO SecureProtoInfo;
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));
260 apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
262 /* note that because we're about to slack we don't use psocket */
263 memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
265 SecureProtoInfo.iAddressFamily = AF_INET;
266 SecureProtoInfo.iSocketType = SOCK_STREAM;
267 SecureProtoInfo.iProtocol = IPPROTO_TCP;
268 SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
270 s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
271 (LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
273 if (s == INVALID_SOCKET) {
274 ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
276 "make_secure_socket: failed to get a socket for %s",
282 optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
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,
288 "make_secure_socket: for %s, WSAIoctl: "
289 "(SO_SSL_SET_FLAGS)", addr);
295 opts.certlen = strlen(key);
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,
304 "make_secure_socket: for %s, WSAIoctl: "
305 "(SO_SSL_SET_SERVER)", addr);
310 optParam = 0x07; /* SO_SSL_AUTH_CLIENT */
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,
316 "make_secure_socket: for %s, WSAIoctl: "
317 "(SO_SSL_SET_FLAGS)", addr);
322 optParam = SO_TLS_UNCLEAN_SHUTDOWN;
323 WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam, sizeof(optParam),
324 NULL, 0, NULL, NULL, NULL);
329 static int convert_secure_socket(conn_rec *c, apr_socket_t *csd)
332 struct tlsclientopts sWS2Opts;
333 struct nwtlsopts sNWTLSOpts;
334 struct sslserveropts opts;
335 unsigned long ulFlags;
337 unicode_t keyFileName[60];
339 apr_os_sock_get(&sock, csd);
341 /* zero out buffers */
342 memset((char *)&sWS2Opts, 0, sizeof(struct tlsclientopts));
343 memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
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)",
356 ulFlags = SO_TLS_UNCLEAN_SHUTDOWN;
357 WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
358 NULL, 0, NULL, NULL, NULL);
360 /* setup the socket for SSL */
361 memset (&sWS2Opts, 0, sizeof(sWS2Opts));
362 memset (&sNWTLSOpts, 0, sizeof(sNWTLSOpts));
363 sWS2Opts.options = &sNWTLSOpts;
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 */
371 /* setup the socket for SSL */
372 unicpy(keyFileName, L"SSL CertificateIP");
373 sWS2Opts.wallet = keyFileName; /* no client certificate */
374 sWS2Opts.walletlen = unilen(keyFileName);
376 sNWTLSOpts.walletProvider = WAL_PROV_KMO; /* the wallet provider defined in wdefs.h */
379 /* make the IOCTL call */
380 rcode = WSAIoctl(sock, SO_TLS_SET_CLIENT, &sWS2Opts,
381 sizeof(struct tlsclientopts), NULL, 0, NULL,
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)",
393 static int SSLize_Socket(SOCKET socketHnd, char *key, request_rec *r)
396 struct tlsserveropts sWS2Opts;
397 struct nwtlsopts sNWTLSOpts;
398 unicode_t SASKey[512];
399 unsigned long ulFlag;
401 memset((char *)&sWS2Opts, 0, sizeof(struct tlsserveropts));
402 memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
404 ulFlag = SO_TLS_ENABLE;
405 rcode = WSAIoctl(socketHnd, SO_TLS_SET_FLAGS, &ulFlag,
406 sizeof(unsigned long), NULL, 0, NULL, NULL, NULL);
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)",
415 ulFlag = SO_TLS_SERVER;
416 rcode = WSAIoctl(socketHnd, SO_TLS_SET_FLAGS, &ulFlag,
417 sizeof(unsigned long),NULL, 0, NULL, NULL, NULL);
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)",
426 loc2uni(UNI_LOCAL_DEFAULT, SASKey, key, 0, 0);
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;
436 /* setup the nwtlsopts structure */
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;
448 rcode = WSAIoctl(socketHnd,
451 sizeof(struct tlsserveropts),
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());
467 static const char *set_secure_listener(cmd_parms *cmd, void *dummy,
468 const char *ips, const char* key,
471 NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
472 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
476 ap_listen_rec **walk;
478 int found_listener = 0;
484 ports = strchr(ips, ':');
488 return "Missing IP address";
489 else if (ports[1] == '\0')
490 return "Address must end in :<port-number>";
498 new = apr_pcalloc(cmd->server->process->pool, sizeof(seclisten_rec));
499 new->local_addr.sin_family = AF_INET;
502 new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
503 addr = apr_pstrdup(cmd->server->process->pool, "0.0.0.0");
506 new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
507 addr = apr_pstrdup(cmd->server->process->pool, ips);
513 return "Port must be numeric";
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;
525 /* If both ports are equivalent, then if their names are equivalent,
526 * then we will re-use the existing record.
528 if (port == oldport &&
529 ((!addr && !sa->hostname) ||
530 ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
533 new->next = ap_listeners;
540 walk = &(*walk)->next;
543 apr_table_add(sc->sltable, ports, addr);
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) {
551 new->local_addr.sin_port = htons(port);
554 new->next = ap_seclisteners;
555 strcpy(new->key, key);
556 new->mutual = (mutual) ? 1 : 0;
559 ap_seclisteners = new;
563 static const char *set_secure_upgradeable_listener(cmd_parms *cmd, void *dummy,
564 const char *ips, const char* key)
566 NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
567 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
570 seclistenup_rec *new;
575 ports = strchr(ips, ':');
579 return "Missing IP address";
580 else if (ports[1] == '\0')
581 return "Address must end in :<port-number>";
590 addr = apr_pstrdup(cmd->pool, "0.0.0.0");
593 addr = apr_pstrdup(cmd->pool, ips);
599 return "Port must be numeric";
601 apr_table_set(sc->slutable, ports, addr);
603 new = apr_pcalloc(cmd->pool, sizeof(seclistenup_rec));
604 new->next = ap_seclistenersup;
605 strcpy(new->key, key);
608 ap_seclistenersup = new;
613 static apr_status_t nwssl_socket_cleanup(void *data)
615 ap_listen_rec* slr = (ap_listen_rec*)data;
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 */
622 ap_listeners = slr->next;
625 /* slr is somewhere in between or at the end*/
626 if (lr->next == slr) {
627 lr->next = slr->next;
634 static const char *set_trusted_certs(cmd_parms *cmd, void *dummy, char *arg)
636 char **ptr = (char **)apr_array_push(certlist);
642 static int nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
645 seclisten_rec* ap_old_seclisteners;
646 ap_listen_rec **walk;
647 seclisten_rec **secwalk;
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;
657 for (secwalk = &ap_seclisteners; *secwalk;) {
659 for (walk = &ap_listeners; *walk;) {
660 sa = (*walk)->bind_addr;
663 seclisten_rec *secnew;
667 /* If both ports are equivalent, then if their names are equivalent,
668 * then we will re-use the existing record.
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 */
676 new->next = nw_old_listeners;
677 nw_old_listeners = new;
679 /* Move the secure socket record to ap_old_seclisterners */
681 *secwalk = secnew->next;
682 secnew->next = ap_old_seclisteners;
683 ap_old_seclisteners = secnew;
689 walk = &(*walk)->next;
691 if (!found && &(*secwalk)->next) {
692 secwalk = &(*secwalk)->next;
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 *));
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();
713 static int nwssl_pre_connection(conn_rec *c, void *csd)
716 if (apr_table_get(c->notes, "nwconv-ssl")) {
717 convert_secure_socket(c, (apr_socket_t*)csd);
720 secsocket_data *csd_data = apr_palloc(c->pool, sizeof(secsocket_data));
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);
730 static int nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
731 apr_pool_t *ptemp, server_rec *s)
737 seclistenup_rec *slu;
740 seclisten_rec *secwalk, *lastsecwalk;
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;
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.
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;
766 lastsecwalk->next = secwalk->next;
768 apr_socket_close(walk->sd);
773 lastsecwalk = secwalk;
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)) {
787 sl->fd = make_secure_socket(s->process->pool, &sl->local_addr, sl->key, sl->mutual, s);
790 apr_os_sock_info_t sock_info;
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;
798 apr_os_sock_make(&sd, &sock_info, s->process->pool);
800 lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
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;
810 lr->next = ap_listeners;
812 apr_pool_cleanup_register(s->process->pool, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
815 return HTTP_INTERNAL_SERVER_ERROR;
819 for (slu = ap_seclistenersup; slu; slu = slu->next) {
820 /* Check the listener list for a matching upgradeable listener */
822 for (lr = ap_listeners; lr; lr = lr->next) {
823 if (slu->port == lr->bind_addr->port) {
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);
834 build_cert_list(s->process->pool);
839 static void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
841 NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
842 new->sltable = apr_table_make(p, 5);
843 new->slutable = apr_table_make(p, 5);
847 static void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
849 NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
850 NWSSLSrvConfigRec *add = (NWSSLSrvConfigRec *)addv;
851 NWSSLSrvConfigRec *merged = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
855 static int compare_ipports(void *rec, const char *key, const char *value)
857 conn_rec *c = (conn_rec*)rec;
860 ((strcmp(value, "0.0.0.0") == 0) || (strcmp(value, c->local_ip) == 0)))
867 static int isSecureConnEx (const server_rec *s, const conn_rec *c, const apr_table_t *t)
871 itoa((c->local_addr)->port, port, 10);
872 if (!apr_table_do(compare_ipports, (void*)c, t, port, NULL)) {
879 static int isSecureConn (const server_rec *s, const conn_rec *c)
881 NWSSLSrvConfigRec *sc = get_nwssl_cfg(s);
883 return isSecureConnEx (s, c, sc->sltable);
886 static int isSecureConnUpgradeable (const server_rec *s, const conn_rec *c)
888 NWSSLSrvConfigRec *sc = get_nwssl_cfg(s);
890 return isSecureConnEx (s, c, sc->slutable);
893 static int isSecure (const request_rec *r)
895 return isSecureConn (r->server, r->connection);
898 static int isSecureUpgradeable (const request_rec *r)
900 return isSecureConnUpgradeable (r->server, r->connection);
903 static int isSecureUpgraded (const request_rec *r)
905 secsocket_data *csd_data = (secsocket_data*)ap_get_module_config(r->connection->conn_config, &nwssl_module);
907 return csd_data->is_secure;
910 static int nwssl_hook_Fixup(request_rec *r)
912 if (!isSecure(r) && !isSecureUpgraded(r))
915 apr_table_setn(r->subprocess_env, "HTTPS", "on");
920 static const char *nwssl_hook_http_scheme(const request_rec *r)
922 if (isSecure(r) && !isSecureUpgraded(r))
928 static apr_port_t nwssl_hook_default_port(const request_rec *r)
931 return DEFAULT_HTTPS_PORT;
936 int ssl_proxy_enable(conn_rec *c)
938 apr_table_setn(c->notes, "nwconv-ssl", "Y");
943 int ssl_engine_disable(conn_rec *c)
948 static int ssl_is_https(conn_rec *c)
950 secsocket_data *csd_data = (secsocket_data*)ap_get_module_config(c->conn_config, &nwssl_module);
952 return isSecureConn (c->base_server, c) || (csd_data && csd_data->is_secure);
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)
958 NWSSLSrvConfigRec *mc = get_nwssl_cfg(s);
967 * When no pool is given try to find one
979 * Request dependent stuff
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))
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);
1012 if (strcEQ(var, "REQUEST_METHOD"))
1014 else if (strcEQ(var, "REQUEST_SCHEME"))
1015 result = ap_http_scheme(r);
1016 else if (strcEQ(var, "REQUEST_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"))
1032 if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
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;
1047 if (strcEQ(var, "PATH_INFO"))
1048 result = r->path_info;
1049 else if (strcEQ(var, "QUERY_STRING"))
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;
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);*/
1073 if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
1078 * Totally independent stuff
1080 if (result == NULL) {
1081 if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
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);
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);
1097 #define MKTIMESTR(format, tmfield) \
1098 apr_time_exp_lt(&tm, apr_time_now()); \
1099 result = apr_psprintf(p, format, tm.tmfield); \
1101 else if (strcEQ(var, "TIME_MON")) {
1102 MKTIMESTR("%02d", tm_mon+1)
1104 else if (strcEQ(var, "TIME_DAY")) {
1105 MKTIMESTR("%02d", tm_mday)
1107 else if (strcEQ(var, "TIME_HOUR")) {
1108 MKTIMESTR("%02d", tm_hour)
1110 else if (strcEQ(var, "TIME_MIN")) {
1111 MKTIMESTR("%02d", tm_min)
1113 else if (strcEQ(var, "TIME_SEC")) {
1114 MKTIMESTR("%02d", tm_sec)
1116 else if (strcEQ(var, "TIME_WDAY")) {
1117 MKTIMESTR("%d", tm_wday)
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);
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);
1131 result = apr_table_get(r->subprocess_env, var+4);
1133 result = getenv(var+4);
1137 if (result != NULL && resdup)
1138 result = apr_pstrdup(p, result);
1141 return (char *)result;
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"
1148 static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
1149 apr_bucket_brigade *bb)
1152 const char *upgrade;
1153 apr_bucket_brigade *upgradebb;
1154 request_rec *r = f->r;
1155 apr_socket_t *csd = NULL;
1158 secsocket_data *csd_data;
1162 /* Just remove the filter, if it doesn't work the first time, it won't
1163 * work at all for this request.
1165 ap_remove_output_filter(f);
1169 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02131)
1170 "Unable to get upgradeable socket handle");
1172 return ap_pass_brigade(f->next, bb);
1175 /* No need to ensure that this is a server with optional SSL, the filter
1176 * is only inserted if that is true.
1179 upgrade = apr_table_get(r->headers_in, "Upgrade");
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);
1186 apr_table_unset(r->headers_out, "Upgrade");
1188 csd_data = (secsocket_data*)ap_get_module_config(r->connection->conn_config, &nwssl_module);
1189 csd = csd_data->csd;
1191 /* Send the interim 101 response. */
1192 upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1194 ap_fputs(f->next, upgradebb, SWITCH_STATUS_LINE CRLF
1195 UPGRADE_HEADER CRLF CONNECTION_HEADER CRLF CRLF);
1197 b = apr_bucket_flush_create(f->c->bucket_alloc);
1198 APR_BRIGADE_INSERT_TAIL(upgradebb, b);
1200 rv = ap_pass_brigade(f->next, upgradebb);
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;
1207 key = get_port_key(r->connection);
1211 apr_os_sock_get(&sockdes, csd);
1214 ret = SSLize_Socket(sockdes, key, r);
1216 csd_data->is_secure = 1;
1220 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02133)
1221 "Upgradeable socket handle not found");
1222 return AP_FILTER_ERROR;
1225 ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, APLOGNO(02134)
1226 "Awaiting re-negotiation handshake");
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);
1234 static void ssl_hook_Insert_Filter(request_rec *r)
1236 NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
1238 if (isSecureUpgradeable (r)) {
1239 ap_add_output_filter("UPGRADE_FILTER", NULL, r, r->connection);
1243 static const command_rec nwssl_module_cmds[] =
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"),
1256 static void register_hooks(apr_pool_t *p)
1258 ap_register_output_filter ("UPGRADE_FILTER", ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
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);
1268 APR_REGISTER_OPTIONAL_FN(ssl_is_https);
1269 APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
1271 APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
1272 APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
1275 AP_DECLARE_MODULE(nwssl) =
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 */