Download raw body.
(return of) the httpd banner suppressing patch
> > +++ server_fcgi.c 13 May 2025 20:44:43 -0000
> > @@ -345,6 +345,7 @@ server_fcgi(struct httpd *env, struct cl
> > goto fail;
> > }
> >
> > + /* RFC 3875 requires this variable always be present */
>
>
> Deleted. I don't find that helpful; otherwise, you would have to
> write that for all variables.
I disagree, this comment should remain as it was added for good reason.
It's explicity to prevent someone from helpfully fixing this "bug" down
the road and adding a "if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)"
presumed to be missing, when in fact it should not be there by design.
You don't need it for all variables since the others don't have knobs.
I noticed another similar comment in that file for context purposes:
/* RFC 3875 mandates that PATH_INFO is empty if not set */
> > +++ parse.y 13 May 2025 20:44:43 -0000
> > @@ -141,9 +141,9 @@ typedef struct {
> > %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
> > %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
> > %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
> > -%token ERRDOCS GZIPSTATIC
> > +%token ERRDOCS GZIPSTATIC BANNER
> > %token <v.string> STRING
> > -%token <v.number> NUMBER
> > +%token <v.number> NUMBER
>
>
> Deleted, I will commit that separately.
It looks like the whitespace error somehow got filtered out? IIRC it
was concealed & didn't show up in all editors. There is a one-character
diff which should look like this, unless that was committed with the
gzip diff?
-%token <v.number> NUMBER
+%token <v.number> NUMBER
Regards
Lloyd
Rafael Sadowski wrote:
> On Tue May 13, 2025 at 08:59:37PM +0000, Lloyd wrote:
>
> > Henry Ford wrote:
> >
> > > I have a few comments on this
> > >
> > > This directive should be listed along with the other directives that
> > > are not allowed in location blocks in the httpd.conf(5) manpage.
> >
> > Good catch, thanks for giving this a deeper look.
> >
> > > Since HTTPD_SERVERNAME is a constant I don't think you really need
> > > to use asprintf(3) here (could just use string literal concatenation).
> > >
> > > If if makes sense to use asprintf(3) here then you should check
> > > if it fails, and at some point free bannertoken.
> >
> > Looking back, when I first developed the patch the servername was a
> > user configurable string. I later ripped that out and reverted to a
> > simple on/off condition of the banner. That said, the use of asprintf
> > is consistent with all the adjacent code and is a little bit cleaner
> > visually, but you're correct there was a missing free() in there.
> >
> > As for checking for failure on asprintf, OpenBSD should set the value
> > of the pointer to NULL on error anyway which is checked later; however,
> > other OSes don't make that guarantee. E.g. Linux claims the value of
> > the pointer becomes undefined. So I would agree the additional check
> > and redundant setting the pointer to NULL does become prudent.
> >
> > Thanks for the feedback, a revised patch can be found below.
> >
> > Regards
> > Lloyd
>
>
> Hi Lloyd, Hi Kirill,
>
> some comments in-line. At the very bottom, a diff revised with the
> in-line changes and after GZIPSTATIC commit from today.
>
> Kirill are you sill OK with this diff? For you too Lloyd?
>
> Thanks,
>
> Rafael
>
> > Index: config.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/config.c,v
> > retrieving revision 1.65
> > diff -u -p -u -p -r1.65 config.c
> > --- config.c 17 Jan 2024 08:22:40 -0000 1.65
> > +++ config.c 13 May 2025 20:44:43 -0000
> > @@ -591,6 +591,8 @@ config_getserver_config(struct httpd *en
> > srv_conf->flags |= parent->flags & SRVFLAG_ERRDOCS;
> > (void)strlcpy(srv_conf->errdocroot, parent->errdocroot,
> > sizeof(srv_conf->errdocroot));
> > +
>
>
> Deleted extra whitespaces.
>
> > + srv_conf->flags |= parent->flags & SRVFLAG_NO_BANNER;
> >
> > DPRINTF("%s: %s %d location \"%s\", "
> > "parent \"%s[%u]\", flags: %s",
> > Index: httpd.conf.5
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v
> > retrieving revision 1.125
> > diff -u -p -u -p -r1.125 httpd.conf.5
> > --- httpd.conf.5 3 Nov 2023 13:03:02 -0000 1.125
> > +++ httpd.conf.5 13 May 2025 20:44:43 -0000
> > @@ -166,6 +166,14 @@ If not specified, it defaults to
> > within the
> > .Xr chroot 2
> > directory.
> > +.It Ic no banner
> > +Do not send the
> > +.Va Server
> > +HTTP response header, and hide the server software name in error documents.
> > +The
> > +.Va SERVER_SOFTWARE
> > +CGI environment variable is always set in accordance with
> > +.%R RFC 3875 .
> > .It Ic prefork Ar number
> > Run the specified number of server processes.
> > This increases the performance and prevents delays when connecting
> > @@ -227,6 +235,20 @@ and must be readable by the www user.
> > Use the
> > .Ic no authenticate
> > directive to disable authentication in a location.
> > +.It Oo Ic no Oc Ic banner
> > +When prefixed with the
> > +.Ic no
> > +keyword,
> > +suppress the
> > +.Va Server
> > +HTTP response header, and hide the server software name in error documents for
> > +the current
> > +.Ic server.
> > +If
> > +.Ic no
> > +is omitted, enable the banner for the current
> > +.Ic server
> > +if it was disabled globally.
> > .It Ic block drop
> > Drop the connection without sending an error page.
> > .It Ic block Op Ic return Ar code Op Ar uri
> > @@ -473,6 +495,7 @@ and for generic ones later on.
> > A location section may include most of the server configuration rules
> > except
> > .Ic alias ,
> > +.Ic banner ,
> > .Ic connection ,
> > .Ic errdocs ,
> > .Ic hsts ,
> > Index: httpd.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
> > retrieving revision 1.165
> > diff -u -p -u -p -r1.165 httpd.h
> > --- httpd.h 8 Oct 2024 05:28:11 -0000 1.165
> > +++ httpd.h 13 May 2025 20:44:43 -0000
> > @@ -389,6 +389,7 @@ SPLAY_HEAD(client_tree, client);
> > #define SRVFLAG_PATH_REWRITE 0x01000000
> > #define SRVFLAG_NO_PATH_REWRITE 0x02000000
> > #define SRVFLAG_GZIP_STATIC 0x04000000
> > +#define SRVFLAG_NO_BANNER 0x08000000
> > #define SRVFLAG_LOCATION_FOUND 0x40000000
> > #define SRVFLAG_LOCATION_NOT_FOUND 0x80000000
> >
> > @@ -398,7 +399,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"
> > + "\33GZIP_STATIC\34NO_BANNER\37LOCATION_FOUND\40LOCATION_NOT_FOUND"
> >
> > #define TCPFLAG_NODELAY 0x01
> > #define TCPFLAG_NNODELAY 0x02
> > Index: parse.y
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
> > retrieving revision 1.128
> > diff -u -p -u -p -r1.128 parse.y
> > --- parse.y 27 Feb 2022 20:30:30 -0000 1.128
> > +++ parse.y 13 May 2025 20:44:43 -0000
> > @@ -141,9 +141,9 @@ typedef struct {
> > %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
> > %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
> > %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
> > -%token ERRDOCS GZIPSTATIC
> > +%token ERRDOCS GZIPSTATIC BANNER
> > %token <v.string> STRING
> > -%token <v.number> NUMBER
> > +%token <v.number> NUMBER
>
>
> Deleted, I will commit that separately.
>
> > %type <v.port> port
> > %type <v.string> fcgiport
> > %type <v.number> opttls optmatch optfound
> > @@ -227,6 +227,9 @@ main : PREFORK NUMBER {
> > | LOGDIR STRING {
> > conf->sc_logdir = $2;
> > }
> > + | NO BANNER {
> > + conf->sc_flags |= SRVFLAG_NO_BANNER;
> > + }
> > | DEFAULT TYPE mediastring {
> > memcpy(&conf->sc_default_type, &media,
> > sizeof(struct media_type));
> > @@ -300,6 +303,9 @@ server : SERVER optmatch STRING {
> >
> > s->srv_conf.hsts_max_age = SERVER_HSTS_DEFAULT_AGE;
> >
> > + if (conf->sc_flags & SRVFLAG_NO_BANNER)
> > + s->srv_conf.flags |= SRVFLAG_NO_BANNER;
> > +
> > (void)strlcpy(s->srv_conf.errdocroot,
> > conf->sc_errdocroot,
> > sizeof(s->srv_conf.errdocroot));
> > @@ -550,6 +556,7 @@ serveroptsl : LISTEN ON STRING opttls po
> > | request
> > | root
> > | directory
> > + | banner
> > | logformat
> > | fastcgi
> > | authenticate
> > @@ -687,6 +694,22 @@ serveroptsl : LISTEN ON STRING opttls po
> > }
> > ;
> >
> > +banner : BANNER {
> > + if (parentsrv != NULL) {
> > + yyerror("banner inside location");
> > + YYERROR;
> > + }
> > + srv->srv_conf.flags &= ~SRVFLAG_NO_BANNER;
> > + }
> > + | NO BANNER {
> > + if (parentsrv != NULL) {
> > + yyerror("no banner inside location");
> > + YYERROR;
> > + }
> > + srv->srv_conf.flags |= SRVFLAG_NO_BANNER;
> > + }
> > + ;
> > +
> > optfound : /* empty */ { $$ = 0; }
> > | FOUND { $$ = 1; }
> > | NOT FOUND { $$ = -1; }
> > @@ -1428,6 +1451,7 @@ lookup(char *s)
> > { "authenticate", AUTHENTICATE},
> > { "auto", AUTO },
> > { "backlog", BACKLOG },
> > + { "banner", BANNER },
> > { "block", BLOCK },
> > { "body", BODY },
> > { "buffer", BUFFER },
> > Index: server_fcgi.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/server_fcgi.c,v
> > retrieving revision 1.97
> > diff -u -p -u -p -r1.97 server_fcgi.c
> > --- server_fcgi.c 8 Nov 2023 19:19:10 -0000 1.97
> > +++ server_fcgi.c 13 May 2025 20:44:43 -0000
> > @@ -345,6 +345,7 @@ server_fcgi(struct httpd *env, struct cl
> > goto fail;
> > }
> >
> > + /* RFC 3875 requires this variable always be present */
>
>
> Deleted. I don't find that helpful; otherwise, you would have to
> write that for all variables.
>
> > if (fcgi_add_param(¶m, "SERVER_SOFTWARE", HTTPD_SERVERNAME,
> > clt) == -1) {
> > errstr = "failed to encode param";
> > @@ -659,9 +660,12 @@ server_fcgi_header(struct client *clt, u
> > kv_set(&resp->http_pathquery, "%s", error) == -1)
> > return (-1);
> >
> > - /* Add headers /
> > - if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
> > - return (-1);
> > + / Add server banner header to response unless suppressed */
> > + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0) {
> > + if (kv_add(&resp->http_headers, "Server",
> > + HTTPD_SERVERNAME) == NULL)
> > + return (-1);
> > + }
>
>
> Deleted extra whitespaces.
>
> > if (clt->clt_fcgi.type == FCGI_END_REQUEST ||
> > EVBUFFER_LENGTH(clt->clt_srvevb) == 0) {
> > Index: server_http.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
> > retrieving revision 1.155
> > diff -u -p -u -p -r1.155 server_http.c
> > --- server_http.c 22 Dec 2024 13:51:42 -0000 1.155
> > +++ server_http.c 13 May 2025 20:44:43 -0000
> > @@ -890,6 +890,7 @@ server_abort_http(struct client *clt, un
> > char *httpmsg, *body = NULL, *extraheader = NULL;
> > char tmbuf[32], hbuf[128], *hstsheader = NULL;
> > char *clenheader = NULL;
> > + char *bannerheader = NULL, *bannertoken = NULL;
> > char buf[IBUF_READ_SIZE];
> > char *escapedmsg = NULL;
> > char cstr[5];
> > @@ -981,7 +982,11 @@ server_abort_http(struct client *clt, un
> >
> > body = replace_var(body, "$HTTP_ERROR", httperr);
> > body = replace_var(body, "$RESPONSE_CODE", cstr);
> > - body = replace_var(body, "$SERVER_SOFTWARE", HTTPD_SERVERNAME);
> > + /* Check if server banner is suppressed */
> > + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
> > + body = replace_var(body, "$SERVER_SOFTWARE", HTTPD_SERVERNAME);
> > + else
> > + body = replace_var(body, "$SERVER_SOFTWARE", "");
> > bodylen = strlen(body);
> > goto send;
> >
> > @@ -994,6 +999,14 @@ server_abort_http(struct client *clt, un
> > "body { background-color: #1E1F21; color: #EEEFF1; }\n"
> > "a { color: #BAD7FF; }\n}";
> >
> > + /* If banner is suppressed, don't write it to the error document /
> > + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
> > + if (asprintf(&bannertoken, "<hr>\n<address>%s</address>\n",
> > + HTTPD_SERVERNAME) == -1) {
> > + bannertoken = NULL;
> > + goto done;
> > + }
> > +
> > / Generate simple HTML error document */
> > if ((bodylen = asprintf(&body,
> > "<!DOCTYPE html>\n"
> > @@ -1005,10 +1018,11 @@ server_abort_http(struct client *clt, un
> > "</head>\n"
> > "<body>\n"
> > "<h1>%03d %s</h1>\n"
> > - "<hr>\n<address>%s</address>\n"
> > + "%s"
> > "</body>\n"
> > "</html>\n",
> > - code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) {
> > + code, httperr, style, code, httperr,
> > + bannertoken == NULL ? "" : bannertoken)) == -1) {
> > body = NULL;
> > goto done;
> > }
> > @@ -1037,11 +1051,19 @@ server_abort_http(struct client *clt, un
> > }
> > }
> >
> > + /* If banner is suppressed, don't write a Server header /
> > + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
> > + if (asprintf(&bannerheader, "Server: %s\r\n",
> > + HTTPD_SERVERNAME) == -1) {
> > + bannerheader = NULL;
> > + goto done;
> > + }
> > +
> > / Add basic HTTP headers */
> > if (asprintf(&httpmsg,
> > "HTTP/1.0 %03d %s\r\n"
> > "Date: %s\r\n"
> > - "Server: %s\r\n"
> > + "%s"
> > "Connection: close\r\n"
> > "Content-Type: text/html\r\n"
> > "%s"
> > @@ -1049,7 +1071,8 @@ server_abort_http(struct client *clt, un
> > "%s"
> > "\r\n"
> > "%s",
> > - code, httperr, tmbuf, HTTPD_SERVERNAME,
> > + code, httperr, tmbuf,
> > + bannerheader == NULL ? "" : bannerheader,
> > clenheader == NULL ? "" : clenheader,
> > extraheader == NULL ? "" : extraheader,
> > hstsheader == NULL ? "" : hstsheader,
> > @@ -1066,6 +1089,8 @@ server_abort_http(struct client *clt, un
> > free(extraheader);
> > free(hstsheader);
> > free(clenheader);
> > + free(bannerheader);
> > + free(bannertoken);
> > if (msg == NULL)
> > msg = "\"\"";
> > if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) {
> > @@ -1558,10 +1583,12 @@ server_response_http(struct client *clt,
> > kv_set(&resp->http_pathquery, "%s", error) == -1)
> > return (-1);
> >
> > - /* Add headers /
> > - if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
> > - return (-1);
> > -
> > + / Add server banner header to response unless suppressed /
> > + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0) {
> > + if (kv_add(&resp->http_headers, "Server",
> > + HTTPD_SERVERNAME) == NULL)
> > + return (-1);
> > + }
> > / Is it a persistent connection? */
> > if (clt->clt_persist) {
> > if (kv_add(&resp->http_headers,
>
>
>
>
> diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c
> index cdb04f1eb0e..f2dc4bb63f2 100644
> --- a/usr.sbin/httpd/config.c
> +++ b/usr.sbin/httpd/config.c
> @@ -638,6 +638,8 @@ config_getserver_config(struct httpd *env, struct server *srv,
> (void)strlcpy(srv_conf->errdocroot, parent->errdocroot,
>
> sizeof(srv_conf->errdocroot));
>
>
> + srv_conf->flags |= parent->flags & SRVFLAG_NO_BANNER;
>
> +
> DPRINTF("%s: %s %d location \"%s\", "
> "parent \"%s[%u]\", flags: %s",
> func, ps->ps_title[privsep_process], ps->ps_instance,
>
> diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5
> index 79411a7e941..fa6c76b26f8 100644
> --- a/usr.sbin/httpd/httpd.conf.5
> +++ b/usr.sbin/httpd/httpd.conf.5
> @@ -171,6 +171,14 @@ If not specified, it defaults to
> within the
> .Xr chroot 2
> directory.
> +.It Ic no banner
> +Do not send the
> +.Va Server
> +HTTP response header, and hide the server software name in error documents.
> +The
> +.Va SERVER_SOFTWARE
> +CGI environment variable is always set in accordance with
> +.%R RFC 3875 .
> .It Ic prefork Ar number
> Run the specified number of server processes.
> This increases the performance and prevents delays when connecting
> @@ -232,6 +240,20 @@ and must be readable by the www user.
> Use the
> .Ic no authenticate
> directive to disable authentication in a location.
> +.It Oo Ic no Oc Ic banner
> +When prefixed with the
> +.Ic no
> +keyword,
> +suppress the
> +.Va Server
> +HTTP response header, and hide the server software name in error documents for
> +the current
> +.Ic server.
> +If
> +.Ic no
> +is omitted, enable the banner for the current
> +.Ic server
> +if it was disabled globally.
> .It Ic block drop
> Drop the connection without sending an error page.
> .It Ic block Op Ic return Ar code Op Ar uri
> @@ -478,6 +500,7 @@ and for generic ones later on.
> A location section may include most of the server configuration rules
> except
> .Ic alias ,
> +.Ic banner ,
> .Ic connection ,
> .Ic errdocs ,
> .Ic hsts ,
> diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
> index 40bcaf6cf35..f3eec1d28ea 100644
> --- a/usr.sbin/httpd/httpd.h
> +++ b/usr.sbin/httpd/httpd.h
> @@ -389,6 +389,7 @@ SPLAY_HEAD(client_tree, client);
> #define SRVFLAG_PATH_REWRITE 0x01000000
> #define SRVFLAG_NO_PATH_REWRITE 0x02000000
> #define SRVFLAG_GZIP_STATIC 0x04000000
> +#define SRVFLAG_NO_BANNER 0x08000000
> #define SRVFLAG_LOCATION_FOUND 0x40000000
> #define SRVFLAG_LOCATION_NOT_FOUND 0x80000000
>
> @@ -398,7 +399,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_REWRITE" \
> - "\32NO_PATH_REWRITE\33GZIP_STATIC\37LOCATION_FOUND" \
> + "\32NO_PATH_REWRITE\34NO_BANNER\33GZIP_STATIC\37LOCATION_FOUND" \
> "\40LOCATION_NOT_FOUND"
>
> #define TCPFLAG_NODELAY 0x01
> diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y
> index d565e61d727..a422cde7823 100644
> --- a/usr.sbin/httpd/parse.y
> +++ b/usr.sbin/httpd/parse.y
> @@ -141,7 +141,7 @@ typedef struct {
> %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
> %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
> %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
> -%token ERRDOCS GZIPSTATIC
> +%token ERRDOCS GZIPSTATIC BANNER
> %token <v.string> STRING
>
> %token <v.number> NUMBER
>
> %type <v.port> port
>
> @@ -227,6 +227,9 @@ main : PREFORK NUMBER {
> | LOGDIR STRING {
> conf->sc_logdir = $2;
>
> }
> + | NO BANNER {
> + conf->sc_flags |= SRVFLAG_NO_BANNER;
>
> + }
> | DEFAULT TYPE mediastring {
> memcpy(&conf->sc_default_type, &media,
>
> sizeof(struct media_type));
> @@ -300,6 +303,9 @@ server : SERVER optmatch STRING {
>
> s->srv_conf.hsts_max_age = SERVER_HSTS_DEFAULT_AGE;
>
>
> + if (conf->sc_flags & SRVFLAG_NO_BANNER)
>
> + s->srv_conf.flags |= SRVFLAG_NO_BANNER;
>
> +
> (void)strlcpy(s->srv_conf.errdocroot,
>
> conf->sc_errdocroot,
>
> sizeof(s->srv_conf.errdocroot));
>
> @@ -550,6 +556,7 @@ serveroptsl : LISTEN ON STRING opttls port {
> | request
> | root
> | directory
> + | banner
> | logformat
> | fastcgi
> | authenticate
> @@ -687,6 +694,22 @@ serveroptsl : LISTEN ON STRING opttls port {
> }
> ;
>
> +banner : BANNER {
> + if (parentsrv != NULL) {
> + yyerror("banner inside location");
> + YYERROR;
> + }
> + srv->srv_conf.flags &= ~SRVFLAG_NO_BANNER;
>
> + }
> + | NO BANNER {
> + if (parentsrv != NULL) {
> + yyerror("no banner inside location");
> + YYERROR;
> + }
> + srv->srv_conf.flags |= SRVFLAG_NO_BANNER;
>
> + }
> + ;
> +
> optfound : /* empty */ { $$ = 0; }
> | FOUND { $$ = 1; }
> | NOT FOUND { $$ = -1; }
> @@ -1428,6 +1451,7 @@ lookup(char *s)
> { "authenticate", AUTHENTICATE},
> { "auto", AUTO },
> { "backlog", BACKLOG },
> + { "banner", BANNER },
> { "block", BLOCK },
> { "body", BODY },
> { "buffer", BUFFER },
> diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c
> index 70bd78c0820..7c436654e0d 100644
> --- a/usr.sbin/httpd/server_fcgi.c
> +++ b/usr.sbin/httpd/server_fcgi.c
> @@ -659,9 +659,12 @@ server_fcgi_header(struct client *clt, unsigned int code)
> kv_set(&resp->http_pathquery, "%s", error) == -1)
>
> return (-1);
>
> - /* Add headers */
> - if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
>
> - return (-1);
> + /* Add server banner header to response unless suppressed */
> + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0) {
>
> + if (kv_add(&resp->http_headers, "Server",
>
> + HTTPD_SERVERNAME) == NULL)
> + return (-1);
> + }
>
> if (clt->clt_fcgi.type == FCGI_END_REQUEST ||
>
> EVBUFFER_LENGTH(clt->clt_srvevb) == 0) {
>
> diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c
> index aef4e4567fc..6d7d2e3251a 100644
> --- a/usr.sbin/httpd/server_http.c
> +++ b/usr.sbin/httpd/server_http.c
> @@ -890,6 +890,7 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
> char *httpmsg, *body = NULL, *extraheader = NULL;
> char tmbuf[32], hbuf[128], *hstsheader = NULL;
> char *clenheader = NULL;
> + char *bannerheader = NULL, *bannertoken = NULL;
> char buf[IBUF_READ_SIZE];
> char *escapedmsg = NULL;
> char cstr[5];
> @@ -981,7 +982,11 @@ server_abort_http(struct client *clt, unsigned int code, const char msg)
>
> body = replace_var(body, "$HTTP_ERROR", httperr);
> body = replace_var(body, "$RESPONSE_CODE", cstr);
> - body = replace_var(body, "$SERVER_SOFTWARE", HTTPD_SERVERNAME);
> + / Check if server banner is suppressed */
> + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
>
> + body = replace_var(body, "$SERVER_SOFTWARE", HTTPD_SERVERNAME);
> + else
> + body = replace_var(body, "$SERVER_SOFTWARE", "");
> bodylen = strlen(body);
> goto send;
>
> @@ -994,6 +999,14 @@ server_abort_http(struct client *clt, unsigned int code, const char msg)
> "body { background-color: #1E1F21; color: #EEEFF1; }\n"
> "a { color: #BAD7FF; }\n}";
>
> + / If banner is suppressed, don't write it to the error document */
> + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
>
> + if (asprintf(&bannertoken, "<hr>\n<address>%s</address>\n",
>
> + HTTPD_SERVERNAME) == -1) {
> + bannertoken = NULL;
> + goto done;
> + }
> +
> /* Generate simple HTML error document */
> if ((bodylen = asprintf(&body,
> "<!DOCTYPE html>\n"
>
> @@ -1005,10 +1018,11 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
> "</head>\n"
>
> "<body>\n"
>
> "<h1>%03d %s</h1>\n"
>
> - "<hr>\n<address>%s</address>\n"
>
> + "%s"
> "</body>\n"
>
> "</html>\n",
>
> - code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) {
> + code, httperr, style, code, httperr,
> + bannertoken == NULL ? "" : bannertoken)) == -1) {
> body = NULL;
> goto done;
> }
> @@ -1037,11 +1051,19 @@ server_abort_http(struct client *clt, unsigned int code, const char msg)
> }
> }
>
> + / If banner is suppressed, don't write a Server header */
> + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0)
>
> + if (asprintf(&bannerheader, "Server: %s\r\n",
> + HTTPD_SERVERNAME) == -1) {
> + bannerheader = NULL;
> + goto done;
> + }
> +
> /* Add basic HTTP headers */
> if (asprintf(&httpmsg,
> "HTTP/1.0 %03d %s\r\n"
> "Date: %s\r\n"
> - "Server: %s\r\n"
> + "%s"
> "Connection: close\r\n"
> "Content-Type: text/html\r\n"
> "%s"
> @@ -1049,7 +1071,8 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
> "%s"
> "\r\n"
> "%s",
> - code, httperr, tmbuf, HTTPD_SERVERNAME,
> + code, httperr, tmbuf,
> + bannerheader == NULL ? "" : bannerheader,
> clenheader == NULL ? "" : clenheader,
> extraheader == NULL ? "" : extraheader,
> hstsheader == NULL ? "" : hstsheader,
> @@ -1066,6 +1089,8 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
> free(extraheader);
> free(hstsheader);
> free(clenheader);
> + free(bannerheader);
> + free(bannertoken);
> if (msg == NULL)
> msg = "\"\"";
> if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) {
> @@ -1558,10 +1583,12 @@ server_response_http(struct client *clt, unsigned int code,
> kv_set(&resp->http_pathquery, "%s", error) == -1)
>
> return (-1);
>
> - /* Add headers */
> - if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
>
> - return (-1);
> -
> + /* Add server banner header to response unless suppressed */
> + if ((srv_conf->flags & SRVFLAG_NO_BANNER) == 0) {
>
> + if (kv_add(&resp->http_headers, "Server",
>
> + HTTPD_SERVERNAME) == NULL)
> + return (-1);
> + }
> /* Is it a persistent connection? */
> if (clt->clt_persist) {
>
> if (kv_add(&resp->http_headers,
(return of) the httpd banner suppressing patch