Project

General

Profile

Feature #1936 » mod_lvhost.c

hazzadous, 2009-03-22 14:10

 
1
/*
2
 *
3
 * mod_lvhost.c
4
 * Copyright (c) 2008, Stephane Camberlin
5
 * All rights 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
 * - Redistributions of source code must retain the above copyright notice, 
12
 *   this list of conditions and the following disclaimer.
13
 *
14
 * - Redistributions in binary form must reproduce the above copyright 
15
 *   notice, this list of conditions and the following disclaimer in the 
16
 *   documentation and/or other materials provided with the distribution.
17
 *
18
 * - Neither the name of the 'incremental' nor the names of its 
19
 *   contributors may be used to endorse or promote products derived 
20
 *   from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
25
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
26
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
27
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (
28
 * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
31
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33
 * THE POSSIBILITY OF SUCH DAMAGE.
34
 *
35
 */
36

    
37
#include <ctype.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <errno.h>
41
#include <time.h>
42
#include <assert.h>
43

    
44
#include "base.h"
45
#include "log.h"
46
#include "buffer.h"
47
#include "stat_cache.h"
48

    
49
#include "plugin.h"
50

    
51
#ifdef HAVE_CONFIG_H
52
#include "config.h"
53
#endif
54

    
55
#include <ldap.h>
56
#include <lber.h>
57

    
58
#define DEBUG 1
59
#define CACHE_LIFETIME 3600
60

    
61
#define PATCH_OPTION(x) \
62
        p->conf.x = s->x;
63

    
64
/** 
65
 * Common lvhost related data.
66
 * 
67
 * Configuration shared by all handled requests within a config_context.
68
 */
69
typedef struct
70
{
71
	LDAP	*ldap_c;	/** LDAP session handle used for all queries. */
72
	buffer	*ldap_uri;	/** URI in form that openldap library expects it. */
73
	unsigned short	ldap_starttls;
74
	buffer	*sasl_user;	/** SASL auth user ( = authz user). */
75
	buffer	*sasl_pass;	
76
	buffer	*sasl_realm;
77
	buffer	*sasl_mech;
78
	buffer	*ldap_binddn;	/** If set, use simple binds. */
79
	buffer	*ldap_password;	/** Simple bind password. */
80
	buffer	*ldap_base;		/** The search root.  Scope is sub */
81

    
82
	/** The filter used to search for document root,
83
	 *  given an input of server name.  
84
	 *  Default: (&(objectClass=vhost)(serverName=?))
85
	 */
86
	buffer	*ldap_filter;
87

    
88
	/** The attribute representing docroot.
89
	 *  Default: documentRoot
90
	 */
91
	buffer	*ldap_attribute;
92

    
93
	unsigned short ldap_persist;	/** If use, use refreshAndPersist */
94
  
95
	buffer	*ldap_pre;
96
	buffer	*ldap_post;
97
  
98
	int		free_me;
99

    
100
} lvhost_plugin_config;
101

    
102
/* cache struct.  Maybe use lightys arrays later */
103
typedef struct {
104

    
105
	buffer* server_name;
106
	buffer* docroot;
107
	time_t birth;
108

    
109
} doc_cache_t;
110

    
111
typedef struct {
112

    
113
	PLUGIN_DATA;
114
  
115
	buffer  *docroot;
116
	buffer  *tmp_buf;
117
	doc_cache_t **doc_cache;
118
	unsigned int cache_size;
119

    
120
	lvhost_plugin_config **config_storage;
121
	lvhost_plugin_config conf;
122

    
123
} plugin_data;
124

    
125
INIT_FUNC(mod_lvhost_init) {
126

    
127
	plugin_data *p;
128

    
129
	p = (plugin_data*)malloc( sizeof(*p) );
130

    
131
	if( p )
132
	{
133
		p->tmp_buf = buffer_init();
134
		p->docroot = buffer_init();
135
		p->doc_cache = malloc( 0 );
136
		p->cache_size = 0;
137
	}
138

    
139
	return p;
140
}
141

    
142
FREE_FUNC(mod_lvhost_cleanup) {
143

    
144
	plugin_data *p = p_d;
145

    
146
	UNUSED(srv);
147

    
148
	if (!p) return HANDLER_GO_ON;
149

    
150
	if (p->config_storage) {
151
    
152
		size_t i, j;
153

    
154
		for (i = 0; i < srv->config_context->used; i++)
155
		{  
156
			lvhost_plugin_config *s = p->config_storage[i];
157
      
158
			if (!s) continue;
159
 
160
			if (s->free_me) ldap_unbind_ext(s->ldap_c, NULL, NULL);
161

    
162
	        /* Free all the buffers for this config_context */
163
    	    buffer *bufs[] = {	s->ldap_uri,		s->sasl_user,
164
								s->sasl_pass,		s->sasl_mech,
165
								s->sasl_realm,		s->ldap_binddn,
166
            	                s->ldap_password,	s->ldap_base,
167
								s->ldap_filter,		s->ldap_attribute,
168
								s->ldap_pre,		s->ldap_post };
169

    
170
			for(j = 0; j * sizeof(buffer*) < sizeof(bufs); j++)
171
				buffer_free(bufs[j]);
172
	      
173
			free(s);
174
		} 
175
	      
176
		free(p->config_storage);
177
	}
178

    
179
	buffer_free(p->docroot);
180
	free(p->doc_cache);
181

    
182
	free(p);
183

    
184
	return HANDLER_GO_ON;
185
}
186

    
187
SETDEFAULTS_FUNC(mod_lvhost_set_defaults) {
188

    
189
	plugin_data *p = p_d;
190
  
191
	size_t i, j, k;
192
	int err;
193
  
194
	struct berval cred;
195

    
196
	int ldap_version = LDAP_VERSION3;
197

    
198
	/* 
199
	 * List of config values to be read from the lighttpd configfile.
200
	 * Format is { confstring, destination memory, type, scope }
201
	 * Please place T_CONFIG_STRINGs at top.
202
	 */
203
	config_values_t cv[] = {
204
  
205
		{ "lvhost.uri",				NULL,
206
									T_CONFIG_STRING,
207
									T_CONFIG_SCOPE_SERVER },
208

    
209
		{ "lvhost.sasl_mech",		NULL,
210
									T_CONFIG_STRING, 
211
									T_CONFIG_SCOPE_SERVER },
212

    
213
	 	{ "lvhost.sasl_user",		NULL,
214
									T_CONFIG_STRING, 
215
									T_CONFIG_SCOPE_SERVER },
216

    
217
		{ "lvhost.sasl_realm",		NULL,
218
									T_CONFIG_STRING,
219
									T_CONFIG_SCOPE_SERVER },
220

    
221
	    { "lvhost.sasl_pass",		NULL,
222
    	                            T_CONFIG_STRING,
223
        	                        T_CONFIG_SCOPE_SERVER },
224

    
225
		{ "lvhost.binddn",			NULL,
226
									T_CONFIG_STRING,
227
									T_CONFIG_SCOPE_SERVER },
228

    
229
		{ "lvhost.password",		NULL,
230
									T_CONFIG_STRING,
231
									T_CONFIG_SCOPE_SERVER },
232

    
233
		{ "lvhost.base",			NULL,
234
									T_CONFIG_STRING,
235
									T_CONFIG_SCOPE_SERVER },
236

    
237
		{ "lvhost.filter",			NULL,
238
									T_CONFIG_STRING,
239
									T_CONFIG_SCOPE_SERVER },
240

    
241
		{ "lvhost.attribute",		NULL,
242
									T_CONFIG_STRING,
243
									T_CONFIG_SCOPE_SERVER },
244

    
245
        { "lvhost.starttls",        NULL,
246
                                    T_CONFIG_BOOLEAN,
247
                                    T_CONFIG_SCOPE_SERVER },
248

    
249
		{ "lvhost.persistent",		NULL,
250
									T_CONFIG_BOOLEAN,
251
									T_CONFIG_SCOPE_SERVER },
252

    
253
		{ NULL,						NULL,
254
									T_CONFIG_UNSET,
255
									T_CONFIG_SCOPE_UNSET }
256

    
257
	};
258
  
259
	if ( !p ) return HANDLER_ERROR;
260
  
261
	/* 
262
	 * Allocate memory for pointers to instances of lvhost_plugin_config
263
	 * that will be created one per config_context.
264
	 */
265
	p->config_storage = 
266
			(lvhost_plugin_config**)malloc(	srv->config_context->used
267
											* sizeof(lvhost_plugin_config*) );
268

    
269
	if( !(p->config_storage) ) return HANDLER_ERROR;
270

    
271
	/*
272
	 * If we managed to allocate space for the config points,
273
	 * continue with initiate these pointers.
274
	 */
275
	for (i = 0; i < srv->config_context->used; i++)
276
	{
277
		buffer *myfilter = buffer_init();
278
		char *qmark = 0;
279
 
280
		/* The lvhost plugin config for the i-th config_context */
281

    
282
		lvhost_plugin_config *s;
283
		s = (lvhost_plugin_config *)malloc( sizeof(*s) );
284
		if( !s ) return HANDLER_ERROR;
285

    
286
		/* Initialize all the buffers for this config_context */
287
		buffer **bufs[] = {	&s->ldap_uri, 		&s->sasl_mech, 	&s->sasl_user,
288
							&s->sasl_realm,		&s->sasl_pass, 	&s->ldap_binddn,
289
							&s->ldap_password,	&s->ldap_base,	&s->ldap_filter,
290
							&s->ldap_attribute };
291

    
292
		/* Init these separately */
293
		s->ldap_pre = buffer_init();
294
		s->ldap_post = buffer_init();
295

    
296
		for(j = 0; j * sizeof(buffer**) < sizeof(bufs); j++)
297
		{
298
#if DEBUG==2
299
			log_error_write(	srv, __FILE__, __LINE__, "ss",
300
								"Initializing buffer for", cv[j].key );
301
#endif
302
			*bufs[j] = buffer_init();
303
		}
304

    
305
		/*
306
		 * Point the destinations of cv to our config storage to
307
		 * be filled by config_insert_values_global.  dests must be the same
308
		 * order as they are in cv, so make sure bufs and bools are correct
309
		 */
310
		unsigned short *bools[] = { &s->ldap_starttls, &s->ldap_persist };
311
		void** dests = (void**)malloc( sizeof(bufs) + sizeof(bools) );
312
		if(!dests) return HANDLER_ERROR;
313

    
314
		/* Append bools to the buffers */
315
		for(j = 0; j * sizeof(buffer**) < sizeof(bufs); j++)
316
			dests[j] = *bufs[j];
317
		memcpy(	dests + j, bools, sizeof(bools) );
318

    
319
		/* nDests should be the same as the length of cv - 1 */
320
		size_t nDests = sizeof(cv) / sizeof(config_values_t) - 1;
321
		assert( (nDests * sizeof(void*)) == (sizeof(bools) + sizeof(bufs)) );
322

    
323
		for(j = 0; cv[j].key; j++)
324
		{
325
#if DEBUG==2
326
			log_error_write(	srv, __FILE__, __LINE__, "ss",
327
								"Setting destination for", cv[j].key );
328
#endif
329
			assert( dests[j] );
330
			cv[j].destination = dests[j];
331
		}
332

    
333
		p->config_storage[i] = s;
334

    
335
		if (config_insert_values_global(srv, 
336
				((data_config *)srv->config_context->data[i])->value, cv))
337
		{
338
			return HANDLER_ERROR;
339
		}
340

    
341
#if DEBUG==2
342
		/* Print what we got from lighttpd config. */
343
		for(j = 0; cv[j].key; j++)
344
		{
345
			switch( cv[j].type )
346
			{
347
				case T_CONFIG_STRING:
348
					log_error_write(	srv, __FILE__, __LINE__, "ssb",
349
										"lvhost config: ", cv[j].key, 
350
										(buffer*)dests[j] 				);
351
					break;
352

    
353
				case T_CONFIG_BOOLEAN:
354
					log_error_write(	srv, __FILE__, __LINE__, "ssd",
355
										"lvhost config: ", cv[j].key,
356
										*((unsigned short*)cv[j].destination) );
357
					break;
358
			default:
359
					log_error_write(	srv, __FILE__, __LINE__, "ssd",
360
										"lvhost config: ", cv[j].key,
361
										*((int*)cv[j].destination)		);
362
			};
363
		}
364
#endif /* DEBUG */
365

    
366
		/*
367
		 * Initiate default values for certain buffers
368
		 */
369

    
370
		/**
371
		 * Structure containing a buffer - stringi default pairing
372
		 */
373
		typedef struct { buffer* b; const char* d; } buffer_default_t;
374
		buffer_default_t defaults[] = 
375
			{
376
				{ s->ldap_filter,		"(&(objectClass=vhost)(serverName=?))" 	},
377
				{ s->ldap_attribute,	"documentRoot"							},
378
				{ s->sasl_mech,			"PLAIN"									}
379
			};
380

    
381
		for(j = 0; j * sizeof(buffer_default_t) < sizeof(defaults); j++)
382
			if( buffer_is_empty(defaults[j].b) )
383
				buffer_copy_string( defaults[j].b, defaults[j].d );
384

    
385
		/*
386
		 * Check that we have none empty buffers on
387
		 * the following variables.
388
		 */
389
		buffer* required_buffers[] = { 	s->ldap_uri, s->ldap_base,
390
										s->ldap_filter, s->ldap_attribute };
391

    
392
		for(j = 0; j * sizeof(buffer*) < sizeof(required_buffers); j++)
393
		{
394
			/* Get the index of required_buffers, as seen in cv */
395
			for( k = 0; k < nDests; k++ )
396
				if( required_buffers[j] == dests[k] ) break;
397

    
398
			/* Should have gotten a match */
399
			assert( k < nDests );
400

    
401
			if( buffer_is_empty(required_buffers[j]) )
402
			{
403
				log_error_write(	srv, __FILE__, __LINE__, "ss", 
404
									"Missing required option:", cv[k].key );
405
				/* TODO: readd this line maybe
406
				 * I don't seem to understand config_contexts 
407
				 * yet to leave this out
408
				 * return HANDLER_ERROR;
409
				 */
410

    
411
				return HANDLER_GO_ON;
412
			}
413
		}
414

    
415
		/*
416
		 * Next we split the ldap_filter string in two
417
		 * at the contained question mark if it has one,
418
		 * and put the two halfs in ldap_pre and ldap_post maybe
419
		 */
420
		buffer_copy_string_buffer(myfilter, s->ldap_filter);
421

    
422
		if( (qmark = index(myfilter->ptr, '?')) )
423
		{
424
			*qmark = '\0';
425
			buffer_copy_string(s->ldap_pre, myfilter->ptr);
426
			buffer_copy_string(s->ldap_post, qmark+1);
427
		}
428
		else
429
		{
430
			buffer_copy_string_buffer(s->ldap_pre, myfilter);
431
		}
432
    
433
		buffer_free(myfilter);
434
 
435
		s->free_me = 0;
436

    
437
		/*
438
		 * Now we setup the ldap session to be referenced by ldap_c
439
		 */
440
		if ((err = ldap_initialize( &s->ldap_c,
441
									s->ldap_uri->ptr )) != LDAP_SUCCESS) {
442
			log_error_write(	srv, __FILE__, __LINE__, "ss", 
443
								"ldap_initialize() failed, exiting... :", 
444
								ldap_err2string(err)						);
445
			return HANDLER_ERROR;
446
		}
447
    
448
		s->free_me = 1;
449

    
450
		/* Start TLS if requested */
451
		if(    s->ldap_starttls 
452
			&& ( err = ldap_start_tls_s( s->ldap_c, NULL, NULL ) ) )
453
		{
454
            log_error_write(    srv, __FILE__, __LINE__, "ss",
455
                                "ldap_start_tls_s() failed, exiting... :",
456
                                ldap_err2string(err)                        );
457
			return HANDLER_ERROR;
458
		}
459

    
460
		ldap_set_option( s->ldap_c, LDAP_OPT_PROTOCOL_VERSION, &ldap_version );
461

    
462
		/*
463
		 * If binddn was given, assume we want  a simple bind.
464
		 * For now let us perform all ldap operations syncronously.
465
		 */
466
		if( !buffer_is_empty(s->ldap_binddn) )
467
		{
468
	        if ((err = ldap_simple_bind_s(  s->ldap_c,
469
    	                                    s->ldap_binddn->ptr,
470
			                                s->ldap_password->ptr)) != LDAP_SUCCESS)
471
			{
472
        	    log_error_write(    srv, __FILE__, __LINE__, "ss",
473
	                                "ldap_simple_bind_s() failed, exiting... :",
474
    	                            ldap_err2string(err)                        );
475
        	    return HANDLER_ERROR;
476
			}
477

    
478
			/* We were successful.  No need to do anything else */
479
			return HANDLER_GO_ON;
480
		}
481

    
482
		if( !buffer_is_empty(s->sasl_pass) )
483
		{
484
			cred.bv_val = strdup(s->sasl_pass->ptr);
485
			cred.bv_len = strlen(s->sasl_pass->ptr);
486
		} else {
487
			cred.bv_val = NULL;
488
			cred.bv_len = 0;
489
		}
490
  
491
		if ((err = ldap_sasl_bind_s(	s->ldap_c, 
492
										s->sasl_user->ptr,
493
										s->sasl_mech->ptr,
494
										&cred, NULL, NULL, NULL	)) != LDAP_SUCCESS)
495
		{
496
			log_error_write(	srv, __FILE__, __LINE__, "ss", 
497
								"ldap_sasl_bind_s() failed, exiting... :", 
498
								ldap_err2string(err)						);
499
			return HANDLER_ERROR;
500
		}
501
	}
502

    
503
	return HANDLER_GO_ON;
504
}
505

    
506
static int mod_lvhost_patch_connection(	server *srv, 
507
										connection *con, 
508
										plugin_data *p	)
509
{
510
	size_t i;
511
	lvhost_plugin_config *s = p->config_storage[0];
512

    
513
	PATCH_OPTION(ldap_base);
514
	PATCH_OPTION(ldap_attribute);
515
	PATCH_OPTION(ldap_pre);
516
	PATCH_OPTION(ldap_post);
517
	PATCH_OPTION(ldap_c);
518

    
519
	for (i = 1; i < srv->config_context->used; i++)
520
	{
521
		data_config *dc = (data_config *)srv->config_context->data[i];
522
		s = p->config_storage[i];
523

    
524
		if (!config_check_cond(srv, con, dc)) continue;
525

    
526
		PATCH_OPTION(ldap_base);
527
		PATCH_OPTION(ldap_attribute);
528
		PATCH_OPTION(ldap_pre);
529
		PATCH_OPTION(ldap_post);
530
		PATCH_OPTION(ldap_c);
531
	}
532

    
533
	return 0;
534
}
535

    
536
CONNECTION_FUNC(mod_lvhost_handle_docroot)
537
{
538
	plugin_data *p = p_d;
539

    
540
	int n = 0;
541
	size_t i;
542
  
543
	LDAPMessage *msg, *entry;
544
	struct berval **vals;
545
	int ldap_scope = LDAP_SCOPE_SUBTREE;
546

    
547
	/* Fold if no host specified */
548
	if (!con->uri.authority->used)
549
	{
550
		log_error_write(	srv, __FILE__, __LINE__, 
551
							"s", "Exiting: no host header."	);
552
		return HANDLER_GO_ON;
553
	}
554

    
555
	/* Find the requested server name in cache */
556
	doc_cache_t *cache_entry = 0;
557

    
558
#if DEBUG==2
559
	log_error_write( 	srv, __FILE__, __LINE__, "sd",
560
						"Checking cache of size", p->cache_size );
561
#endif
562

    
563
	for(i = 0; i < p->cache_size; i++)
564
	{
565
		if(buffer_is_equal(p->doc_cache[i]->server_name, con->uri.authority))
566
		{
567
			cache_entry = p->doc_cache[i]; n=1;
568
			break;
569
		}
570
	}
571

    
572
	if( cache_entry && ( (time(0) - cache_entry->birth ) < CACHE_LIFETIME ) )
573
	{
574
		log_error_write(	srv, __FILE__, __LINE__, "sb", 
575
							"Using cache for", cache_entry->server_name	);
576
        buffer_copy_string_buffer(con->server_name, cache_entry->server_name);
577
        buffer_copy_string_buffer(con->physical.doc_root, cache_entry->docroot);
578
		return HANDLER_GO_ON;
579
	}
580

    
581
	mod_lvhost_patch_connection(srv, con, p);
582

    
583
	/* Perhaps ldap_c has become invalid?  Create a new session? */
584
	if (!p->conf.ldap_c)
585
	{
586
		log_error_write(	srv, __FILE__, __LINE__, "s", 
587
							"Exiting: no ldap handler..."	);
588
		return HANDLER_GO_ON;
589
	}
590
  
591
	buffer_copy_string_buffer(p->tmp_buf, p->conf.ldap_pre);
592
  
593
	if (p->conf.ldap_post->used)
594
	{
595
		buffer_append_string_buffer(p->tmp_buf, con->uri.authority);
596
		buffer_append_string_buffer(p->tmp_buf, p->conf.ldap_post);
597
	}
598

    
599
	if (ldap_search_ext_s(	p->conf.ldap_c, p->conf.ldap_base->ptr,
600
							ldap_scope,	p->tmp_buf->ptr, NULL,
601
							0, NULL, NULL, NULL, 0, &msg	) != LDAP_SUCCESS)
602
	{
603
		log_error_write(	srv, __FILE__, __LINE__, "sb", 
604
							"Exiting: ldap_search_ext_s failed:", p->tmp_buf);
605
	}
606
	else
607
	{
608
		/* If search successful, update the cache. */
609
		n = ldap_count_entries(p->conf.ldap_c, msg);
610
		if( !n ) return HANDLER_GO_ON;
611
		if( n>1 )
612
		{
613
			log_error_write(	srv, __FILE__, __LINE__, "sbs", 
614
								"Duplicate entry for filter:", p->tmp_buf,
615
								": Just using the first"					);
616
		}
617

    
618
		entry = ldap_first_entry(p->conf.ldap_c, msg);
619

    
620
		vals = ldap_get_values_len(	p->conf.ldap_c, entry, 
621
									p->conf.ldap_attribute->ptr );
622

    
623
		if( vals )
624
		{
625
			stat_cache_entry *sce;
626
			buffer_copy_string(p->docroot, vals[0]->bv_val);
627

    
628
			if (HANDLER_ERROR 
629
					== stat_cache_get_entry(srv, con, p->docroot, &sce))
630
			{
631
				log_error_write(	srv, __FILE__, __LINE__, "sb", 
632
									strerror(errno), p->docroot		);
633
				return HANDLER_GO_ON;
634
			}
635

    
636
			if (!S_ISDIR(sce->st.st_mode))
637
			{
638
				log_error_write(	srv, __FILE__, __LINE__, "sb", 
639
									"Not a directory", p->docroot	);
640
		    	return HANDLER_GO_ON;
641
			}
642

    
643

    
644
			if( !cache_entry )
645
			{
646
				cache_entry = malloc( sizeof(doc_cache_t) );
647
				if(!cache_entry) return HANDLER_ERROR;
648

    
649
				cache_entry->server_name = buffer_init();
650
				cache_entry->docroot = buffer_init();
651

    
652
				buffer_copy_string_buffer( 	cache_entry->server_name, 
653
											con->uri.authority );
654

    
655
				p->doc_cache = realloc( p->doc_cache, 
656
										(p->cache_size + 1) 
657
										* sizeof(doc_cache_t*) );
658

    
659
				if(!p->doc_cache) return HANDLER_ERROR;
660

    
661
				p->doc_cache[p->cache_size] = cache_entry;
662
				p->cache_size = p->cache_size + 1;
663

    
664
#if DEBUG==2
665
				log_error_write( 	srv, __FILE__, __LINE__, "sd", 
666
									"Adding doc root to cache, new size:", 
667
									p->cache_size							);
668
#endif
669

    
670
			}
671

    
672
			cache_entry->birth = time(0);
673
			buffer_copy_string_buffer(cache_entry->docroot, p->docroot);
674
		}
675
		else
676
		{
677
			/* We should remove the cache perhaps? Leave it for now. */
678
		}
679

    
680
		ldap_value_free_len(vals);
681
		ldap_msgfree(msg);
682
	}
683

    
684
	/* If we haven't gotten cache_entry by now, we are stumped. */
685
	if( !cache_entry ) return HANDLER_GO_ON;
686

    
687
	buffer_copy_string_buffer(con->server_name, cache_entry->server_name);
688
	buffer_copy_string_buffer(con->physical.doc_root, cache_entry->docroot);
689

    
690
#ifdef DEBUG
691
	log_error_write(    srv, __FILE__, __LINE__, "sb",
692
						"Server name:", con->server_name    );
693
	log_error_write(	srv, __FILE__, __LINE__, "sb", 
694
						"Document root:", con->physical.doc_root	);
695
#endif
696

    
697
	return HANDLER_GO_ON;
698
}
699

    
700
int mod_lvhost_plugin_init(plugin *p) {
701

    
702
	p->version                  = LIGHTTPD_VERSION_ID;
703
	p->name                     = buffer_init_string("lvhost");
704
	p->init                     = mod_lvhost_init;
705
	p->cleanup                  = mod_lvhost_cleanup;
706
	p->set_defaults             = mod_lvhost_set_defaults;
707
	p->handle_docroot           = mod_lvhost_handle_docroot;
708

    
709
	p->data                     = NULL;
710

    
711
	return 0;
712

    
713
}
714

    
(2-2/2)