📄 mod_nw_ssl.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
*
* This module gives Apache the ability to do SSL/TLS with a minimum amount
* of effort. All of the SSL/TLS logic is already on NetWare versions 5 and
* above and is interfaced through WinSock on NetWare. As you can see in
* the code below SSL/TLS sockets can be created with three WinSock calls.
*
* To load, simply place the module in the modules directory under the main
* apache tree. Then add a "SecureListen" with two arguments. The first
* argument is an address and/or port. The second argument is the key pair
* name as created in ConsoleOne.
*
* Examples:
*
* SecureListen 443 "SSL CertificateIP"
* SecureListen 123.45.67.89:443 mycert
*/
#define WS_SSL
#define MAX_ADDRESS 512
#define MAX_KEY 80
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_core.h"
#include "ap_listen.h"
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_optional.h"
#include <unilib.h>
#ifndef SO_TLS_UNCLEAN_SHUTDOWN
#define SO_TLS_UNCLEAN_SHUTDOWN 0
#endif
/* The ssl_var_lookup() optional function retrieves SSL environment
* variables. */
APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
(apr_pool_t *, server_rec *,
conn_rec *, request_rec *,
char *));
/* An optional function which returns non-zero if the given connection
* is using SSL/TLS. */
APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
/* The ssl_proxy_enable() and ssl_engine_disable() optional functions
* are used by mod_proxy to enable use of SSL for outgoing
* connections. */
APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
#define strEQ(s1,s2) (strcmp(s1,s2) == 0)
#define strNE(s1,s2) (strcmp(s1,s2) != 0)
#define strEQn(s1,s2,n) (strncmp(s1,s2,n) == 0)
#define strNEn(s1,s2,n) (strncmp(s1,s2,n) != 0)
#define strcEQ(s1,s2) (strcasecmp(s1,s2) == 0)
#define strcNE(s1,s2) (strcasecmp(s1,s2) != 0)
#define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0)
#define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0)
#define strIsEmpty(s) (s == NULL || s[0] == NUL)
module AP_MODULE_DECLARE_DATA nwssl_module;
typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
typedef struct seclisten_rec seclisten_rec;
typedef struct seclistenup_rec seclistenup_rec;
typedef struct secsocket_data secsocket_data;
struct seclisten_rec {
seclisten_rec *next;
struct sockaddr_in local_addr; /* local IP address and port */
int fd;
int used; /* Only used during restart */
char key[MAX_KEY];
int mutual;
char *addr;
apr_port_t port;
};
struct seclistenup_rec {
seclistenup_rec *next;
char key[MAX_KEY];
char *addr;
apr_port_t port;
};
struct NWSSLSrvConfigRec {
apr_table_t *sltable;
apr_table_t *slutable;
apr_pool_t *pPool;
};
struct secsocket_data {
apr_socket_t* csd;
int is_secure;
};
static apr_array_header_t *certlist = NULL;
static unicode_t** certarray = NULL;
static int numcerts = 0;
static seclisten_rec* ap_seclisteners = NULL;
static seclistenup_rec* ap_seclistenersup = NULL;
#define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
static void build_cert_list (apr_pool_t *p)
{
int i;
char **rootcerts = (char **)certlist->elts;
numcerts = certlist->nelts;
certarray = apr_palloc(p, sizeof(unicode_t*)*numcerts);
for (i = 0; i < numcerts; ++i) {
unicode_t *unistr;
unistr = (unicode_t*)apr_palloc(p, strlen(rootcerts[i])*4);
loc2uni (UNI_LOCAL_DEFAULT, unistr, rootcerts[i], 0, 2);
certarray[i] = unistr;
}
}
/*
* Parses a host of the form <address>[:port]
* :port is permitted if 'port' is not NULL
*/
static unsigned long parse_addr(const char *w, unsigned short *ports)
{
struct hostent *hep;
unsigned long my_addr;
char *p;
p = strchr(w, ':');
if (ports != NULL) {
*ports = 0;
if (p != NULL && strcmp(p + 1, "*") != 0)
*ports = atoi(p + 1);
}
if (p != NULL)
*p = '\0';
if (strcmp(w, "*") == 0) {
if (p != NULL)
*p = ':';
return htonl(INADDR_ANY);
}
my_addr = apr_inet_addr((char *)w);
if (my_addr != INADDR_NONE) {
if (p != NULL)
*p = ':';
return my_addr;
}
hep = gethostbyname(w);
if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
/* XXX Should be echoing by h_errno the actual failure, no?
* ap_log_error would be good here. Better yet - APRize.
*/
fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
exit(1);
}
if (hep->h_addr_list[1]) {
fprintf(stderr, "Host %s has multiple addresses ---\n", w);
fprintf(stderr, "you must choose one explicitly for use as\n");
fprintf(stderr, "a secure port. Exiting!!!\n");
exit(1);
}
if (p != NULL)
*p = ':';
return ((struct in_addr *) (hep->h_addr))->s_addr;
}
static int find_secure_listener(seclisten_rec *lr)
{
seclisten_rec *sl;
for (sl = ap_seclisteners; sl; sl = sl->next) {
if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
sl->used = 1;
return sl->fd;
}
}
return -1;
}
static char *get_port_key(conn_rec *c)
{
seclistenup_rec *sl;
for (sl = ap_seclistenersup; sl; sl = sl->next) {
if ((sl->port == (c->local_addr)->port) &&
((strcmp(sl->addr, "0.0.0.0") == 0) || (strcmp(sl->addr, c->local_ip) == 0))) {
return sl->key;
}
}
return NULL;
}
static int make_secure_socket(apr_pool_t *pconf, const struct sockaddr_in *server,
char* key, int mutual, server_rec *sconf)
{
int s;
int one = 1;
char addr[MAX_ADDRESS];
struct sslserveropts opts;
unsigned int optParam;
WSAPROTOCOL_INFO SecureProtoInfo;
int no = 1;
if (server->sin_addr.s_addr != htonl(INADDR_ANY))
apr_snprintf(addr, sizeof(addr), "address %s port %d",
inet_ntoa(server->sin_addr), ntohs(server->sin_port));
else
apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
/* note that because we're about to slack we don't use psocket */
memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
SecureProtoInfo.iAddressFamily = AF_INET;
SecureProtoInfo.iSocketType = SOCK_STREAM;
SecureProtoInfo.iProtocol = IPPROTO_TCP;
SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
(LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
if (s == INVALID_SOCKET) {
ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
"make_secure_socket: failed to get a socket for %s",
addr);
return -1;
}
if (!mutual) {
optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
"make_secure_socket: for %s, WSAIoctl: "
"(SO_SSL_SET_FLAGS)", addr);
return -1;
}
}
opts.cert = key;
opts.certlen = strlen(key);
opts.sidtimeout = 0;
opts.sidentries = 0;
opts.siddir = NULL;
if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
NULL, 0, NULL, NULL, NULL) != 0) {
ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
"make_secure_socket: for %s, WSAIoctl: "
"(SO_SSL_SET_SERVER)", addr);
return -1;
}
if (mutual) {
optParam = 0x07; // SO_SSL_AUTH_CLIENT
if(WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam,
sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), sconf,
"make_secure_socket: for %s, WSAIoctl: "
"(SO_SSL_SET_FLAGS)", addr);
return -1;
}
}
optParam = SO_TLS_UNCLEAN_SHUTDOWN;
WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam, sizeof(optParam),
NULL, 0, NULL, NULL, NULL);
return s;
}
int convert_secure_socket(conn_rec *c, apr_socket_t *csd)
{
int rcode;
struct tlsclientopts sWS2Opts;
struct nwtlsopts sNWTLSOpts;
struct sslserveropts opts;
unsigned long ulFlags;
SOCKET sock;
unicode_t keyFileName[60];
apr_os_sock_get(&sock, csd);
/* zero out buffers */
memset((char *)&sWS2Opts, 0, sizeof(struct tlsclientopts));
memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
/* turn on ssl for the socket */
ulFlags = (numcerts ? SO_TLS_ENABLE : SO_TLS_ENABLE | SO_TLS_BLIND_ACCEPT);
rcode = WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
NULL, 0, NULL, NULL, NULL);
if (SOCKET_ERROR == rcode)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
"Error: %d with ioctlsocket(flag SO_TLS_ENABLE)", WSAGetLastError());
return rcode;
}
ulFlags = SO_TLS_UNCLEAN_SHUTDOWN;
WSAIoctl(sock, SO_TLS_SET_FLAGS, &ulFlags, sizeof(unsigned long),
NULL, 0, NULL, NULL, NULL);
/* setup the socket for SSL */
memset (&sWS2Opts, 0, sizeof(sWS2Opts));
memset (&sNWTLSOpts, 0, sizeof(sNWTLSOpts));
sWS2Opts.options = &sNWTLSOpts;
if (numcerts) {
sNWTLSOpts.walletProvider = WAL_PROV_DER; //the wallet provider defined in wdefs.h
sNWTLSOpts.TrustedRootList = certarray; //array of certs in UNICODE format
sNWTLSOpts.numElementsInTRList = numcerts; //number of certs in TRList
}
else {
/* setup the socket for SSL */
unicpy(keyFileName, L"SSL CertificateIP");
sWS2Opts.wallet = keyFileName; /* no client certificate */
sWS2Opts.walletlen = unilen(keyFileName);
sNWTLSOpts.walletProvider = WAL_PROV_KMO; //the wallet provider defined in wdefs.h
}
/* make the IOCTL call */
rcode = WSAIoctl(sock, SO_TLS_SET_CLIENT, &sWS2Opts,
sizeof(struct tlsclientopts), NULL, 0, NULL,
NULL, NULL);
/* make sure that it was successfull */
if(SOCKET_ERROR == rcode ){
ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
"Error: %d with ioctl (SO_TLS_SET_CLIENT)", WSAGetLastError());
}
return rcode;
}
int SSLize_Socket(SOCKET socketHnd, char *key, request_rec *r)
{
int rcode;
struct tlsserveropts sWS2Opts;
struct nwtlsopts sNWTLSOpts;
unicode_t SASKey[512];
unsigned long ulFlag;
memset((char *)&sWS2Opts, 0, sizeof(struct tlsserveropts));
memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -