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