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