--- embedaddon/lighttpd/src/mod_dirlisting.c 2013/10/14 10:32:47 1.1 +++ embedaddon/lighttpd/src/mod_dirlisting.c 2016/11/02 10:35:00 1.1.1.3 @@ -1,3 +1,5 @@ +#include "first.h" + #include "base.h" #include "log.h" #include "buffer.h" @@ -14,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -22,16 +25,13 @@ * this is a dirlisting for a lighttpd plugin */ - -#ifdef HAVE_SYS_SYSLIMITS_H -#include -#endif - #ifdef HAVE_ATTR_ATTRIBUTES_H #include #endif -#include "version.h" +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif /* plugin config for all request/connections */ @@ -120,7 +120,7 @@ static int excludes_buffer_append(excludes_buffer *exb } exb->ptr[exb->used]->string = buffer_init(); - buffer_copy_string_buffer(exb->ptr[exb->used]->string, string); + buffer_copy_buffer(exb->ptr[exb->used]->string, string); exb->used++; @@ -194,47 +194,6 @@ FREE_FUNC(mod_dirlisting_free) { return HANDLER_GO_ON; } -static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option) { - data_unset *du; - - if (NULL != (du = array_get_element(ca, option))) { - data_array *da; - size_t j; - - if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", - "unexpected type for key: ", option, "array of strings"); - - return HANDLER_ERROR; - } - - da = (data_array *)du; - - for (j = 0; j < da->value->used; j++) { - if (da->value->data[j]->type != TYPE_STRING) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", option, "[", - da->value->data[j]->key, "](string)"); - - return HANDLER_ERROR; - } - - if (0 != excludes_buffer_append(s->excludes, - ((data_string *)(da->value->data[j]))->value)) { -#ifdef HAVE_PCRE_H - log_error_write(srv, __FILE__, __LINE__, "sb", - "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value); -#else - log_error_write(srv, __FILE__, __LINE__, "s", - "pcre support is missing, please install libpcre and the headers"); -#endif - } - } - } - - return 0; -} - /* handle plugin config and check values */ #define CONFIG_EXCLUDE "dir-listing.exclude" @@ -278,17 +237,18 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) { if (!p) return HANDLER_ERROR; - p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); + p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); for (i = 0; i < srv->config_context->used; i++) { + data_config const* config = (data_config const*)srv->config_context->data[i]; plugin_config *s; - array *ca; + data_unset *du_excludes; s = calloc(1, sizeof(plugin_config)); s->excludes = excludes_buffer_init(); s->dir_listing = 0; s->external_css = buffer_init(); - s->hide_dot_files = 0; + s->hide_dot_files = 1; s->show_readme = 0; s->hide_readme_file = 0; s->show_header = 0; @@ -316,13 +276,48 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) { cv[13].destination = &(s->auto_layout); p->config_storage[i] = s; - ca = ((data_config *)srv->config_context->data[i])->value; - if (0 != config_insert_values_global(srv, ca, cv)) { + if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { return HANDLER_ERROR; } - parse_config_entry(srv, s, ca, CONFIG_EXCLUDE); + if (NULL != (du_excludes = array_get_element(config->value, CONFIG_EXCLUDE))) { + array *excludes_list; + size_t j; + + if (du_excludes->type != TYPE_ARRAY) { + log_error_write(srv, __FILE__, __LINE__, "sss", + "unexpected type for key: ", CONFIG_EXCLUDE, "array of strings"); + return HANDLER_ERROR; + } + + excludes_list = ((data_array*)du_excludes)->value; + +#ifndef HAVE_PCRE_H + if (excludes_list->used > 0) { + log_error_write(srv, __FILE__, __LINE__, "sss", + "pcre support is missing for: ", CONFIG_EXCLUDE, ", please install libpcre and the headers"); + return HANDLER_ERROR; + } +#else + for (j = 0; j < excludes_list->used; j++) { + data_unset *du_exclude = excludes_list->data[j]; + + if (du_exclude->type != TYPE_STRING) { + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", CONFIG_EXCLUDE, "[", + du_exclude->key, "](string)"); + return HANDLER_ERROR; + } + + if (0 != excludes_buffer_append(s->excludes, ((data_string*)(du_exclude))->value)) { + log_error_write(srv, __FILE__, __LINE__, "sb", + "pcre-compile failed for", ((data_string*)(du_exclude))->value); + return HANDLER_ERROR; + } + } +#endif + } } return HANDLER_GO_ON; @@ -441,11 +436,11 @@ static void http_dirls_sort(dirls_entry_t **ent, int n /* buffer must be able to hold "999.9K" * conversion is simple but not perfect */ -static int http_list_directory_sizefmt(char *buf, off_t size) { - const char unit[] = "KMGTPE"; /* Kilo, Mega, Tera, Peta, Exa */ - const char *u = unit - 1; /* u will always increment at least once */ +static int http_list_directory_sizefmt(char *buf, size_t bufsz, off_t size) { + const char unit[] = " KMGTPE"; /* Kilo, Mega, Giga, Tera, Peta, Exa */ + const char *u = unit; /* u will always increment at least once */ int remain; - char *out = buf; + size_t buflen; if (size < 100) size += 99; @@ -469,15 +464,51 @@ static int http_list_directory_sizefmt(char *buf, off_ u++; } - out += LI_ltostr(out, size); - out[0] = '.'; - out[1] = remain + '0'; - out[2] = *u; - out[3] = '\0'; + li_itostrn(buf, bufsz, size); + buflen = strlen(buf); + if (buflen + 3 >= bufsz) return buflen; + buf[buflen+0] = '.'; + buf[buflen+1] = remain + '0'; + buf[buflen+2] = *u; + buf[buflen+3] = '\0'; - return (out + 3 - buf); + return buflen + 3; } +/* don't want to block when open()ing a fifo */ +#if defined(O_NONBLOCK) +# define FIFO_NONBLOCK O_NONBLOCK +#else +# define FIFO_NONBLOCK 0 +#endif + +static void http_list_directory_include_file(buffer *out, buffer *path, const char *classname, int encode) { + int fd = open(path->ptr, O_RDONLY | FIFO_NONBLOCK); + ssize_t rd; + char buf[8192]; + + if (-1 == fd) return; + + if (encode) { + buffer_append_string_len(out, CONST_STR_LEN("
"));
+	}
+
+	while ((rd = read(fd, buf, sizeof(buf))) > 0) {
+		if (encode) {
+			buffer_append_string_encoded(out, buf, (size_t)rd, ENCODING_MINIMAL_XML);
+		} else {
+			buffer_append_string_len(out, buf, (size_t)rd);
+		}
+	}
+	close(fd);
+
+	if (encode) {
+		buffer_append_string_len(out, CONST_STR_LEN("
")); + } +} + static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); @@ -491,7 +522,7 @@ static void http_list_directory_header(server *srv, co buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("\n")); - if (p->conf.external_css->used > 1) { + if (!buffer_string_is_empty(p->conf.external_css)) { buffer_append_string_len(out, CONST_STR_LEN("conf.external_css); buffer_append_string_len(out, CONST_STR_LEN("\" />\n")); @@ -536,23 +567,13 @@ static void http_list_directory_header(server *srv, co /* HEADER.txt */ if (p->conf.show_header) { - stream s; /* if we have a HEADER file, display it in
 */
 
-		buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
-		BUFFER_APPEND_SLASH(p->tmp_buf);
+		buffer_copy_buffer(p->tmp_buf, con->physical.path);
+		buffer_append_slash(p->tmp_buf);
 		buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt"));
 
-		if (-1 != stream_open(&s, p->tmp_buf)) {
-			if (p->conf.encode_header) {
-				buffer_append_string_len(out, CONST_STR_LEN("
"));
-				buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
-				buffer_append_string_len(out, CONST_STR_LEN("
")); - } else { - buffer_append_string_len(out, s.start, s.size); - } - } - stream_close(&s); + http_list_directory_include_file(out, p->tmp_buf, "header", p->conf.encode_header); } buffer_append_string_len(out, CONST_STR_LEN("

Index of ")); @@ -570,7 +591,7 @@ static void http_list_directory_header(server *srv, co "" "\n" "\n" - "" + "" "Parent Directory/" " " "-  " @@ -589,23 +610,13 @@ static void http_list_directory_footer(server *srv, co )); if (p->conf.show_readme) { - stream s; /* if we have a README file, display it in
 */
 
-		buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
-		BUFFER_APPEND_SLASH(p->tmp_buf);
+		buffer_copy_buffer(p->tmp_buf,  con->physical.path);
+		buffer_append_slash(p->tmp_buf);
 		buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));
 
-		if (-1 != stream_open(&s, p->tmp_buf)) {
-			if (p->conf.encode_readme) {
-				buffer_append_string_len(out, CONST_STR_LEN("
"));
-				buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
-				buffer_append_string_len(out, CONST_STR_LEN("
")); - } else { - buffer_append_string_len(out, s.start, s.size); - } - } - stream_close(&s); + http_list_directory_include_file(out, p->tmp_buf, "readme", p->conf.encode_readme); } if(p->conf.auto_layout) { @@ -613,10 +624,8 @@ static void http_list_directory_footer(server *srv, co "
" )); - if (p->conf.set_footer->used > 1) { + if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); - } else if (buffer_is_empty(con->conf.server_tag)) { - buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC)); } else { buffer_append_string_buffer(out, con->conf.server_tag); } @@ -644,7 +653,7 @@ static int http_list_directory(server *srv, connection size_t k; const char *content_type; long name_max; -#ifdef HAVE_XATTR +#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) char attrval[128]; int attrlen; #endif @@ -652,9 +661,9 @@ static int http_list_directory(server *srv, connection struct tm tm; #endif - if (dir->used == 0) return -1; + if (buffer_string_is_empty(dir)) return -1; - i = dir->used - 1; + i = buffer_string_length(dir); #ifdef HAVE_PATHCONF if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { @@ -671,9 +680,9 @@ static int http_list_directory(server *srv, connection name_max = NAME_MAX; #endif - path = malloc(dir->used + name_max); - assert(path); - strcpy(path, dir->ptr); + path = malloc(i + name_max + 1); + force_assert(NULL != path); + memcpy(path, dir->ptr, i+1); path_file = path + i; if (NULL == (dp = opendir(path))) { @@ -685,11 +694,11 @@ static int http_list_directory(server *srv, connection } dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); - assert(dirs.ent); + force_assert(dirs.ent); dirs.size = DIRLIST_BLOB_SIZE; dirs.used = 0; files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); - assert(files.ent); + force_assert(files.ent); files.size = DIRLIST_BLOB_SIZE; files.used = 0; @@ -730,7 +739,11 @@ static int http_list_directory(server *srv, connection log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching:", n); - return -1; + /* aborting would require a lot of manual cleanup here. + * skip instead (to not leak names that break pcre matching) + */ + exclude_match = 1; + break; } } else { @@ -762,7 +775,7 @@ static int http_list_directory(server *srv, connection if (list->used == list->size) { list->size += DIRLIST_BLOB_SIZE; list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size); - assert(list->ent); + force_assert(list->ent); } tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i); @@ -779,9 +792,9 @@ static int http_list_directory(server *srv, connection if (files.used) http_dirls_sort(files.ent, files.used); - out = chunkqueue_get_append_buffer(con->write_queue); + out = buffer_init(); buffer_copy_string_len(out, CONST_STR_LEN("conf.encoding)) { + if (buffer_string_is_empty(p->conf.encoding)) { buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1")); } else { buffer_append_string_buffer(out, p->conf.encoding); @@ -800,7 +813,7 @@ static int http_list_directory(server *srv, connection strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif - buffer_append_string_len(out, CONST_STR_LEN("namelen, ENCODING_REL_URI_PART); buffer_append_string_len(out, CONST_STR_LEN("/\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); @@ -816,16 +829,23 @@ static int http_list_directory(server *srv, connection tmp = files.ent[i]; content_type = NULL; -#ifdef HAVE_XATTR - +#if defined(HAVE_XATTR) if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); attrlen = sizeof(attrval) - 1; - if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) { + if (attr_get(path, srv->srvconf.xattr_name->ptr, attrval, &attrlen, 0) == 0) { attrval[attrlen] = '\0'; content_type = attrval; } } +#elif defined(HAVE_EXTATTR) + if (con->conf.use_xattr) { + memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); + if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, srv->srvconf.xattr_name->ptr, attrval, sizeof(attrval)-1))) { + attrval[attrlen] = '\0'; + content_type = attrval; + } + } #endif if (content_type == NULL) { @@ -834,10 +854,10 @@ static int http_list_directory(server *srv, connection data_string *ds = (data_string *)con->conf.mimetypes->data[k]; size_t ct_len; - if (ds->key->used == 0) + if (buffer_is_empty(ds->key)) continue; - ct_len = ds->key->used - 1; + ct_len = buffer_string_length(ds->key); if (tmp->namelen < ct_len) continue; @@ -854,7 +874,7 @@ static int http_list_directory(server *srv, connection #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif - http_list_directory_sizefmt(sizebuf, tmp->size); + http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size); buffer_append_string_len(out, CONST_STR_LEN("namelen, ENCODING_REL_URI_PART); @@ -878,7 +898,7 @@ static int http_list_directory(server *srv, connection http_list_directory_footer(srv, con, p, out); /* Insert possible charset to Content-Type */ - if (buffer_is_empty(p->conf.encoding)) { + if (buffer_string_is_empty(p->conf.encoding)) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); } else { buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset=")); @@ -887,6 +907,8 @@ static int http_list_directory(server *srv, connection } con->file_finished = 1; + chunkqueue_append_buffer(con->write_queue, out); + buffer_free(out); return 0; } @@ -911,9 +933,9 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) { if (con->mode != DIRECT) return HANDLER_GO_ON; - if (con->physical.path->used == 0) return HANDLER_GO_ON; - if (con->uri.path->used == 0) return HANDLER_GO_ON; - if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON; + if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON; + if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON; mod_dirlisting_patch_connection(srv, con, p);