Claudio Jeker writes:

> Another thing to consider is that X-Forwarded headers should only be
> accepted from trusted sources. I don't think this particular usage of
> X-Forwarded-Proto is probelmatic. In the end for this particular case of
> redirect using a relative URL seems to be a better choice since it will
> preserve the host, port and proto from the original requests without any
> configuration magic.

Here's a quick effort to test out the idea. Not sure I like it yet...but
figured this could help move discussion forward. (Not looking for an OK
yet as I doubt this config style is good yet.)

Couple points:
  * the srvflag bitmap is sort of at the semantic breaking point as a
    uint32_t...hesitant to bump it to uint64_t just to allow better flag
    groupings but that's a thought

  * not sure i like my config style...maybe (yet another) optional token
    or two in the "auto index" pattern instead?

Quick example config folks can test with. First `# cp -R /var/www /tmp`
and then stage some files there for your enjoyment.

chroot "/tmp/www"
server "default" {
        listen on * port 80
        directory {
                auto index
                relative redirects
        }
}

Example without "relative redirects":

~ $ curl -i localhost/bgplg
HTTP/1.0 301 Moved Permanently
Server: OpenBSD httpd
Connection: close
Content-Type: text/html
Content-Length: 510
Location: http://localhost/bgplg/

With "relative redirects":

~ $ curl -i localhost/bgplg
HTTP/1.0 301 Moved Permanently
Server: OpenBSD httpd
Connection: close
Content-Type: text/html
Content-Length: 510
Location: /bgplg/

-dv


Index: usr.sbin/httpd/httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.156
diff -u -p -r1.156 httpd.h
--- usr.sbin/httpd/httpd.h      20 Apr 2021 21:11:56 -0000      1.156
+++ usr.sbin/httpd/httpd.h      28 Apr 2021 12:10:18 -0000
@@ -392,6 +392,7 @@ SPLAY_HEAD(client_tree, client);
 #define SRVFLAG_DEFAULT_TYPE   0x00800000
 #define SRVFLAG_PATH_REWRITE   0x01000000
 #define SRVFLAG_NO_PATH_REWRITE        0x02000000
+#define SRVFLAG_RELATIVE_REDIR 0x04000000
 #define SRVFLAG_LOCATION_FOUND 0x40000000
 #define SRVFLAG_LOCATION_NOT_FOUND 0x80000000

@@ -401,7 +402,7 @@ SPLAY_HEAD(client_tree, client);
        "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG"          \
        "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH"         \
        "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH" \
-       "\37LOCATION_FOUND\40LOCATION_NOT_FOUND"
+       "\33RELATIVE_REDIR\37LOCATION_FOUND\40LOCATION_NOT_FOUND"

 #define TCPFLAG_NODELAY                0x01
 #define TCPFLAG_NNODELAY       0x02
Index: usr.sbin/httpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
retrieving revision 1.125
diff -u -p -r1.125 parse.y
--- usr.sbin/httpd/parse.y      10 Apr 2021 10:10:07 -0000      1.125
+++ usr.sbin/httpd/parse.y      28 Apr 2021 12:10:18 -0000
@@ -137,9 +137,10 @@ typedef struct {
 %token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
 %token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LIFETIME
 %token LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK
-%token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET
-%token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
-%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
+%token PROTOCOLS REDIRECTS RELATIVE REQUESTS ROOT SACK SERVER SOCKET STRIP
+%token STYLE SYSLOG TCP TICKET TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS
+%token DEFAULT PRELOAD REQUEST ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP
+%token RETURN PASS REWRITE
 %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
@@ -1038,7 +1039,11 @@ dirflags : INDEX STRING          {
                        srv_conf->flags &= ~SRVFLAG_AUTO_INDEX;
                        srv_conf->flags |= SRVFLAG_NO_AUTO_INDEX;
                }
-               ;
+               | RELATIVE REDIRECTS    {
+                       srv_conf->flags &= ~SRVFLAG_RELATIVE_REDIR;
+                       srv_conf->flags |= SRVFLAG_RELATIVE_REDIR;
+               }
+       ;


 logformat      : LOG logflags
@@ -1425,6 +1430,8 @@ lookup(char *s)
                { "prefork",            PREFORK },
                { "preload",            PRELOAD },
                { "protocols",          PROTOCOLS },
+               { "redirects",          REDIRECTS },
+               { "relative",           RELATIVE },
                { "request",            REQUEST },
                { "requests",           REQUESTS },
                { "return",             RETURN },
Index: usr.sbin/httpd/server_file.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v
retrieving revision 1.69
diff -u -p -r1.69 server_file.c
--- usr.sbin/httpd/server_file.c        16 Mar 2021 06:44:14 -0000      1.69
+++ usr.sbin/httpd/server_file.c        28 Apr 2021 12:10:18 -0000
@@ -85,13 +85,17 @@ server_file_access(struct httpd *env, st
                if (path[strlen(path) - 1] != '/') {
                        if ((encodedpath = url_encode(desc->http_path)) == NULL)
                                return (500);
-                       if (asprintf(&newpath, "http%s://%s%s/",
-                           srv_conf->flags & SRVFLAG_TLS ? "s" : "",
-                           desc->http_host, encodedpath) == -1) {
-                               free(encodedpath);
-                               return (500);
-                       }
+
+                       if (srv_conf->flags & SRVFLAG_RELATIVE_REDIR)
+                               ret = asprintf(&newpath, "%s/", encodedpath);
+                       else
+                               ret = asprintf(&newpath, "http%s://%s%s/",
+                                   srv_conf->flags & SRVFLAG_TLS ? "s" : "",
+                                   desc->http_host, encodedpath);
+
                        free(encodedpath);
+                       if (ret < 0)
+                               return (500);

                        /* Path alias will be used for the redirection */
                        desc->http_path_alias = newpath;

Reply via email to