]> granicus.if.org Git - apache/blob - modules/arch/netware/mod_nw_ssl.c
A couple of observations
[apache] / modules / arch / netware / mod_nw_ssl.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * mod_tls.c - Apache SSL/TLS module for NetWare by Mike Gardiner.
61  *
62  * This module gives Apache the ability to do SSL/TLS with a minimum amount
63  * of effort.  All of the SSL/TLS logic is already on NetWare versions 5 and
64  * above and is interfaced through WinSock on NetWare.  As you can see in
65  * the code below SSL/TLS sockets can be created with three WinSock calls.
66  *
67  * To load, simply place the module in the modules directory under the main
68  * apache tree.  Then add a "SecureListen" with two arguments.  The first
69  * argument is an address and/or port.  The second argument is the key pair
70  * name as created in ConsoleOne.
71  *
72  *  Examples:
73  *
74  *          SecureListen 443 "SSL CertificateIP"  
75  *          SecureListen 123.45.67.89:443 mycert
76  */
77
78 #define WS_SSL
79
80 #define  MAX_ADDRESS  512
81 #define  MAX_KEY       80
82
83
84 #include "httpd.h"
85 #include "http_config.h"
86 #include "http_log.h"
87 #include "ap_listen.h"
88 #include "apr_strings.h"
89 #include "apr_portable.h"
90
91 module AP_MODULE_DECLARE_DATA nwssl_module;
92
93 typedef struct NWSSLSrvConfigRec NWSSLSrvConfigRec;
94 typedef struct seclisten_rec seclisten_rec;
95
96 struct seclisten_rec {
97     seclisten_rec *next;
98     struct sockaddr_in local_addr;      /* local IP address and port */
99     int fd;
100     int used;                               /* Only used during restart */
101     char key[MAX_KEY];
102     int mutual;
103     char *addr;
104     int port;
105 };
106
107 struct NWSSLSrvConfigRec {
108     apr_table_t *sltable;
109 };
110
111 static seclisten_rec* ap_seclisteners = NULL;
112
113 #define get_nwssl_cfg(srv) (NWSSLSrvConfigRec *) ap_get_module_config(srv->module_config, &nwssl_module)
114
115 /*
116  * Parses a host of the form <address>[:port]
117  * :port is permitted if 'port' is not NULL
118  */
119 static unsigned long parse_addr(const char *w, unsigned short *ports)
120 {
121     struct hostent *hep;
122     unsigned long my_addr;
123     char *p;
124
125     p = strchr(w, ':');
126     if (ports != NULL) {
127         *ports = 0;
128     if (p != NULL && strcmp(p + 1, "*") != 0)
129         *ports = atoi(p + 1);
130     }
131
132     if (p != NULL)
133         *p = '\0';
134     if (strcmp(w, "*") == 0) {
135         if (p != NULL)
136             *p = ':';
137         return htonl(INADDR_ANY);
138     }
139
140     my_addr = apr_inet_addr((char *)w);
141     if (my_addr != INADDR_NONE) {
142         if (p != NULL)
143             *p = ':';
144         return my_addr;
145     }
146
147     hep = gethostbyname(w);
148
149     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
150         /* XXX Should be echoing by r_errno the actual failure, no? 
151          * ap_log_error would be good here.
152          */
153         fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
154         exit(1);
155     }
156
157     if (hep->h_addr_list[1]) {
158         fprintf(stderr, "Host %s has multiple addresses ---\n", w);
159         fprintf(stderr, "you must choose one explicitly for use as\n");
160         fprintf(stderr, "a secure port.  Exiting!!!\n");
161         exit(1);
162     }
163
164     if (p != NULL)
165         *p = ':';
166
167     return ((struct in_addr *) (hep->h_addr))->s_addr;
168 }
169
170 static int find_secure_listener(seclisten_rec *lr)
171 {
172     seclisten_rec *sl;
173
174     for (sl = ap_seclisteners; sl; sl = sl->next) {
175         if (!memcmp(&sl->local_addr, &lr->local_addr, sizeof(sl->local_addr))) {
176             sl->used = 1;
177             return sl->fd;
178         }
179     }    
180     return -1;
181 }
182
183
184 static int make_secure_socket(apr_pool_t *pconf, const struct sockaddr_in *server,
185                               char* key, int mutual, server_rec *server_conf)
186 {
187     int s;
188     int one = 1;
189     char addr[MAX_ADDRESS];
190     struct sslserveropts opts;
191     unsigned int optParam;
192     WSAPROTOCOL_INFO SecureProtoInfo;
193     int no = 1;
194     
195     if (server->sin_addr.s_addr != htonl(INADDR_ANY))
196         apr_snprintf(addr, sizeof(addr), "address %s port %d",
197             inet_ntoa(server->sin_addr), ntohs(server->sin_port));
198     else
199         apr_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
200
201     /* note that because we're about to slack we don't use psocket */
202     memset(&SecureProtoInfo, 0, sizeof(WSAPROTOCOL_INFO));
203
204     SecureProtoInfo.iAddressFamily = AF_INET;
205     SecureProtoInfo.iSocketType = SOCK_STREAM;
206     SecureProtoInfo.iProtocol = IPPROTO_TCP;   
207     SecureProtoInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;
208
209     s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
210             (LPWSAPROTOCOL_INFO)&SecureProtoInfo, 0, 0);
211             
212     if (s == INVALID_SOCKET) {
213         errno = WSAGetLastError();
214         ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
215             "make_secure_socket: failed to get a socket for %s", addr);
216         return -1;
217     }
218         
219     if (!mutual) {
220         optParam = SO_SSL_ENABLE | SO_SSL_SERVER;
221                     
222         if (WSAIoctl(s, SO_SSL_SET_FLAGS, (char *)&optParam,
223             sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
224             errno = WSAGetLastError();
225             ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
226                 "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr);
227             return -1;
228         }
229     }
230
231     opts.cert = key;
232     opts.certlen = strlen(key);
233     opts.sidtimeout = 0;
234     opts.sidentries = 0;
235     opts.siddir = NULL;
236
237     if (WSAIoctl(s, SO_SSL_SET_SERVER, (char *)&opts, sizeof(opts),
238         NULL, 0, NULL, NULL, NULL) != 0) {
239         errno = WSAGetLastError();
240         ap_log_error(APLOG_MARK, APLOG_CRIT, errno, server_conf,
241             "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_SERVER)", addr);
242         return -1;
243     }
244
245     if (mutual) {
246         optParam = 0x07;               // SO_SSL_AUTH_CLIENT
247
248         if(WSAIoctl(s, SO_SSL_SET_FLAGS, (char*)&optParam,
249             sizeof(optParam), NULL, 0, NULL, NULL, NULL)) {
250             errno = WSAGetLastError();
251             ap_log_error( APLOG_MARK, APLOG_CRIT, errno, server_conf,
252                 "make_secure_socket: for %s, WSAIoctl: (SO_SSL_SET_FLAGS)", addr );
253             return -1;
254         }
255     }
256
257     return s;
258 }
259
260 static const char *set_secure_listener(cmd_parms *cmd, void *dummy, 
261                                        const char *ips, const char* key, 
262                                        const char* mutual)
263 {
264     NWSSLSrvConfigRec* sc = get_nwssl_cfg(cmd->server);
265     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
266     char *ports, *addr;
267     unsigned short port;
268     seclisten_rec *new;
269
270     
271     if (err != NULL) 
272         return err;
273
274     ports = strchr(ips, ':');
275     
276     if (ports != NULL) {    
277             if (ports == ips)
278                 return "Missing IP address";
279             else if (ports[1] == '\0')
280                 return "Address must end in :<port-number>";
281                 
282             *(ports++) = '\0';
283     }
284     else {
285             ports = (char*)ips;
286     }
287     
288     new = apr_pcalloc(cmd->pool, sizeof(seclisten_rec)); 
289     new->local_addr.sin_family = AF_INET;
290     
291     if (ports == ips) {
292             new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
293         addr = apr_pstrdup(cmd->pool, "0.0.0.0");
294     }
295     else {
296             new->local_addr.sin_addr.s_addr = parse_addr(ips, NULL);
297         addr = apr_pstrdup(cmd->pool, ips);
298     }
299     
300     port = atoi(ports);
301     
302     if (!port) 
303             return "Port must be numeric";
304             
305     apr_table_set(sc->sltable, ports, "T");
306     
307     new->local_addr.sin_port = htons(port);
308     new->fd = -1;
309     new->used = 0;
310     new->next = ap_seclisteners;
311     strcpy(new->key, key);
312     new->mutual = (mutual) ? 1 : 0;
313     new->addr = addr;
314     new->port = port;
315     ap_seclisteners = new;
316     return NULL;
317 }
318
319 static apr_status_t nwssl_socket_cleanup(void *data)
320 {
321     ap_listen_rec* slr = (ap_listen_rec*)data;
322     ap_listen_rec* lr;
323
324     /* Remove our secure listener from the listener list */
325     for (lr = ap_listeners; lr; lr = lr->next) {
326         /* slr is at the head of the list */
327         if (lr == slr) {
328             ap_listeners = slr->next;
329             break;
330         }
331         /* slr is somewhere in between or at the end*/
332         if (lr->next == slr) {
333             lr->next = slr->next;
334             break;
335         }
336     }
337     return APR_SUCCESS;
338 }
339
340 static int nwssl_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
341                          apr_pool_t *ptemp)
342 {
343     ap_seclisteners = NULL;
344
345     return OK;
346 }
347
348 static int nwssl_post_config(apr_pool_t *pconf, apr_pool_t *plog,
349                           apr_pool_t *ptemp, server_rec *s)
350 {
351     seclisten_rec* sl;
352     ap_listen_rec* lr;
353     apr_socket_t*  sd;
354     apr_status_t status;
355     
356     for (sl = ap_seclisteners; sl != NULL; sl = sl->next) {
357         sl->fd = find_secure_listener(sl);
358
359         if (sl->fd < 0)
360             sl->fd = make_secure_socket(pconf, &sl->local_addr, sl->key, sl->mutual, s);            
361             
362         if (sl->fd >= 0) {
363             apr_os_sock_info_t sock_info;
364
365             sock_info.os_sock = &(sl->fd);
366             sock_info.local = (struct sockaddr*)&(sl->local_addr);
367             sock_info.remote = NULL;
368             sock_info.family = APR_INET;
369             sock_info.type = SOCK_STREAM;
370
371             apr_os_sock_make(&sd, &sock_info, pconf);
372
373             lr = apr_pcalloc(pconf, sizeof(ap_listen_rec));
374         
375             if (lr) {
376                                 lr->sd = sd;
377                 if ((status = apr_sockaddr_info_get(&lr->bind_addr, sl->addr, APR_UNSPEC, sl->port, 0, 
378                                               pconf)) != APR_SUCCESS) {
379                     ap_log_perror(APLOG_MARK, APLOG_CRIT, status, pconf,
380                                  "alloc_listener: failed to set up sockaddr for %s:%d", sl->addr, sl->port);
381                     return HTTP_INTERNAL_SERVER_ERROR;
382                 }
383                 lr->next = ap_listeners;
384                 ap_listeners = lr;
385                 apr_pool_cleanup_register(pconf, lr, nwssl_socket_cleanup, apr_pool_cleanup_null);
386             }                        
387         } else {
388             return HTTP_INTERNAL_SERVER_ERROR;
389         }
390     } 
391     return OK;
392 }
393
394 static void *nwssl_config_server_create(apr_pool_t *p, server_rec *s)
395 {
396     NWSSLSrvConfigRec *new = apr_palloc(p, sizeof(NWSSLSrvConfigRec));
397     new->sltable = apr_table_make(p, 5);
398     return new;
399 }
400
401 static void *nwssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
402 {
403     NWSSLSrvConfigRec *base = (NWSSLSrvConfigRec *)basev;
404     NWSSLSrvConfigRec *add  = (NWSSLSrvConfigRec *)addv;
405     NWSSLSrvConfigRec *merged  = (NWSSLSrvConfigRec *)apr_palloc(p, sizeof(NWSSLSrvConfigRec));
406     return merged;
407 }
408
409 static int isSecure (const request_rec *r)
410 {
411     NWSSLSrvConfigRec *sc = get_nwssl_cfg(r->server);
412     const char *s_secure = NULL;
413     char port[8];
414     int ret = 0;
415
416     itoa(((r->connection)->local_addr)->port, port, 10);
417     s_secure = apr_table_get(sc->sltable, port);    
418     if (s_secure)
419         ret = 1;
420
421     return ret;
422 }
423
424 static int nwssl_hook_Fixup(request_rec *r)
425 {
426     apr_table_t *e = r->subprocess_env;    
427     if (!isSecure(r))
428         return DECLINED;
429
430     apr_table_set(e, "HTTPS", "on");
431     
432     return DECLINED;
433 }
434
435 static const char *nwssl_hook_http_method (const request_rec *r)
436 {
437     if (isSecure(r))
438         return "https";
439
440     return NULL;
441 }
442
443 static const command_rec nwssl_module_cmds[] =
444 {
445     AP_INIT_TAKE23("SecureListen", set_secure_listener, NULL, RSRC_CONF,
446       "specify an address and/or port with a key pair name.\n"
447       "Optional third parameter of MUTUAL configures the port for mutual authentication."),
448     {NULL}
449 };
450
451 static void register_hooks(apr_pool_t *p)
452 {
453     ap_hook_pre_config(nwssl_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
454     ap_hook_post_config(nwssl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
455     ap_hook_fixups(nwssl_hook_Fixup, NULL, NULL, APR_HOOK_MIDDLE);
456     ap_hook_http_method(nwssl_hook_http_method,   NULL,NULL, APR_HOOK_MIDDLE);
457 }
458
459 module AP_MODULE_DECLARE_DATA nwssl_module =
460 {
461     STANDARD20_MODULE_STUFF,
462     NULL,                       /* dir config creater */
463     NULL,                       /* dir merger --- default is to override */
464     nwssl_config_server_create, /* server config */
465     nwssl_config_server_merge,  /* merge server config */
466     nwssl_module_cmds,          /* command apr_table_t */
467     register_hooks
468 };
469