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
|
|