From: Lloyd Subject: Re: (return of) the httpd banner suppressing patch To: Rafael Sadowski Cc: "Kirill A. Korinsky" , "tech@openbsd.org" Date: Fri, 28 Nov 2025 06:11:05 +0000 > > +++ 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 STRING > > -%token NUMBER > > +%token 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 NUMBER +%token 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 STRING > > -%token NUMBER > > +%token NUMBER > > > Deleted, I will commit that separately. > > > %type port > > %type fcgiport > > %type 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, "
\n
%s
\n", > > + HTTPD_SERVERNAME) == -1) { > > + bannertoken = NULL; > > + goto done; > > + } > > + > > / Generate simple HTML error document */ > > if ((bodylen = asprintf(&body, > > "\n" > > @@ -1005,10 +1018,11 @@ server_abort_http(struct client *clt, un > > "\n" > > "\n" > > "

%03d %s

\n" > > - "
\n
%s
\n" > > + "%s" > > "\n" > > "\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 STRING > > %token NUMBER > > %type 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, "
\n
%s
\n", > > + HTTPD_SERVERNAME) == -1) { > + bannertoken = NULL; > + goto done; > + } > + > /* Generate simple HTML error document */ > if ((bodylen = asprintf(&body, > "\n" > > @@ -1005,10 +1018,11 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg) > "\n" > > "\n" > > "

%03d %s

\n" > > - "
\n
%s
\n" > > + "%s" > "\n" > > "\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,