about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--INSTALL4
-rw-r--r--doc/index.html6
-rw-r--r--doc/tipidee.conf.html31
-rw-r--r--doc/upgrade.html10
-rw-r--r--package/deps.mak3
-rw-r--r--package/info2
-rw-r--r--src/config/defaults.c1
-rw-r--r--src/config/lexparse.c1
-rw-r--r--src/tipideed/deps-exe/tipideed1
-rw-r--r--src/tipideed/responses.c41
-rw-r--r--src/tipideed/tipideed-internal.h9
-rw-r--r--src/tipideed/tipideed.c18
-rw-r--r--src/tipideed/util.c29
13 files changed, 118 insertions, 38 deletions
diff --git a/INSTALL b/INSTALL
index 5e148af..e1ca77e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,8 +6,8 @@ Build Instructions
 
   - A POSIX-compliant C development environment
   - GNU make version 3.81 or later
-  - skalibs version 2.14.0.1 or later: https://skarnet.org/software/skalibs/
-  - (optional but recommended): s6-networking version 2.7.0.0 or later:
+  - skalibs version 2.14.1.0 or later: https://skarnet.org/software/skalibs/
+  - (optional but recommended): s6-networking version 2.7.0.1 or later:
       https://skarnet.org/software/s6-networking/
 
  This software will run on any operating system that implements
diff --git a/doc/index.html b/doc/index.html
index 0db88cd..2aef76b 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -111,11 +111,11 @@ make it shorter. Just like the code.
  <li> A POSIX-compliant system with a standard C development environment </li>
  <li> GNU make, version 3.81 or later </li>
  <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
-2.14.0.1 or later. It's a build-time requirement. It's also a run-time
+2.14.1.0 or later. It's a build-time requirement. It's also a run-time
 requirement if you link against the shared version of the skalibs
 library. </li>
  <li> Recommended at run-time: <a href="//skarnet.org/software/s6-networking/">s6-networking</a> version
-2.7.0.0 or later. It's not a strict requirement, but tipidee relies on a super-server such as
+2.7.0.1 or later. It's not a strict requirement, but tipidee relies on a super-server such as
 <a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a>
 to listen to the network and provide connection
 information via environment variables. It also defers to tools such as
@@ -143,7 +143,7 @@ Don't take my word for it; try it out for yourself. </li>
 
 <ul>
  <li> The current released version of tipidee is
-<a href="tipidee-0.0.2.0.tar.gz">0.0.2.0</a>. </li>
+<a href="tipidee-0.0.3.0.tar.gz">0.0.3.0</a>. </li>
  <li> You can checkout a copy of the
 <a href="//git.skarnet.org/cgi-bin/cgit.cgi/tipidee/">tipidee
 git repository</a>:
diff --git a/doc/tipidee.conf.html b/doc/tipidee.conf.html
index 691ac94..17c1a4f 100644
--- a/doc/tipidee.conf.html
+++ b/doc/tipidee.conf.html
@@ -302,6 +302,37 @@ a directive can protect dynamically managed content that is restricted
 to a given hierarchy. </li>
 </ul>
 
+<div id="XXX_no_translate">
+<h4> <tt>XXX_no_translate</tt> </h4>
+</div>
+
+<p>
+ <code> global XXX_no_translate <em>value</em> </code>
+</p>
+
+<ul>
+ <li> This directive is dangerous and significantly changes the behaviour of tipideed,
+which is why it is marked with the <tt>XXX_</tt> prefix. If you are not 100% certain
+that you need it, do not use it. </li>
+ <li> <em>value</em> is a non-negative integer. If it is nonzero, then:
+  <ul>
+   <li> Symbolic links are <em>not resolved</em> when tipidee looks for resources
+or error pages. This means that host names and resource paths will be looked up
+in the configuration database as they are given by the client, not as they appear
+in the filesystem. </li>
+    <ul>
+     <li> In particular, a same resource could have different attributes depending on how
+it is accessed: it could be seen as a CGI script from one URI and as a regular file from
+another. </li>
+     <li> This also means that if your configuration file needs local directives, you must
+specify them for every host/port combination your server is listening on. </li>
+    </ul> </li>
+   <li> If tipideed is not chrooted, symbolic links <em>may</em> point outside of the
+server root: this will not be checked. This allows you to serve data from other parts
+of the filesystem. </li>
+  </ul> </li>
+</ul>
+
 <div id="index-file">
 <h3> The <tt>index-file</tt> directive </h3>
 </div>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 74f7594..f2a6880 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,6 +18,16 @@
 
 <h1> What has changed in tipidee </h1>
 
+<h2> in.0.0.3.0 </h2>
+
+<ul>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a>
+dependency bumped to 2.14.1.0 </li>
+ <li> <a href="//skarnet.org/software/s6-networking/">s6-networking</a>
+recommendation bumped to 2.7.0.1 </li>
+ <li> New <tt>global XXX_no_translate</tt> configuration directive. </li>
+</ul>
+
 <h2> in.0.0.2.0 </h2>
 
 <ul>
diff --git a/package/deps.mak b/package/deps.mak
index 9ef8eed..cd49648 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -67,6 +67,7 @@ src/tipideed/responses.o src/tipideed/responses.lo: src/tipideed/responses.c src
 src/tipideed/send_file.o src/tipideed/send_file.lo: src/tipideed/send_file.c src/tipideed/tipideed-internal.h
 src/tipideed/tipideed.o src/tipideed/tipideed.lo: src/tipideed/tipideed.c src/include/tipidee/tipidee.h src/tipideed/tipideed-internal.h
 src/tipideed/trace.o src/tipideed/trace.lo: src/tipideed/trace.c src/include/tipidee/log.h src/include/tipidee/method.h src/include/tipidee/response.h src/tipideed/tipideed-internal.h
+src/tipideed/util.o src/tipideed/util.lo: src/tipideed/util.c src/tipideed/tipideed-internal.h
 
 tipidee-config: EXTRA_LIBS := -lskarnet ${SPAWN_LIB}
 tipidee-config: src/config/tipidee-config.o src/config/util.o src/config/node.o src/config/repo.o src/config/conftree.o src/config/headers.o src/config/defaults.o src/config/lexparse.o
@@ -80,5 +81,5 @@ endif
 libtipidee.so.xyzzy: EXTRA_LIBS := -lskarnet
 libtipidee.so.xyzzy: src/libtipidee/tipidee_conf_free.lo src/libtipidee/tipidee_conf_get.lo src/libtipidee/tipidee_conf_get_argv.lo src/libtipidee/tipidee_conf_get_content_type.lo src/libtipidee/tipidee_conf_get_errorfile.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_resattr.lo src/libtipidee/tipidee_conf_get_resattr1.lo src/libtipidee/tipidee_conf_get_responseheaders.lo src/libtipidee/tipidee_conf_get_string.lo src/libtipidee/tipidee_conf_get_uint32.lo src/libtipidee/tipidee_conf_init.lo src/libtipidee/tipidee_headers_get_content_length.lo src/libtipidee/tipidee_headers_init.lo src/libtipidee/tipidee_headers_parse.lo src/libtipidee/tipidee_headers_search.lo src/libtipidee/tipidee_log_answer.lo src/libtipidee/tipidee_log_exit.lo src/libtipidee/tipidee_log_resource.lo src/libtipidee/tipidee_log_request.lo src/libtipidee/tipidee_log_start.lo src/libtipidee/tipidee_method.lo src/libtipidee/tipidee_response_error_nofile.lo src/libtipidee/tipidee_response_error_nofile_G.lo src/libtipidee/tipidee_response_file.lo src/libtipidee/tipidee_response_file_G.lo src/libtipidee/tipidee_response_header_date.lo src/libtipidee/tipidee_response_header_date_G.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_header_preparebuiltin.lo src/libtipidee/tipidee_response_header_writeall.lo src/libtipidee/tipidee_response_header_writeall_G.lo src/libtipidee/tipidee_response_header_writemerge.lo src/libtipidee/tipidee_response_header_writemerge_G.lo src/libtipidee/tipidee_response_status.lo src/libtipidee/tipidee_rql_read.lo src/libtipidee/tipidee_uri_parse.lo src/libtipidee/tipidee_util_chunked_read.lo src/libtipidee/tipidee_util_defaulttext.lo src/libtipidee/tipidee_util_httpdate.lo
 tipideed: EXTRA_LIBS := -lskarnet
-tipideed: src/tipideed/tipideed.o src/tipideed/cgi.o src/tipideed/harden.o src/tipideed/options.o src/tipideed/regular.o src/tipideed/responses.o src/tipideed/send_file.o src/tipideed/trace.o libtipidee.a.xyzzy
+tipideed: src/tipideed/tipideed.o src/tipideed/cgi.o src/tipideed/harden.o src/tipideed/options.o src/tipideed/regular.o src/tipideed/responses.o src/tipideed/send_file.o src/tipideed/trace.o src/tipideed/util.o libtipidee.a.xyzzy
 INTERNAL_LIBS :=
diff --git a/package/info b/package/info
index 3492464..a525420 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
 package=tipidee
-version=0.0.2.0
+version=0.0.3.0
 category=web
 package_macro_name=TIPIDEE
diff --git a/src/config/defaults.c b/src/config/defaults.c
index 7dbab8a..18dfa7e 100644
--- a/src/config/defaults.c
+++ b/src/config/defaults.c
@@ -25,6 +25,7 @@ static struct defaults_s const defaults[] =
   RECU32("G:max_cgi_body_length", 4194304),
   RECU32("G:logv", TIPIDEE_LOG_DEFAULT),
   RECU32("G:executable_means_cgi", 0),
+  RECU32("G:XXX_no_translate", 0),
   RECS("G:index-file", "index.html"),
 
   RECS("T:html", "text/html"),
diff --git a/src/config/lexparse.c b/src/config/lexparse.c
index 99eeaa0..d5fcf6d 100644
--- a/src/config/lexparse.c
+++ b/src/config/lexparse.c
@@ -97,6 +97,7 @@ static inline void parse_global (char const *s, size_t const *word, size_t n, md
 {
   static char const *const globalkeys[] =
   {
+    "XXX_no_translate",
     "cgi_timeout",
     "executable_means_cgi",
     "max_cgi_body_length",
diff --git a/src/tipideed/deps-exe/tipideed b/src/tipideed/deps-exe/tipideed
index e1a6c0a..8e5263e 100644
--- a/src/tipideed/deps-exe/tipideed
+++ b/src/tipideed/deps-exe/tipideed
@@ -5,5 +5,6 @@ regular.o
 responses.o
 send_file.o
 trace.o
+util.o
 libtipidee.a.xyzzy
 -lskarnet
diff --git a/src/tipideed/responses.c b/src/tipideed/responses.c
index ad53351..6e32ea9 100644
--- a/src/tipideed/responses.c
+++ b/src/tipideed/responses.c
@@ -40,21 +40,14 @@ void response_error (tipidee_rql const *rql, char const *docroot, unsigned int s
 {
   tain deadline ;
   tipidee_defaulttext dt ;
-  char const *file = 0;
-  size_t salen = g.sa.len ;
+  char const *file = 0 ;
+  size_t pos = translate_path(docroot) ;
 
-  if (sarealpath(&g.sa, docroot) == -1)
-  {
-    if (errno != ENOENT) strerr_diefu2sys(111, "realpath ", docroot) ;
-  }
-  else
-  {
-    if (!stralloc_0(&g.sa)) strerr_diefu1sys(111, "build response") ;
-    if (strncmp(g.sa.s + salen, g.sa.s, g.cwdlen) || g.sa.s[salen + g.cwdlen] != '/')
-      strerr_dief4x(102, "layout error: ", "docroot ", docroot, " points outside of the server's root") ;
-    file = tipidee_conf_get_errorfile(&g.conf, g.sa.s + salen + g.cwdlen + 1, status) ;
-    g.sa.len = salen ;
-  }
+  if (pos) file = tipidee_conf_get_errorfile(&g.conf, g.sa.s + pos , status) ;
+  else if (errno == EPERM)
+    strerr_dief4x(102, "layout error: ", "docroot ", docroot, " points outside of the server's root") ;
+  else if (errno != ENOENT)
+    strerr_diefu2sys(111, "translate_path ", docroot) ;
 
   if (!tipidee_util_defaulttext(status, &dt))
   {
@@ -65,13 +58,17 @@ void response_error (tipidee_rql const *rql, char const *docroot, unsigned int s
 
   if (file)
   {
-    if (sarealpath(&g.sa, file) == -1 || !stralloc_0(&g.sa))
-      strerr_warnwu3sys("realpath ", "custom response file ", file) ;
-    else if (strncmp(g.sa.s + salen, g.sa.s, g.cwdlen) || g.sa.s[salen + g.cwdlen] != '/')
-      strerr_warnw4x("layout error: ", "custom response file ", file, " points outside of the server's root") ;
+    pos = translate_path(file) ;
+    if (!pos)
+    {
+      if (errno == EPERM)
+        strerr_warnw4x("layout error: ", "custom response file ", file, " points outside of the server's root") ;
+      else
+        strerr_warnwu3sys("translate_path ", "custom response file ", file) ;
+    }
     else
     {
-      int fd = open_read(g.sa.s + salen + g.cwdlen + 1) ;
+      int fd = open_read(g.sa.s + pos) ;
       if (fd == -1) strerr_warnwu3sys("open ", "custom response file ", file) ;
       else
       {
@@ -88,16 +85,14 @@ void response_error (tipidee_rql const *rql, char const *docroot, unsigned int s
         }
         else
         {
-          tipidee_response_file_G(buffer_1, rql, status, dt.reason, &st, tipidee_conf_get_content_type(&g.conf, g.sa.s + salen + g.cwdlen + 1), g.rhdr, g.rhdrn, options) ;
+          tipidee_response_file_G(buffer_1, rql, status, dt.reason, &st, tipidee_conf_get_content_type(&g.conf, g.sa.s + pos), g.rhdr, g.rhdrn, options) ;
           tipidee_log_answer(g.logv, rql, status, st.st_size) ;
-          send_file(fd, st.st_size, g.sa.s + salen + g.cwdlen + 1) ;
+          send_file(fd, st.st_size, g.sa.s + pos) ;
           fd_close(fd) ;
-          g.sa.len = salen ;
           return ;
         }
       }
     }
-    g.sa.len = salen ;
   }
 
   tipidee_response_error_nofile_G(buffer_1, rql, status, dt.reason, dt.text, g.rhdr, g.rhdrn, options & 1 || !g.cont) ;
diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h
index 8b0e114..8631861 100644
--- a/src/tipideed/tipideed-internal.h
+++ b/src/tipideed/tipideed-internal.h
@@ -41,6 +41,7 @@ struct global_s
   uint16_t cont : 2 ;
   uint16_t ssl : 1 ;
   uint16_t xiscgi : 1 ;
+  uint8_t flagnoxlate : 1 ;
 } ;
 #define GLOBAL_ZERO \
 { \
@@ -64,7 +65,8 @@ struct global_s
   .indexn = 0, \
   .cont = 1, \
   .ssl = 0, \
-  .xiscgi = 0 \
+  .xiscgi = 0, \
+  .flagnoxlate = 0 \
 }
 
 extern struct global_s g ;
@@ -138,6 +140,11 @@ extern int respond_304 (tipidee_rql const *, char const *, struct stat const *)
 extern int respond_cgi (tipidee_rql *, char const *, char const *, size_t, char const *, char *, tipidee_headers const *, tipidee_resattr const *, char const *, size_t) ;
 
 
+ /* util */
+
+extern size_t translate_path (char const *) ;
+
+
  /* main */
 
 extern void log_and_exit (int) gccattr_noreturn ;
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index 0f5d44c..8323db1 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -195,13 +195,16 @@ static inline unsigned int indexify (tipidee_rql const *rql, char const *docroot
 
 static inline void get_resattr (tipidee_rql const *rql, char const *docroot, char const *res, tipidee_resattr *ra)
 {
-  size_t pos = g.sa.len ;
-  if (sarealpath(&g.sa, res) == -1 || !stralloc_0(&g.sa)) die500sys(rql, 111, docroot, "realpath ", res) ;
-  if (strncmp(g.sa.s + pos, g.sa.s, g.cwdlen) || g.sa.s[pos + g.cwdlen] != '/')
-    die500x(rql, 102, docroot, "resource ", res, " points outside of the server's root") ;
-  if (!tipidee_conf_get_resattr(&g.conf, g.sa.s + pos + g.cwdlen + 1, ra))
-    die500sys(rql, 102, docroot, "look up resource attributes for ", g.sa.s + pos + g.cwdlen + 1) ;
-  g.sa.len = pos ;
+  size_t pos = translate_path(res) ;
+  if (!pos)
+  {
+    if (errno == EPERM)
+      die500x(rql, 102, docroot, "resource ", res, " points outside of the server's root") ;
+    else
+      die500sys(rql, 111, docroot, "path_canonicalize ", res) ;
+  }
+  if (!tipidee_conf_get_resattr(&g.conf, g.sa.s + pos, ra))
+    die500sys(rql, 102, docroot, "look up resource attributes for ", g.sa.s + pos) ;
 }
 
 static inline void force_redirect (tipidee_rql const *rql, char const *fn)
@@ -353,6 +356,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
   g.maxcgibody = get_uint32("G:max_cgi_body_length") ;
   g.logv = get_uint32("G:logv") ;
   g.xiscgi = !!get_uint32("G:executable_means_cgi") ;
+  g.flagnoxlate = !!get_uint32("G:XXX_no_translate") ;
   n = tipidee_conf_get_argv(&g.conf, "G:index-file", g.indexnames, 16, &g.indexlen) ;
   if (!n) strerr_dief3x(102, "bad", " config value for ", "G:index_file") ;
   g.indexn = n-1 ;
diff --git a/src/tipideed/util.c b/src/tipideed/util.c
new file mode 100644
index 0000000..2891306
--- /dev/null
+++ b/src/tipideed/util.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <string.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+#include "tipideed-internal.h"
+
+size_t translate_path (char const *path)
+{
+  size_t n = g.sa.len ;
+  if (g.flagnoxlate)
+  {
+    if (!stralloc_readyplus(&g.sa, strlen(path) + 2)) return 0 ;
+    path_canonicalize(g.sa.s + n, path, 0) ;
+    return n ;
+  }
+  if (sarealpath(&g.sa, path) == -1 || !stralloc_0(&g.sa))
+  {
+    g.sa.len = n ;
+    return 0 ;
+  }
+  g.sa.len = n ;
+  if (strncmp(g.sa.s + n, g.sa.s, g.cwdlen) || g.sa.s[n + g.cwdlen] != '/')
+    return (errno = EPERM, 0) ;
+  return n + g.cwdlen + 1 ;
+}