add new url stripping option:
authorchrisz <chrisz@openbsd.org>
Sun, 4 Jan 2015 22:23:58 +0000 (22:23 +0000)
committerchrisz <chrisz@openbsd.org>
Sun, 4 Jan 2015 22:23:58 +0000 (22:23 +0000)
strip number
Strip number path components from the beginning of the
request URI before looking up the stripped-down URI at
the document root.

reviewed with much patience and OK by reyk@

usr.sbin/httpd/httpd.conf.5
usr.sbin/httpd/httpd.h
usr.sbin/httpd/parse.y
usr.sbin/httpd/server_fcgi.c
usr.sbin/httpd/server_file.c
usr.sbin/httpd/server_http.c

index ff0152a..b582385 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: httpd.conf.5,v 1.41 2015/01/03 15:49:18 reyk Exp $
+.\"    $OpenBSD: httpd.conf.5,v 1.42 2015/01/04 22:23:58 chrisz Exp $
 .\"
 .\" Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: January 3 2015 $
+.Dd $Mdocdate: January 4 2015 $
 .Dt HTTPD.CONF 5
 .Os
 .Sh NAME
@@ -250,7 +250,10 @@ Enable or disable logging to
 .Xr syslog 3
 instead of the log files.
 .El
-.It Ic root Ar directory
+.It Ic root Ar option
+Valid options are:
+.Bl -tag -width Ds
+.It Ar directory
 Set the document root of the server.
 The
 .Ar directory
@@ -260,6 +263,12 @@ root directory of
 .Nm httpd .
 If not specified, it defaults to
 .Pa /htdocs .
+.It Ic strip Ar number
+Strip
+.Ar number
+path components from the beginning of the request URI before
+looking up the stripped-down URI at the document root.
+.El
 .It Ic tcp Ar option
 Enable or disable the specified TCP/IP options; see
 .Xr tcp 4
index 3bcd4b7..12aa1a1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.65 2015/01/02 19:09:52 reyk Exp $ */
+/*     $OpenBSD: httpd.h,v 1.66 2015/01/04 22:23:58 chrisz Exp $       */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -385,6 +385,7 @@ struct server_config {
        char                    *tls_key_file;
 
        u_int32_t                flags;
+       int                      strip;
        u_int8_t                 tcpflags;
        int                      tcpbufsiz;
        int                      tcpbacklog;
@@ -524,6 +525,8 @@ int  server_response_http(struct client *, u_int, struct media_type *,
 void    server_reset_http(struct client *);
 void    server_close_http(struct client *);
 int     server_response(struct httpd *, struct client *);
+const char *
+        server_root_strip(const char *, int);
 struct server_config *
         server_getlocation(struct client *, const char *);
 const char *
index e8f9b10..5a9616c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.49 2015/01/03 23:54:25 reyk Exp $ */
+/*     $OpenBSD: parse.y,v 1.50 2015/01/04 22:23:58 chrisz Exp $       */
 
 /*
  * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -130,7 +130,7 @@ typedef struct {
 %token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
 %token COMBINED CONNECTION DIRECTORY ERR FCGI INDEX IP KEY LISTEN LOCATION
 %token LOG LOGDIR MAXIMUM NO NODELAY ON PORT PREFORK REQUEST REQUESTS ROOT
-%token SACK SERVER SOCKET STYLE SYSLOG TCP TIMEOUT TLS TYPES
+%token SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT TLS TYPES 
 %token ERROR INCLUDE
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
@@ -434,17 +434,8 @@ serveroptsl        : LISTEN ON STRING opttls port {
                                YYERROR;
                        }
                } tls
-               | ROOT STRING           {
-                       if (strlcpy(srv->srv_conf.root, $2,
-                           sizeof(srv->srv_conf.root)) >=
-                           sizeof(srv->srv_conf.root)) {
-                               yyerror("document root too long");
-                               free($2);
-                               YYERROR;
-                       }
-                       free($2);
-                       srv->srv_conf.flags |= SRVFLAG_ROOT;
-               }
+               | ROOT rootflags
+               | ROOT '{' rootflags_l '}'
                | DIRECTORY dirflags
                | DIRECTORY '{' dirflags_l '}'
                | logformat
@@ -625,6 +616,30 @@ tlsopts            : CERTIFICATE STRING            {
                }
                ;
 
+rootflags_l    : rootflags comma rootflags_l
+               | rootflags
+               ;
+
+rootflags      : STRING                {
+                       if (strlcpy(srv->srv_conf.root, $1,
+                           sizeof(srv->srv_conf.root)) >=
+                           sizeof(srv->srv_conf.root)) {
+                               yyerror("document root too long");
+                               free($1);
+                               YYERROR;
+                       }
+                       free($1);
+                       srv->srv_conf.flags |= SRVFLAG_ROOT;
+               }
+               | STRIP NUMBER          {
+                       if ($2 < 0 || $2 > INT_MAX) {
+                               yyerror("invalid strip number");
+                               YYERROR;
+                       }
+                       srv->srv_conf.strip = $2;
+               }
+               ;
+
 dirflags_l     : dirflags comma dirflags_l
                | dirflags
                ;
@@ -962,6 +977,7 @@ lookup(char *s)
                { "sack",               SACK },
                { "server",             SERVER },
                { "socket",             SOCKET },
+               { "strip",              STRIP },
                { "style",              STYLE },
                { "syslog",             SYSLOG },
                { "tcp",                TCP },
index 842214e..a6055cd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_fcgi.c,v 1.43 2014/12/21 00:54:49 guenther Exp $       */
+/*     $OpenBSD: server_fcgi.c,v 1.44 2015/01/04 22:23:58 chrisz Exp $ */
 
 /*
  * Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -101,8 +101,8 @@ server_fcgi(struct httpd *env, struct client *clt)
        size_t                           scriptlen;
        int                              pathlen;
        int                              fd = -1, ret;
-       const char                      *errstr = NULL;
-       char                            *str, *p, *script = NULL;
+       const char                      *stripped, *p, *alias, *errstr = NULL;
+       char                            *str, *script = NULL;
 
        if (srv_conf->socket[0] == ':') {
                struct sockaddr_storage  ss;
@@ -190,9 +190,13 @@ server_fcgi(struct httpd *env, struct client *clt)
        h->type = FCGI_PARAMS;
        h->content_len = param.total_len = 0;
 
-       if ((pathlen = asprintf(&script, "%s%s", srv_conf->root,
-           desc->http_path_alias != NULL ?
-           desc->http_path_alias : desc->http_path)) == -1) {
+       alias = desc->http_path_alias != NULL
+           ? desc->http_path_alias
+           : desc->http_path;
+
+       stripped = server_root_strip(alias, srv_conf->strip);
+       if ((pathlen = asprintf(&script, "%s%s", srv_conf->root, stripped))
+           == -1) {
                errstr = "failed to get script name";
                goto fail;
        }
@@ -213,8 +217,17 @@ server_fcgi(struct httpd *env, struct client *clt)
                script[scriptlen] = '\0';
        }
 
-       if (fcgi_add_param(&param, "SCRIPT_NAME",
-           script + strlen(srv_conf->root), clt) == -1) {
+       /*
+        * calculate length of http SCRIPT_NAME:
+        * add length of stripped prefix,
+        * subtract length of prepended local root
+        */
+       scriptlen += (stripped - alias) - strlen(srv_conf->root);
+       if ((str = strndup(alias, scriptlen)) == NULL)
+               goto fail;
+       ret = fcgi_add_param(&param, "SCRIPT_NAME", str, clt);
+       free(str);
+       if (ret == -1) {
                errstr = "failed to encode param";
                goto fail;
        }
index c2eca71..6167bdb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_file.c,v 1.43 2015/01/01 14:15:02 reyk Exp $   */
+/*     $OpenBSD: server_file.c,v 1.44 2015/01/04 22:23:58 chrisz Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -150,17 +150,19 @@ server_file(struct httpd *env, struct client *clt)
        struct http_descriptor  *desc = clt->clt_descreq;
        struct server_config    *srv_conf = clt->clt_srv_conf;
        char                     path[MAXPATHLEN];
-       const char              *errstr = NULL;
+       const char              *stripped, *errstr = NULL;
        int                      ret = 500;
 
        if (srv_conf->flags & SRVFLAG_FCGI)
                return (server_fcgi(env, clt));
 
        /* Request path is already canonicalized */
-       if ((size_t)snprintf(path, sizeof(path), "%s%s",
-           srv_conf->root,
+       stripped = server_root_strip(
            desc->http_path_alias != NULL ?
-           desc->http_path_alias : desc->http_path) >= sizeof(path)) {
+           desc->http_path_alias : desc->http_path,
+           srv_conf->strip);
+       if ((size_t)snprintf(path, sizeof(path), "%s%s",
+           srv_conf->root, stripped) >= sizeof(path)) {
                errstr = desc->http_path;
                goto abort;
        }
@@ -276,7 +278,7 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st)
        int                       code = 500;
        struct evbuffer          *evb = NULL;
        struct media_type        *media;
-       const char               *style;
+       const char               *stripped, *style;
        struct tm                 tm;
        time_t                    t, dir_mtime;
 
@@ -286,8 +288,9 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st)
        }
 
        /* Request path is already canonicalized */
+       stripped = server_root_strip(desc->http_path, srv_conf->strip);
        if ((size_t)snprintf(path, sizeof(path), "%s%s",
-           srv_conf->root, desc->http_path) >= sizeof(path))
+           srv_conf->root, stripped) >= sizeof(path))
                goto abort;
 
        /* Now open the file, should be readable or we have another problem */
index 3a5d84e..d83c7b4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_http.c,v 1.58 2015/01/01 14:15:02 reyk Exp $   */
+/*     $OpenBSD: server_http.c,v 1.59 2015/01/04 22:23:58 chrisz Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -887,6 +887,21 @@ server_response(struct httpd *httpd, struct client *clt)
        return (-1);
 }
 
+const char *
+server_root_strip(const char *path, int n)
+{
+       const char *p;
+
+       /* Strip strip leading directories. Leading '/' is ignored. */
+       for (; n > 0 && *path != '\0'; n--)
+               if ((p = strchr(++path, '/')) == NULL)
+                       path = strchr(path, '\0');
+               else
+                       path = p;
+
+       return (path);
+}
+
 struct server_config *
 server_getlocation(struct client *clt, const char *path)
 {