1 #include "base.h"
2 #include "log.h"
3 #include "buffer.h"
4 
5 #include "plugin.h"
6 
7 #include "stat_cache.h"
8 
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 
14 /* plugin config for all request/connections */
15 
16 typedef struct {
17 	array *indexfiles;
18 } plugin_config;
19 
20 typedef struct {
21 	PLUGIN_DATA;
22 
23 	buffer *tmp_buf;
24 
25 	plugin_config **config_storage;
26 
27 	plugin_config conf;
28 } plugin_data;
29 
30 /* init the plugin data */
INIT_FUNC(mod_indexfile_init)31 INIT_FUNC(mod_indexfile_init) {
32 	plugin_data *p;
33 
34 	p = calloc(1, sizeof(*p));
35 
36 	p->tmp_buf = buffer_init();
37 
38 	return p;
39 }
40 
41 /* detroy the plugin data */
FREE_FUNC(mod_indexfile_free)42 FREE_FUNC(mod_indexfile_free) {
43 	plugin_data *p = p_d;
44 
45 	UNUSED(srv);
46 
47 	if (!p) return HANDLER_GO_ON;
48 
49 	if (p->config_storage) {
50 		size_t i;
51 		for (i = 0; i < srv->config_context->used; i++) {
52 			plugin_config *s = p->config_storage[i];
53 
54 			if (!s) continue;
55 
56 			array_free(s->indexfiles);
57 
58 			free(s);
59 		}
60 		free(p->config_storage);
61 	}
62 
63 	buffer_free(p->tmp_buf);
64 
65 	free(p);
66 
67 	return HANDLER_GO_ON;
68 }
69 
70 /* handle plugin config and check values */
71 
SETDEFAULTS_FUNC(mod_indexfile_set_defaults)72 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
73 	plugin_data *p = p_d;
74 	size_t i = 0;
75 
76 	config_values_t cv[] = {
77 		{ "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
78 		{ "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
79 		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
80 	};
81 
82 	if (!p) return HANDLER_ERROR;
83 
84 	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
85 
86 	for (i = 0; i < srv->config_context->used; i++) {
87 		plugin_config *s;
88 
89 		s = calloc(1, sizeof(plugin_config));
90 		s->indexfiles    = array_init();
91 
92 		cv[0].destination = s->indexfiles;
93 		cv[1].destination = s->indexfiles; /* old name for [0] */
94 
95 		p->config_storage[i] = s;
96 
97 		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
98 			return HANDLER_ERROR;
99 		}
100 	}
101 
102 	return HANDLER_GO_ON;
103 }
104 
105 #define PATCH(x) \
106 	p->conf.x = s->x;
mod_indexfile_patch_connection(server * srv,connection * con,plugin_data * p)107 static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
108 	size_t i, j;
109 	plugin_config *s = p->config_storage[0];
110 
111 	PATCH(indexfiles);
112 
113 	/* skip the first, the global context */
114 	for (i = 1; i < srv->config_context->used; i++) {
115 		data_config *dc = (data_config *)srv->config_context->data[i];
116 		s = p->config_storage[i];
117 
118 		/* condition didn't match */
119 		if (!config_check_cond(srv, con, dc)) continue;
120 
121 		/* merge config */
122 		for (j = 0; j < dc->value->used; j++) {
123 			data_unset *du = dc->value->data[j];
124 
125 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
126 				PATCH(indexfiles);
127 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
128 				PATCH(indexfiles);
129 			}
130 		}
131 	}
132 
133 	return 0;
134 }
135 #undef PATCH
136 
URIHANDLER_FUNC(mod_indexfile_subrequest)137 URIHANDLER_FUNC(mod_indexfile_subrequest) {
138 	plugin_data *p = p_d;
139 	size_t k;
140 	stat_cache_entry *sce = NULL;
141 
142 	if (con->mode != DIRECT) return HANDLER_GO_ON;
143 
144 	if (con->uri.path->used == 0) return HANDLER_GO_ON;
145 	if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
146 
147 	mod_indexfile_patch_connection(srv, con, p);
148 
149 	if (con->conf.log_request_handling) {
150 		log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
151 		log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
152 	}
153 
154 	/* indexfile */
155 	for (k = 0; k < p->conf.indexfiles->used; k++) {
156 		data_string *ds = (data_string *)p->conf.indexfiles->data[k];
157 
158 		if (ds->value && ds->value->ptr[0] == '/') {
159 			/* if the index-file starts with a prefix as use this file as
160 			 * index-generator */
161 			buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
162 		} else {
163 			buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
164 		}
165 		buffer_append_string_buffer(p->tmp_buf, ds->value);
166 
167 		if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
168 			if (errno == EACCES) {
169 				con->http_status = 403;
170 				buffer_reset(con->physical.path);
171 
172 				return HANDLER_FINISHED;
173 			}
174 
175 			if (errno != ENOENT &&
176 			    errno != ENOTDIR) {
177 				/* we have no idea what happend. let's tell the user so. */
178 
179 				con->http_status = 500;
180 
181 				log_error_write(srv, __FILE__, __LINE__, "ssbsb",
182 						"file not found ... or so: ", strerror(errno),
183 						con->uri.path,
184 						"->", con->physical.path);
185 
186 				buffer_reset(con->physical.path);
187 
188 				return HANDLER_FINISHED;
189 			}
190 			continue;
191 		}
192 
193 		/* rewrite uri.path to the real path (/ -> /index.php) */
194 		buffer_append_string_buffer(con->uri.path, ds->value);
195 		buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
196 
197 		/* fce is already set up a few lines above */
198 
199 		return HANDLER_GO_ON;
200 	}
201 
202 	/* not found */
203 	return HANDLER_GO_ON;
204 }
205 
206 /* this function is called at dlopen() time and inits the callbacks */
207 
208 int mod_indexfile_plugin_init(plugin *p);
mod_indexfile_plugin_init(plugin * p)209 int mod_indexfile_plugin_init(plugin *p) {
210 	p->version     = LIGHTTPD_VERSION_ID;
211 	p->name        = buffer_init_string("indexfile");
212 
213 	p->init        = mod_indexfile_init;
214 	p->handle_subrequest_start = mod_indexfile_subrequest;
215 	p->set_defaults  = mod_indexfile_set_defaults;
216 	p->cleanup     = mod_indexfile_free;
217 
218 	p->data        = NULL;
219 
220 	return 0;
221 }
222