]> granicus.if.org Git - apache/blob - modules/ssl/ssl_engine_vars.c
00aa0a43b2d126cc3a15914f623478653a6d6d44
[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     SSLModConfigRec *mc = myModConfig(s);
93     char *result;
94     BOOL resdup;
95     time_t tc;
96     struct tm *tm;
97
98     result = NULL;
99     resdup = TRUE;
100
101     /*
102      * When no pool is given try to find one
103      */
104     if (p == NULL) {
105         if (r != NULL)
106             p = r->pool;
107         else if (c != NULL)
108             p = c->pool;
109         else
110             p = mc->pPool;
111     }
112
113     /*
114      * Request dependent stuff
115      */
116     if (r != NULL) {
117         if (strcEQ(var, "HTTP_USER_AGENT"))
118             result = ssl_var_lookup_header(p, r, "User-Agent");
119         else if (strcEQ(var, "HTTP_REFERER"))
120             result = ssl_var_lookup_header(p, r, "Referer");
121         else if (strcEQ(var, "HTTP_COOKIE"))
122             result = ssl_var_lookup_header(p, r, "Cookie");
123         else if (strcEQ(var, "HTTP_FORWARDED"))
124             result = ssl_var_lookup_header(p, r, "Forwarded");
125         else if (strcEQ(var, "HTTP_HOST"))
126             result = ssl_var_lookup_header(p, r, "Host");
127         else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
128             result = ssl_var_lookup_header(p, r, "Proxy-Connection");
129         else if (strcEQ(var, "HTTP_ACCEPT"))
130             result = ssl_var_lookup_header(p, r, "Accept");
131         else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
132             /* all other headers from which we are still not know about */
133             result = ssl_var_lookup_header(p, r, var+5);
134         else if (strcEQ(var, "THE_REQUEST"))
135             result = r->the_request;
136         else if (strcEQ(var, "REQUEST_METHOD"))
137             result = (char *)(r->method);
138         else if (strcEQ(var, "REQUEST_SCHEME"))
139             result = (char *)ap_http_method(r);
140         else if (strcEQ(var, "REQUEST_URI"))
141             result = r->uri;
142         else if (strcEQ(var, "SCRIPT_FILENAME") ||
143                  strcEQ(var, "REQUEST_FILENAME"))
144             result = r->filename;
145         else if (strcEQ(var, "PATH_INFO"))
146             result = r->path_info;
147         else if (strcEQ(var, "QUERY_STRING"))
148             result = r->args;
149         else if (strcEQ(var, "REMOTE_HOST"))
150             result = (char *)ap_get_remote_host(r->connection,
151                                         r->per_dir_config, REMOTE_NAME, NULL);
152         else if (strcEQ(var, "REMOTE_IDENT"))
153             result = (char *)ap_get_remote_logname(r);
154         else if (strcEQ(var, "IS_SUBREQ"))
155             result = (r->main != NULL ? "true" : "false");
156         else if (strcEQ(var, "DOCUMENT_ROOT"))
157             result = (char *)ap_document_root(r);
158         else if (strcEQ(var, "SERVER_ADMIN"))
159             result = r->server->server_admin;
160         else if (strcEQ(var, "SERVER_NAME"))
161             result = (char *)ap_get_server_name(r);
162         else if (strcEQ(var, "SERVER_PORT"))
163             result = apr_psprintf(p, "%u", ap_get_server_port(r));
164         else if (strcEQ(var, "SERVER_PROTOCOL"))
165             result = r->protocol;
166     }
167
168     /*
169      * Connection stuff
170      */
171     if (result == NULL && c != NULL) {
172         if (strcEQ(var, "REMOTE_ADDR"))
173             result = c->remote_ip;
174         else if (strcEQ(var, "REMOTE_USER"))
175             result = r->user;
176         else if (strcEQ(var, "AUTH_TYPE"))
177             result = r->ap_auth_type;
178         else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
179             result = ssl_var_lookup_ssl(p, c, var+4);
180         else if (strcEQ(var, "HTTPS")) {
181             if (apr_table_get(c->notes, "ssl") != NULL)
182                 result = "on";
183             else
184                 result = "off";
185         }
186     }
187
188     /*
189      * Totally independent stuff
190      */
191     if (result == NULL) {
192         if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
193             result = ssl_var_lookup_ssl_version(p, var+12);
194         else if (strcEQ(var, "SERVER_SOFTWARE"))
195             result = (char *)ap_get_server_version();
196         else if (strcEQ(var, "API_VERSION")) {
197             result = apr_psprintf(p, "%d", MODULE_MAGIC_NUMBER);
198             resdup = FALSE;
199         }
200         else if (strcEQ(var, "TIME_YEAR")) {
201             tc = time(NULL);
202             tm = localtime(&tc);
203             result = apr_psprintf(p, "%02d%02d",
204                                  (tm->tm_year / 100) + 19, tm->tm_year % 100);
205             resdup = FALSE;
206         }
207 #define MKTIMESTR(format, tmfield) \
208             tc = time(NULL); \
209             tm = localtime(&tc); \
210             result = apr_psprintf(p, format, tm->tmfield); \
211             resdup = FALSE;
212         else if (strcEQ(var, "TIME_MON")) {
213             MKTIMESTR("%02d", tm_mon+1)
214         }
215         else if (strcEQ(var, "TIME_DAY")) {
216             MKTIMESTR("%02d", tm_mday)
217         }
218         else if (strcEQ(var, "TIME_HOUR")) {
219             MKTIMESTR("%02d", tm_hour)
220         }
221         else if (strcEQ(var, "TIME_MIN")) {
222             MKTIMESTR("%02d", tm_min)
223         }
224         else if (strcEQ(var, "TIME_SEC")) {
225             MKTIMESTR("%02d", tm_sec)
226         }
227         else if (strcEQ(var, "TIME_WDAY")) {
228             MKTIMESTR("%d", tm_wday)
229         }
230         else if (strcEQ(var, "TIME")) {
231             tc = time(NULL);
232             tm = localtime(&tc);
233             result = apr_psprintf(p,
234                         "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19,
235                         (tm->tm_year % 100), tm->tm_mon+1, tm->tm_mday,
236                         tm->tm_hour, tm->tm_min, tm->tm_sec);
237             resdup = FALSE;
238         }
239         /* all other env-variables from the parent Apache process */
240         else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
241             result = (char *)apr_table_get(r->notes, var+4);
242             if (result == NULL)
243                 result = (char *)apr_table_get(r->subprocess_env, var+4);
244             if (result == NULL)
245                 result = getenv(var+4);
246         }
247     }
248
249     if (result != NULL && resdup)
250         result = apr_pstrdup(p, result);
251     if (result == NULL)
252         result = "";
253     return result;
254 }
255
256 static char *ssl_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name)
257 {
258     char *hdr = NULL;
259
260     if ((hdr = (char *)apr_table_get(r->headers_in, name)) != NULL)
261         hdr = apr_pstrdup(p, hdr);
262     return hdr;
263 }
264
265 static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
266 {
267     char *result;
268     X509 *xs;
269     STACK_OF(X509) *sk;
270     SSL *ssl;
271
272     result = NULL;
273
274     ssl = (SSL *)apr_table_get(c->notes, "ssl");
275     if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
276         result = ssl_var_lookup_ssl_version(p, var+8);
277     }
278     else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
279         result = (char *)SSL_get_version(ssl);
280     }
281     else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
282         SSL_SESSION *pSession = SSL_get_session(ssl);
283         result = apr_pstrdup(p, SSL_SESSION_id2sz(pSession->session_id, 
284                                                  pSession->session_id_length));
285     }
286     else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
287         result = ssl_var_lookup_ssl_cipher(p, c, var+6);
288     }
289     else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
290         sk = SSL_get_peer_cert_chain(ssl);
291         result = ssl_var_lookup_ssl_cert_chain(p, sk, var+17);
292     }
293     else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
294         result = ssl_var_lookup_ssl_cert_verify(p, c);
295     }
296     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
297         if ((xs = SSL_get_peer_certificate(ssl)) != NULL)
298             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
299     }
300     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
301         if ((xs = SSL_get_certificate(ssl)) != NULL)
302             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
303     }
304     return result;
305 }
306
307 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var)
308 {
309     char *result;
310     BOOL resdup;
311     X509_NAME *xsname;
312     int nid;
313     char *cp;
314
315     result = NULL;
316     resdup = TRUE;
317
318     if (strcEQ(var, "M_VERSION")) {
319         result = apr_psprintf(p, "%lu", X509_get_version(xs)+1);
320         resdup = FALSE;
321     }
322     else if (strcEQ(var, "M_SERIAL")) {
323         result = ssl_var_lookup_ssl_cert_serial(p, xs);
324     }
325     else if (strcEQ(var, "V_START")) {
326         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
327     }
328     else if (strcEQ(var, "V_END")) {
329         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
330     }
331     else if (strcEQ(var, "S_DN")) {
332         xsname = X509_get_subject_name(xs);
333         cp = X509_NAME_oneline(xsname, NULL, 0);
334         result = apr_pstrdup(p, cp);
335         free(cp);
336         resdup = FALSE;
337     }
338     else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
339         xsname = X509_get_subject_name(xs);
340         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
341         resdup = FALSE;
342     }
343     else if (strcEQ(var, "I_DN")) {
344         xsname = X509_get_issuer_name(xs);
345         cp = X509_NAME_oneline(xsname, NULL, 0);
346         result = apr_pstrdup(p, cp);
347         free(cp);
348         resdup = FALSE;
349     }
350     else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) {
351         xsname = X509_get_issuer_name(xs);
352         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
353         resdup = FALSE;
354     }
355     else if (strcEQ(var, "A_SIG")) {
356         nid = OBJ_obj2nid(xs->cert_info->signature->algorithm);
357         result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
358         resdup = FALSE;
359     }
360     else if (strcEQ(var, "A_KEY")) {
361         nid = OBJ_obj2nid(xs->cert_info->key->algor->algorithm);
362         result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
363         resdup = FALSE;
364     }
365     else if (strcEQ(var, "CERT")) {
366         result = ssl_var_lookup_ssl_cert_PEM(p, xs);
367     }
368
369     if (result != NULL && resdup)
370         result = apr_pstrdup(p, result);
371     return result;
372 }
373
374 static const struct {
375     char *name;
376     int   nid;
377 } ssl_var_lookup_ssl_cert_dn_rec[] = {
378     { "C",     NID_countryName            },
379     { "ST",    NID_stateOrProvinceName    }, /* officially    (RFC2156) */
380     { "SP",    NID_stateOrProvinceName    }, /* compatibility (SSLeay)  */
381     { "L",     NID_localityName           },
382     { "O",     NID_organizationName       },
383     { "OU",    NID_organizationalUnitName },
384     { "CN",    NID_commonName             },
385     { "T",     NID_title                  },
386     { "I",     NID_initials               },
387     { "G",     NID_givenName              },
388     { "S",     NID_surname                },
389     { "D",     NID_description            },
390     { "UID",   NID_uniqueIdentifier       },
391     { "Email", NID_pkcs9_emailAddress     },
392     { NULL,    0                          }
393 };
394
395 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
396 {
397     char *result;
398     X509_NAME_ENTRY *xsne;
399     int i, j, n;
400
401     result = NULL;
402
403     for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
404         if (strEQ(var, ssl_var_lookup_ssl_cert_dn_rec[i].name)) {
405             for (j = 0; j < sk_X509_NAME_ENTRY_num(xsname->entries); j++) {
406                 xsne = sk_X509_NAME_ENTRY_value(xsname->entries, j);
407                 n = OBJ_obj2nid(xsne->object);
408                 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) {
409                     result = apr_palloc(p, xsne->value->length+1);
410                     apr_cpystrn(result, (char *)xsne->value->data, xsne->value->length+1);
411 #ifdef CHARSET_EBCDIC
412                     ascii2ebcdic(result, result, xsne->value->length);
413 #endif /* CHARSET_EBCDIC */
414                     result[xsne->value->length] = NUL;
415                     break;
416                 }
417             }
418             break;
419         }
420     }
421     return result;
422 }
423
424 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm)
425 {
426     char *result;
427     BIO* bio;
428     int n;
429
430     if ((bio = BIO_new(BIO_s_mem())) == NULL)
431         return NULL;
432     ASN1_UTCTIME_print(bio, tm);
433     n = BIO_pending(bio);
434     result = apr_pcalloc(p, n+1);
435     n = BIO_read(bio, result, n);
436     result[n] = NUL;
437     BIO_free(bio);
438     return result;
439 }
440
441 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
442 {
443     char *result;
444     BIO *bio;
445     int n;
446
447     if ((bio = BIO_new(BIO_s_mem())) == NULL)
448         return NULL;
449     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
450     n = BIO_pending(bio);
451     result = apr_pcalloc(p, n+1);
452     n = BIO_read(bio, result, n);
453     result[n] = NUL;
454     BIO_free(bio);
455     return result;
456 }
457
458 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
459 {
460     char *result;
461     X509 *xs;
462     int n;
463
464     result = NULL;
465
466     if (strspn(var, "0123456789") == strlen(var)) {
467         n = atoi(var);
468         if (n < sk_X509_num(sk)) {
469             xs = sk_X509_value(sk, n);
470             result = ssl_var_lookup_ssl_cert_PEM(p, xs);
471         }
472     }
473
474     return result;
475 }
476
477 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
478 {
479     char *result;
480     BIO *bio;
481     int n;
482
483     if ((bio = BIO_new(BIO_s_mem())) == NULL)
484         return NULL;
485     PEM_write_bio_X509(bio, xs);
486     n = BIO_pending(bio);
487     result = apr_pcalloc(p, n+1);
488     n = BIO_read(bio, result, n);
489     result[n] = NUL;
490     BIO_free(bio);
491     return result;
492 }
493
494 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c)
495 {
496     char *result;
497     long vrc;
498     char *verr;
499     char *vinfo;
500     SSL *ssl;
501     X509 *xs;
502
503     result = NULL;
504     ssl   = (SSL *) apr_table_get(c->notes, "ssl");
505     verr  = (char *)apr_table_get(c->notes, "ssl::verify::error");
506     vinfo = (char *)apr_table_get(c->notes, "ssl::verify::info");
507     vrc   = SSL_get_verify_result(ssl);
508     xs    = SSL_get_peer_certificate(ssl);
509
510     if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL)
511         /* no client verification done at all */
512         result = "NONE";
513     else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
514         /* client verification done successful */
515         result = "SUCCESS";
516     else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
517         /* client verification done in generous way */
518         result = "GENEROUS";
519     else
520         /* client verification failed */
521         result = apr_psprintf(p, "FAILED:%s", verr);
522     return result;
523 }
524
525 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var)
526 {
527     char *result;
528     BOOL resdup;
529     int usekeysize, algkeysize;
530     SSL *ssl;
531
532     result = NULL;
533     resdup = TRUE;
534
535     ssl = (SSL *)apr_table_get(c->notes, "ssl");
536     ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
537
538     if (strEQ(var, ""))
539         result = (ssl != NULL ? (char *)SSL_get_cipher_name(ssl) : NULL);
540     else if (strcEQ(var, "_EXPORT"))
541         result = (usekeysize < 56 ? "true" : "false");
542     else if (strcEQ(var, "_USEKEYSIZE")) {
543         result = apr_psprintf(p, "%d", usekeysize);
544         resdup = FALSE;
545     }
546     else if (strcEQ(var, "_ALGKEYSIZE")) {
547         result = apr_psprintf(p, "%d", algkeysize);
548         resdup = FALSE;
549     }
550
551     if (result != NULL && resdup)
552         result = apr_pstrdup(p, result);
553     return result;
554 }
555
556 static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
557 {
558     SSL_CIPHER *cipher;
559
560     *usekeysize = 0;
561     *algkeysize = 0;
562     if (ssl != NULL)
563         if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
564             *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
565     return;
566 }
567
568 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
569 {
570     char *result;
571     char *cp, *cp2;
572
573     result = NULL;
574
575     if (strEQ(var, "PRODUCT")) {
576 #if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION)
577         result = apr_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION);
578 #else
579         result = NULL;
580 #endif
581     }
582     else if (strEQ(var, "INTERFACE")) {
583         result = apr_psprintf(p, "mod_ssl/%s", MOD_SSL_VERSION);
584     }
585     else if (strEQ(var, "LIBRARY")) {
586         result = apr_pstrdup(p, SSL_LIBRARY_TEXT);
587         if ((cp = strchr(result, ' ')) != NULL) {
588             *cp = '/';
589             if ((cp2 = strchr(cp, ' ')) != NULL)
590                 *cp2 = NUL;
591         }
592     }
593     return result;
594 }
595
596 /*  _________________________________________________________________
597 **
598 **  SSL Extension to mod_log_config
599 **  _________________________________________________________________
600 */
601
602 #include "../../modules/loggers/mod_log_config.h"
603
604 static const char *ssl_var_log_handler_c(request_rec *r, char *a);
605 static const char *ssl_var_log_handler_x(request_rec *r, char *a);
606
607 /*
608  * register us for the mod_log_config function registering phase
609  * to establish %{...}c and to be able to expand %{...}x variables.
610  */
611 void ssl_var_log_config_register(apr_pool_t *p)
612 {
613     static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
614
615     log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
616
617     if (log_pfn_register) {
618         log_pfn_register(p, "c", ssl_var_log_handler_c, 0);
619         log_pfn_register(p, "x", ssl_var_log_handler_x, 0);
620     }
621     return;
622 }
623
624 /*
625  * implement the %{..}c log function
626  * (we are the only function)
627  */
628 static const char *ssl_var_log_handler_c(request_rec *r, char *a)
629 {
630     char *result;
631
632     if (apr_table_get(r->connection->notes, "ssl") == NULL)
633         return NULL;
634     result = NULL;
635     if (strEQ(a, "version"))
636         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
637     else if (strEQ(a, "cipher"))
638         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
639     else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
640         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
641     else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
642         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
643     else if (strEQ(a, "errcode"))
644         result = "-";
645     else if (strEQ(a, "errstr"))
646         result = (char *)apr_table_get(r->connection->notes, "ssl::verify::error");
647     if (result != NULL && result[0] == NUL)
648         result = NULL;
649     return result;
650 }
651
652 /*
653  * extend the implementation of the %{..}x log function
654  * (there can be more functions)
655  */
656 static const char *ssl_var_log_handler_x(request_rec *r, char *a)
657 {
658     char *result;
659
660     result = NULL;
661     if (apr_table_get(r->connection->notes, "ssl") != NULL)
662         result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
663     if (result != NULL && result[0] == NUL)
664         result = NULL;
665     return result;
666 }
667