]> granicus.if.org Git - apache/blob - modules/ssl/ssl_engine_vars.c
start moving c->notes usage to a new SSLConnRec structure hanging off of
[apache] / modules / ssl / ssl_engine_vars.c
1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  ssl_engine_vars.c
8 **  Variable Lookup Facility
9 */
10
11 /* ====================================================================
12  * The Apache Software License, Version 1.1
13  *
14  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
15  * reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  *
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in
26  *    the documentation and/or other materials provided with the
27  *    distribution.
28  *
29  * 3. The end-user documentation included with the redistribution,
30  *    if any, must include the following acknowledgment:
31  *       "This product includes software developed by the
32  *        Apache Software Foundation (http://www.apache.org/)."
33  *    Alternately, this acknowledgment may appear in the software itself,
34  *    if and wherever such third-party acknowledgments normally appear.
35  *
36  * 4. The names "Apache" and "Apache Software Foundation" must
37  *    not be used to endorse or promote products derived from this
38  *    software without prior written permission. For written
39  *    permission, please contact apache@apache.org.
40  *
41  * 5. Products derived from this software may not be called "Apache",
42  *    nor may "Apache" appear in their name, without prior written
43  *    permission of the Apache Software Foundation.
44  *
45  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
46  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
49  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  * ====================================================================
58  */
59                              /* ``Those of you who think they
60                                   know everything are very annoying
61                                   to those of us who do.''
62                                                   -- Unknown       */
63 #include "mod_ssl.h"
64
65 /*  _________________________________________________________________
66 **
67 **  Variable Lookup
68 **  _________________________________________________________________
69 */
70
71 static char *ssl_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name);
72 static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var);
73 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var);
74 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var);
75 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm);
76 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs);
77 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var);
78 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs);
79 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c);
80 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var);
81 static void  ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
82 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var);
83
84 void ssl_var_register(void)
85 {
86     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
87     return;
88 }
89
90 char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
91 {
92     SSLConnRec *sslconn;
93     SSLModConfigRec *mc = myModConfig(s);
94     char *result;
95     BOOL resdup;
96     time_t tc;
97     struct tm *tm;
98
99     result = NULL;
100     resdup = TRUE;
101
102     /*
103      * When no pool is given try to find one
104      */
105     if (p == NULL) {
106         if (r != NULL)
107             p = r->pool;
108         else if (c != NULL)
109             p = c->pool;
110         else
111             p = mc->pPool;
112     }
113
114     /*
115      * Request dependent stuff
116      */
117     if (r != NULL) {
118         if (strcEQ(var, "HTTP_USER_AGENT"))
119             result = ssl_var_lookup_header(p, r, "User-Agent");
120         else if (strcEQ(var, "HTTP_REFERER"))
121             result = ssl_var_lookup_header(p, r, "Referer");
122         else if (strcEQ(var, "HTTP_COOKIE"))
123             result = ssl_var_lookup_header(p, r, "Cookie");
124         else if (strcEQ(var, "HTTP_FORWARDED"))
125             result = ssl_var_lookup_header(p, r, "Forwarded");
126         else if (strcEQ(var, "HTTP_HOST"))
127             result = ssl_var_lookup_header(p, r, "Host");
128         else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
129             result = ssl_var_lookup_header(p, r, "Proxy-Connection");
130         else if (strcEQ(var, "HTTP_ACCEPT"))
131             result = ssl_var_lookup_header(p, r, "Accept");
132         else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
133             /* all other headers from which we are still not know about */
134             result = ssl_var_lookup_header(p, r, var+5);
135         else if (strcEQ(var, "THE_REQUEST"))
136             result = r->the_request;
137         else if (strcEQ(var, "REQUEST_METHOD"))
138             result = (char *)(r->method);
139         else if (strcEQ(var, "REQUEST_SCHEME"))
140             result = (char *)ap_http_method(r);
141         else if (strcEQ(var, "REQUEST_URI"))
142             result = r->uri;
143         else if (strcEQ(var, "SCRIPT_FILENAME") ||
144                  strcEQ(var, "REQUEST_FILENAME"))
145             result = r->filename;
146         else if (strcEQ(var, "PATH_INFO"))
147             result = r->path_info;
148         else if (strcEQ(var, "QUERY_STRING"))
149             result = r->args;
150         else if (strcEQ(var, "REMOTE_HOST"))
151             result = (char *)ap_get_remote_host(r->connection,
152                                         r->per_dir_config, REMOTE_NAME, NULL);
153         else if (strcEQ(var, "REMOTE_IDENT"))
154             result = (char *)ap_get_remote_logname(r);
155         else if (strcEQ(var, "IS_SUBREQ"))
156             result = (r->main != NULL ? "true" : "false");
157         else if (strcEQ(var, "DOCUMENT_ROOT"))
158             result = (char *)ap_document_root(r);
159         else if (strcEQ(var, "SERVER_ADMIN"))
160             result = r->server->server_admin;
161         else if (strcEQ(var, "SERVER_NAME"))
162             result = (char *)ap_get_server_name(r);
163         else if (strcEQ(var, "SERVER_PORT"))
164             result = apr_psprintf(p, "%u", ap_get_server_port(r));
165         else if (strcEQ(var, "SERVER_PROTOCOL"))
166             result = r->protocol;
167     }
168
169     /*
170      * Connection stuff
171      */
172     if (result == NULL && c != NULL) {
173         sslconn = myConnConfig(c);
174         if (strcEQ(var, "REMOTE_ADDR"))
175             result = c->remote_ip;
176         else if (strcEQ(var, "REMOTE_USER"))
177             result = r->user;
178         else if (strcEQ(var, "AUTH_TYPE"))
179             result = r->ap_auth_type;
180         else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
181             result = ssl_var_lookup_ssl(p, c, var+4);
182         else if (strcEQ(var, "HTTPS")) {
183             if (sslconn->ssl != NULL)
184                 result = "on";
185             else
186                 result = "off";
187         }
188     }
189
190     /*
191      * Totally independent stuff
192      */
193     if (result == NULL) {
194         if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
195             result = ssl_var_lookup_ssl_version(p, var+12);
196         else if (strcEQ(var, "SERVER_SOFTWARE"))
197             result = (char *)ap_get_server_version();
198         else if (strcEQ(var, "API_VERSION")) {
199             result = apr_psprintf(p, "%d", MODULE_MAGIC_NUMBER);
200             resdup = FALSE;
201         }
202         else if (strcEQ(var, "TIME_YEAR")) {
203             tc = time(NULL);
204             tm = localtime(&tc);
205             result = apr_psprintf(p, "%02d%02d",
206                                  (tm->tm_year / 100) + 19, tm->tm_year % 100);
207             resdup = FALSE;
208         }
209 #define MKTIMESTR(format, tmfield) \
210             tc = time(NULL); \
211             tm = localtime(&tc); \
212             result = apr_psprintf(p, format, tm->tmfield); \
213             resdup = FALSE;
214         else if (strcEQ(var, "TIME_MON")) {
215             MKTIMESTR("%02d", tm_mon+1)
216         }
217         else if (strcEQ(var, "TIME_DAY")) {
218             MKTIMESTR("%02d", tm_mday)
219         }
220         else if (strcEQ(var, "TIME_HOUR")) {
221             MKTIMESTR("%02d", tm_hour)
222         }
223         else if (strcEQ(var, "TIME_MIN")) {
224             MKTIMESTR("%02d", tm_min)
225         }
226         else if (strcEQ(var, "TIME_SEC")) {
227             MKTIMESTR("%02d", tm_sec)
228         }
229         else if (strcEQ(var, "TIME_WDAY")) {
230             MKTIMESTR("%d", tm_wday)
231         }
232         else if (strcEQ(var, "TIME")) {
233             tc = time(NULL);
234             tm = localtime(&tc);
235             result = apr_psprintf(p,
236                         "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19,
237                         (tm->tm_year % 100), tm->tm_mon+1, tm->tm_mday,
238                         tm->tm_hour, tm->tm_min, tm->tm_sec);
239             resdup = FALSE;
240         }
241         /* all other env-variables from the parent Apache process */
242         else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
243             result = (char *)apr_table_get(r->notes, var+4);
244             if (result == NULL)
245                 result = (char *)apr_table_get(r->subprocess_env, var+4);
246             if (result == NULL)
247                 result = getenv(var+4);
248         }
249     }
250
251     if (result != NULL && resdup)
252         result = apr_pstrdup(p, result);
253     if (result == NULL)
254         result = "";
255     return result;
256 }
257
258 static char *ssl_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name)
259 {
260     char *hdr = NULL;
261
262     if ((hdr = (char *)apr_table_get(r->headers_in, name)) != NULL)
263         hdr = apr_pstrdup(p, hdr);
264     return hdr;
265 }
266
267 static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
268 {
269     SSLConnRec *sslconn = myConnConfig(c);
270     char *result;
271     X509 *xs;
272     STACK_OF(X509) *sk;
273     SSL *ssl;
274
275     result = NULL;
276
277     ssl = sslconn->ssl;
278     if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
279         result = ssl_var_lookup_ssl_version(p, var+8);
280     }
281     else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
282         result = (char *)SSL_get_version(ssl);
283     }
284     else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
285         SSL_SESSION *pSession = SSL_get_session(ssl);
286         result = apr_pstrdup(p, SSL_SESSION_id2sz(pSession->session_id, 
287                                                  pSession->session_id_length));
288     }
289     else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
290         result = ssl_var_lookup_ssl_cipher(p, c, var+6);
291     }
292     else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
293         sk = SSL_get_peer_cert_chain(ssl);
294         result = ssl_var_lookup_ssl_cert_chain(p, sk, var+17);
295     }
296     else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
297         result = ssl_var_lookup_ssl_cert_verify(p, c);
298     }
299     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
300         if ((xs = SSL_get_peer_certificate(ssl)) != NULL)
301             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
302     }
303     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
304         if ((xs = SSL_get_certificate(ssl)) != NULL)
305             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
306     }
307     return result;
308 }
309
310 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var)
311 {
312     char *result;
313     BOOL resdup;
314     X509_NAME *xsname;
315     int nid;
316     char *cp;
317
318     result = NULL;
319     resdup = TRUE;
320
321     if (strcEQ(var, "M_VERSION")) {
322         result = apr_psprintf(p, "%lu", X509_get_version(xs)+1);
323         resdup = FALSE;
324     }
325     else if (strcEQ(var, "M_SERIAL")) {
326         result = ssl_var_lookup_ssl_cert_serial(p, xs);
327     }
328     else if (strcEQ(var, "V_START")) {
329         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
330     }
331     else if (strcEQ(var, "V_END")) {
332         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
333     }
334     else if (strcEQ(var, "S_DN")) {
335         xsname = X509_get_subject_name(xs);
336         cp = X509_NAME_oneline(xsname, NULL, 0);
337         result = apr_pstrdup(p, cp);
338         free(cp);
339         resdup = FALSE;
340     }
341     else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
342         xsname = X509_get_subject_name(xs);
343         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
344         resdup = FALSE;
345     }
346     else if (strcEQ(var, "I_DN")) {
347         xsname = X509_get_issuer_name(xs);
348         cp = X509_NAME_oneline(xsname, NULL, 0);
349         result = apr_pstrdup(p, cp);
350         free(cp);
351         resdup = FALSE;
352     }
353     else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) {
354         xsname = X509_get_issuer_name(xs);
355         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
356         resdup = FALSE;
357     }
358     else if (strcEQ(var, "A_SIG")) {
359         nid = OBJ_obj2nid(xs->cert_info->signature->algorithm);
360         result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
361         resdup = FALSE;
362     }
363     else if (strcEQ(var, "A_KEY")) {
364         nid = OBJ_obj2nid(xs->cert_info->key->algor->algorithm);
365         result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
366         resdup = FALSE;
367     }
368     else if (strcEQ(var, "CERT")) {
369         result = ssl_var_lookup_ssl_cert_PEM(p, xs);
370     }
371
372     if (result != NULL && resdup)
373         result = apr_pstrdup(p, result);
374     return result;
375 }
376
377 static const struct {
378     char *name;
379     int   nid;
380 } ssl_var_lookup_ssl_cert_dn_rec[] = {
381     { "C",     NID_countryName            },
382     { "ST",    NID_stateOrProvinceName    }, /* officially    (RFC2156) */
383     { "SP",    NID_stateOrProvinceName    }, /* compatibility (SSLeay)  */
384     { "L",     NID_localityName           },
385     { "O",     NID_organizationName       },
386     { "OU",    NID_organizationalUnitName },
387     { "CN",    NID_commonName             },
388     { "T",     NID_title                  },
389     { "I",     NID_initials               },
390     { "G",     NID_givenName              },
391     { "S",     NID_surname                },
392     { "D",     NID_description            },
393     { "UID",   NID_uniqueIdentifier       },
394     { "Email", NID_pkcs9_emailAddress     },
395     { NULL,    0                          }
396 };
397
398 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
399 {
400     char *result;
401     X509_NAME_ENTRY *xsne;
402     int i, j, n;
403
404     result = NULL;
405
406     for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
407         if (strEQ(var, ssl_var_lookup_ssl_cert_dn_rec[i].name)) {
408             for (j = 0; j < sk_X509_NAME_ENTRY_num(xsname->entries); j++) {
409                 xsne = sk_X509_NAME_ENTRY_value(xsname->entries, j);
410                 n = OBJ_obj2nid(xsne->object);
411                 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) {
412                     result = apr_palloc(p, xsne->value->length+1);
413                     apr_cpystrn(result, (char *)xsne->value->data, xsne->value->length+1);
414 #ifdef CHARSET_EBCDIC
415                     ascii2ebcdic(result, result, xsne->value->length);
416 #endif /* CHARSET_EBCDIC */
417                     result[xsne->value->length] = NUL;
418                     break;
419                 }
420             }
421             break;
422         }
423     }
424     return result;
425 }
426
427 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm)
428 {
429     char *result;
430     BIO* bio;
431     int n;
432
433     if ((bio = BIO_new(BIO_s_mem())) == NULL)
434         return NULL;
435     ASN1_UTCTIME_print(bio, tm);
436     n = BIO_pending(bio);
437     result = apr_pcalloc(p, n+1);
438     n = BIO_read(bio, result, n);
439     result[n] = NUL;
440     BIO_free(bio);
441     return result;
442 }
443
444 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
445 {
446     char *result;
447     BIO *bio;
448     int n;
449
450     if ((bio = BIO_new(BIO_s_mem())) == NULL)
451         return NULL;
452     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
453     n = BIO_pending(bio);
454     result = apr_pcalloc(p, n+1);
455     n = BIO_read(bio, result, n);
456     result[n] = NUL;
457     BIO_free(bio);
458     return result;
459 }
460
461 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
462 {
463     char *result;
464     X509 *xs;
465     int n;
466
467     result = NULL;
468
469     if (strspn(var, "0123456789") == strlen(var)) {
470         n = atoi(var);
471         if (n < sk_X509_num(sk)) {
472             xs = sk_X509_value(sk, n);
473             result = ssl_var_lookup_ssl_cert_PEM(p, xs);
474         }
475     }
476
477     return result;
478 }
479
480 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
481 {
482     char *result;
483     BIO *bio;
484     int n;
485
486     if ((bio = BIO_new(BIO_s_mem())) == NULL)
487         return NULL;
488     PEM_write_bio_X509(bio, xs);
489     n = BIO_pending(bio);
490     result = apr_pcalloc(p, n+1);
491     n = BIO_read(bio, result, n);
492     result[n] = NUL;
493     BIO_free(bio);
494     return result;
495 }
496
497 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c)
498 {
499     SSLConnRec *sslconn = myConnConfig(c);
500     char *result;
501     long vrc;
502     char *verr;
503     char *vinfo;
504     SSL *ssl;
505     X509 *xs;
506
507     result = NULL;
508     ssl   = sslconn->ssl;
509     verr  = (char *)apr_table_get(c->notes, "ssl::verify::error");
510     vinfo = (char *)apr_table_get(c->notes, "ssl::verify::info");
511     vrc   = SSL_get_verify_result(ssl);
512     xs    = SSL_get_peer_certificate(ssl);
513
514     if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL)
515         /* no client verification done at all */
516         result = "NONE";
517     else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
518         /* client verification done successful */
519         result = "SUCCESS";
520     else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
521         /* client verification done in generous way */
522         result = "GENEROUS";
523     else
524         /* client verification failed */
525         result = apr_psprintf(p, "FAILED:%s", verr);
526     return result;
527 }
528
529 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var)
530 {
531     SSLConnRec *sslconn = myConnConfig(c);    
532     char *result;
533     BOOL resdup;
534     int usekeysize, algkeysize;
535     SSL *ssl;
536
537     result = NULL;
538     resdup = TRUE;
539
540     ssl = sslconn->ssl;
541     ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
542
543     if (strEQ(var, ""))
544         result = (ssl != NULL ? (char *)SSL_get_cipher_name(ssl) : NULL);
545     else if (strcEQ(var, "_EXPORT"))
546         result = (usekeysize < 56 ? "true" : "false");
547     else if (strcEQ(var, "_USEKEYSIZE")) {
548         result = apr_psprintf(p, "%d", usekeysize);
549         resdup = FALSE;
550     }
551     else if (strcEQ(var, "_ALGKEYSIZE")) {
552         result = apr_psprintf(p, "%d", algkeysize);
553         resdup = FALSE;
554     }
555
556     if (result != NULL && resdup)
557         result = apr_pstrdup(p, result);
558     return result;
559 }
560
561 static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
562 {
563     SSL_CIPHER *cipher;
564
565     *usekeysize = 0;
566     *algkeysize = 0;
567     if (ssl != NULL)
568         if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
569             *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
570     return;
571 }
572
573 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
574 {
575     char *result;
576     char *cp, *cp2;
577
578     result = NULL;
579
580     if (strEQ(var, "PRODUCT")) {
581 #if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION)
582         result = apr_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION);
583 #else
584         result = NULL;
585 #endif
586     }
587     else if (strEQ(var, "INTERFACE")) {
588         result = apr_psprintf(p, "mod_ssl/%s", MOD_SSL_VERSION);
589     }
590     else if (strEQ(var, "LIBRARY")) {
591         result = apr_pstrdup(p, SSL_LIBRARY_TEXT);
592         if ((cp = strchr(result, ' ')) != NULL) {
593             *cp = '/';
594             if ((cp2 = strchr(cp, ' ')) != NULL)
595                 *cp2 = NUL;
596         }
597     }
598     return result;
599 }
600
601 /*  _________________________________________________________________
602 **
603 **  SSL Extension to mod_log_config
604 **  _________________________________________________________________
605 */
606
607 #include "../../modules/loggers/mod_log_config.h"
608
609 static const char *ssl_var_log_handler_c(request_rec *r, char *a);
610 static const char *ssl_var_log_handler_x(request_rec *r, char *a);
611
612 /*
613  * register us for the mod_log_config function registering phase
614  * to establish %{...}c and to be able to expand %{...}x variables.
615  */
616 void ssl_var_log_config_register(apr_pool_t *p)
617 {
618     static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
619
620     log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
621
622     if (log_pfn_register) {
623         log_pfn_register(p, "c", ssl_var_log_handler_c, 0);
624         log_pfn_register(p, "x", ssl_var_log_handler_x, 0);
625     }
626     return;
627 }
628
629 /*
630  * implement the %{..}c log function
631  * (we are the only function)
632  */
633 static const char *ssl_var_log_handler_c(request_rec *r, char *a)
634 {
635     SSLConnRec *sslconn = myConnConfig(r->connection);
636     char *result;
637
638     if (sslconn->ssl == NULL)
639         return NULL;
640     result = NULL;
641     if (strEQ(a, "version"))
642         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
643     else if (strEQ(a, "cipher"))
644         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
645     else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
646         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
647     else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
648         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
649     else if (strEQ(a, "errcode"))
650         result = "-";
651     else if (strEQ(a, "errstr"))
652         result = (char *)apr_table_get(r->connection->notes, "ssl::verify::error");
653     if (result != NULL && result[0] == NUL)
654         result = NULL;
655     return result;
656 }
657
658 /*
659  * extend the implementation of the %{..}x log function
660  * (there can be more functions)
661  */
662 static const char *ssl_var_log_handler_x(request_rec *r, char *a)
663 {
664     SSLConnRec *sslconn = myConnConfig(r->connection);
665     char *result;
666
667     result = NULL;
668     if (sslconn->ssl != NULL)
669         result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
670     if (result != NULL && result[0] == NUL)
671         result = NULL;
672     return result;
673 }
674