Re: httpd(8): add support for FastCGI parameters
On Mon, Feb 18, 2019 at 08:05:14PM +0100, Florian Obser wrote: > On Mon, Feb 18, 2019 at 12:17:31PM +0200, Paul Irofti wrote: > > On Sun, Feb 17, 2019 at 11:57:20AM +0100, Florian Obser wrote: > > > On Tue, Feb 12, 2019 at 05:02:47PM +0200, Paul Irofti wrote: > > > > Hi, > > > > > > > > This patch adds support for FastCGI parameters. > > > > Grammar change is very simple. > > > > > > > > fastcgi param NAME VALUE > > > > > > > > Example: > > > > %-- > > > > server "default" { > > > > listen on $ext_addr port 80 > > > > > > > > location "/cgi-bin/*" { > > > > fastcgi socket "/run/slowcgi.sock" > > > > fastcgi param TEST1 hello > > > > fastcgi param TEST2 world > > > > > > > > # The /cgi-bin directory is outside of the document root > > > > root "/" > > > > } > > > > } > > > > %-- > > > > > > > > Output: > > > > %-- > > > > CGI/1.1 test script report: > > > > > > > > GATEWAY_INTERFACE = CGI/1.1 > > > > SERVER_SOFTWARE = OpenBSD httpd > > > > SERVER_PROTOCOL = HTTP/1.1 > > > > SERVER_NAME = default > > > > SERVER_ADDR = 127.0.0.1 > > > > SERVER_PORT = 80 > > > > REQUEST_METHOD = GET > > > > HTTP_ACCEPT = > > > > text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 > > > > SCRIPT_NAME = /cgi-bin/testcgi > > > > REQUEST_URI = /cgi-bin/testcgi > > > > PATH_INFO = > > > > QUERY_STRING = > > > > REMOTE_ADDR = 127.0.0.1 > > > > REMOTE_PORT = 28054 > > > > CONTENT_TYPE = > > > > CONTENT_LENGTH = > > > > TEST1 = hello > > > > TEST2 = world > > > > PATH = > > > > %-- > > > > > > > > Initially discussed with florian@. > > > > Thoughts? Silly bike-shedding about the grammar? OKs? > > > > > > > > Manual page changes after grammar is OK'ed. > > > > > > I'm mostly OK with it, config_getserver_fcgiparams() needs a bit of > > > polishing, see inline. > > > > Like this? I did the message length check in two steps as I don't know > > how long it will be until I read how many items were sent. > > kinda, except you can't do it like this, see inline. Heh, silly me. Thanks for catching that! I also added the manual bits in my commit. If you dislike them let me know and I will change them or go ahead and modify them. Thanks again for your review! > > > > > > > Index: config.c > > === > > RCS file: /cvs/src/usr.sbin/httpd/config.c,v > > retrieving revision 1.55 > > diff -u -p -u -p -r1.55 config.c > > --- config.c20 Jun 2018 16:43:05 - 1.55 > > +++ config.c18 Feb 2019 10:15:22 - > > @@ -231,6 +231,9 @@ config_setserver(struct httpd *env, stru > > __func__, srv->srv_conf.name); > > return (-1); > > } > > + > > + /* Configure FCGI parmeters if necessary. */ > > + config_setserver_fcgiparams(env, srv); > > } > > } > > > > @@ -289,6 +292,102 @@ config_settls(struct httpd *env, struct > > tls.tls_chunk_offset += tls.tls_chunk_len; > > data += tls.tls_chunk_len; > > len -= tls.tls_chunk_len; > > + } > > + > > + return (0); > > +} > > + > > +int > > +config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) > > +{ > > + struct server *srv; > > + struct server_config*srv_conf, *iconf; > > + struct fastcgi_param*fp; > > + uint32_t id; > > + size_t c, nc, len; > > + uint8_t *p = imsg->data; > > + > > + len = sizeof(nc) + sizeof(id); > > + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { > > these are all unsigned data types, this is always false > > please write it like this: > if (IMSG_DATA_SIZE(imsg) < len) { > > > + log_debug("%s: invalid message length", __func__); > > + return (-1); > > + } > > + > > + memcpy(, p, sizeof(nc)); /* number of params */ > > + p += sizeof(nc); > > + > > + memcpy(, p, sizeof(id)); /* server conf id */ > > + srv_conf = serverconfig_byid(id); > > + p += sizeof(id); > > + > > + len += nc*sizeof(*fp); > > + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { > > and here. > With that fixed OK florian@ > > > + log_debug("%s: invalid message length", __func__); > > + return (-1); > > + } > > + > > + /* Find associated server config */ > > + TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { > > + if (srv->srv_conf.id == id) { > > + srv_conf = >srv_conf; > > + break; > > + } > > +
Re: httpd(8): add support for FastCGI parameters
On Mon, Feb 18, 2019 at 12:17:31PM +0200, Paul Irofti wrote: > On Sun, Feb 17, 2019 at 11:57:20AM +0100, Florian Obser wrote: > > On Tue, Feb 12, 2019 at 05:02:47PM +0200, Paul Irofti wrote: > > > Hi, > > > > > > This patch adds support for FastCGI parameters. > > > Grammar change is very simple. > > > > > > fastcgi param NAME VALUE > > > > > > Example: > > > %-- > > > server "default" { > > > listen on $ext_addr port 80 > > > > > > location "/cgi-bin/*" { > > > fastcgi socket "/run/slowcgi.sock" > > > fastcgi param TEST1 hello > > > fastcgi param TEST2 world > > > > > > # The /cgi-bin directory is outside of the document root > > > root "/" > > > } > > > } > > > %-- > > > > > > Output: > > > %-- > > > CGI/1.1 test script report: > > > > > > GATEWAY_INTERFACE = CGI/1.1 > > > SERVER_SOFTWARE = OpenBSD httpd > > > SERVER_PROTOCOL = HTTP/1.1 > > > SERVER_NAME = default > > > SERVER_ADDR = 127.0.0.1 > > > SERVER_PORT = 80 > > > REQUEST_METHOD = GET > > > HTTP_ACCEPT = > > > text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 > > > SCRIPT_NAME = /cgi-bin/testcgi > > > REQUEST_URI = /cgi-bin/testcgi > > > PATH_INFO = > > > QUERY_STRING = > > > REMOTE_ADDR = 127.0.0.1 > > > REMOTE_PORT = 28054 > > > CONTENT_TYPE = > > > CONTENT_LENGTH = > > > TEST1 = hello > > > TEST2 = world > > > PATH = > > > %-- > > > > > > Initially discussed with florian@. > > > Thoughts? Silly bike-shedding about the grammar? OKs? > > > > > > Manual page changes after grammar is OK'ed. > > > > I'm mostly OK with it, config_getserver_fcgiparams() needs a bit of > > polishing, see inline. > > Like this? I did the message length check in two steps as I don't know > how long it will be until I read how many items were sent. kinda, except you can't do it like this, see inline. > > > Index: config.c > === > RCS file: /cvs/src/usr.sbin/httpd/config.c,v > retrieving revision 1.55 > diff -u -p -u -p -r1.55 config.c > --- config.c 20 Jun 2018 16:43:05 - 1.55 > +++ config.c 18 Feb 2019 10:15:22 - > @@ -231,6 +231,9 @@ config_setserver(struct httpd *env, stru > __func__, srv->srv_conf.name); > return (-1); > } > + > + /* Configure FCGI parmeters if necessary. */ > + config_setserver_fcgiparams(env, srv); > } > } > > @@ -289,6 +292,102 @@ config_settls(struct httpd *env, struct > tls.tls_chunk_offset += tls.tls_chunk_len; > data += tls.tls_chunk_len; > len -= tls.tls_chunk_len; > + } > + > + return (0); > +} > + > +int > +config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) > +{ > + struct server *srv; > + struct server_config*srv_conf, *iconf; > + struct fastcgi_param*fp; > + uint32_t id; > + size_t c, nc, len; > + uint8_t *p = imsg->data; > + > + len = sizeof(nc) + sizeof(id); > + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { these are all unsigned data types, this is always false please write it like this: if (IMSG_DATA_SIZE(imsg) < len) { > + log_debug("%s: invalid message length", __func__); > + return (-1); > + } > + > + memcpy(, p, sizeof(nc)); /* number of params */ > + p += sizeof(nc); > + > + memcpy(, p, sizeof(id)); /* server conf id */ > + srv_conf = serverconfig_byid(id); > + p += sizeof(id); > + > + len += nc*sizeof(*fp); > + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { and here. With that fixed OK florian@ > + log_debug("%s: invalid message length", __func__); > + return (-1); > + } > + > + /* Find associated server config */ > + TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { > + if (srv->srv_conf.id == id) { > + srv_conf = >srv_conf; > + break; > + } > + TAILQ_FOREACH(iconf, >srv_hosts, entry) { > + if (iconf->id == id) { > + srv_conf = iconf; > + break; > + } > + } > + } > + > + /* Fetch FCGI parameters */ > + for (c = 0; c < nc; c++) { > + if ((fp = calloc(1, sizeof(*fp))) == NULL) > + fatalx("fcgiparams out of memory"); > + memcpy(fp, p, sizeof(*fp)); > +
Re: httpd(8): add support for FastCGI parameters
On Sun, Feb 17, 2019 at 11:57:20AM +0100, Florian Obser wrote: > On Tue, Feb 12, 2019 at 05:02:47PM +0200, Paul Irofti wrote: > > Hi, > > > > This patch adds support for FastCGI parameters. > > Grammar change is very simple. > > > > fastcgi param NAME VALUE > > > > Example: > > %-- > > server "default" { > > listen on $ext_addr port 80 > > > > location "/cgi-bin/*" { > > fastcgi socket "/run/slowcgi.sock" > > fastcgi param TEST1 hello > > fastcgi param TEST2 world > > > > # The /cgi-bin directory is outside of the document root > > root "/" > > } > > } > > %-- > > > > Output: > > %-- > > CGI/1.1 test script report: > > > > GATEWAY_INTERFACE = CGI/1.1 > > SERVER_SOFTWARE = OpenBSD httpd > > SERVER_PROTOCOL = HTTP/1.1 > > SERVER_NAME = default > > SERVER_ADDR = 127.0.0.1 > > SERVER_PORT = 80 > > REQUEST_METHOD = GET > > HTTP_ACCEPT = > > text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 > > SCRIPT_NAME = /cgi-bin/testcgi > > REQUEST_URI = /cgi-bin/testcgi > > PATH_INFO = > > QUERY_STRING = > > REMOTE_ADDR = 127.0.0.1 > > REMOTE_PORT = 28054 > > CONTENT_TYPE = > > CONTENT_LENGTH = > > TEST1 = hello > > TEST2 = world > > PATH = > > %-- > > > > Initially discussed with florian@. > > Thoughts? Silly bike-shedding about the grammar? OKs? > > > > Manual page changes after grammar is OK'ed. > > I'm mostly OK with it, config_getserver_fcgiparams() needs a bit of > polishing, see inline. Like this? I did the message length check in two steps as I don't know how long it will be until I read how many items were sent. Index: config.c === RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.55 diff -u -p -u -p -r1.55 config.c --- config.c20 Jun 2018 16:43:05 - 1.55 +++ config.c18 Feb 2019 10:15:22 - @@ -231,6 +231,9 @@ config_setserver(struct httpd *env, stru __func__, srv->srv_conf.name); return (-1); } + + /* Configure FCGI parmeters if necessary. */ + config_setserver_fcgiparams(env, srv); } } @@ -289,6 +292,102 @@ config_settls(struct httpd *env, struct tls.tls_chunk_offset += tls.tls_chunk_len; data += tls.tls_chunk_len; len -= tls.tls_chunk_len; + } + + return (0); +} + +int +config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) +{ + struct server *srv; + struct server_config*srv_conf, *iconf; + struct fastcgi_param*fp; + uint32_t id; + size_t c, nc, len; + uint8_t *p = imsg->data; + + len = sizeof(nc) + sizeof(id); + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { + log_debug("%s: invalid message length", __func__); + return (-1); + } + + memcpy(, p, sizeof(nc)); /* number of params */ + p += sizeof(nc); + + memcpy(, p, sizeof(id)); /* server conf id */ + srv_conf = serverconfig_byid(id); + p += sizeof(id); + + len += nc*sizeof(*fp); + if ((IMSG_DATA_SIZE(imsg) - len) < 0) { + log_debug("%s: invalid message length", __func__); + return (-1); + } + + /* Find associated server config */ + TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { + if (srv->srv_conf.id == id) { + srv_conf = >srv_conf; + break; + } + TAILQ_FOREACH(iconf, >srv_hosts, entry) { + if (iconf->id == id) { + srv_conf = iconf; + break; + } + } + } + + /* Fetch FCGI parameters */ + for (c = 0; c < nc; c++) { + if ((fp = calloc(1, sizeof(*fp))) == NULL) + fatalx("fcgiparams out of memory"); + memcpy(fp, p, sizeof(*fp)); + TAILQ_INSERT_HEAD(_conf->fcgiparams, fp, entry); + + p += sizeof(*fp); + } + + return (0); +} + +int +config_setserver_fcgiparams(struct httpd *env, struct server *srv) +{ + struct privsep *ps = env->sc_ps; + struct server_config*srv_conf = >srv_conf; + struct fastcgi_param *fp; + struct iovec *iov; + size_t c = 0, nc = 0; + +
Re: httpd(8): add support for FastCGI parameters
On Tue, Feb 12, 2019 at 05:02:47PM +0200, Paul Irofti wrote: > Hi, > > This patch adds support for FastCGI parameters. > Grammar change is very simple. > > fastcgi param NAME VALUE > > Example: > %-- > server "default" { > listen on $ext_addr port 80 > > location "/cgi-bin/*" { > fastcgi socket "/run/slowcgi.sock" > fastcgi param TEST1 hello > fastcgi param TEST2 world > > # The /cgi-bin directory is outside of the document root > root "/" > } > } > %-- > > Output: > %-- > CGI/1.1 test script report: > > GATEWAY_INTERFACE = CGI/1.1 > SERVER_SOFTWARE = OpenBSD httpd > SERVER_PROTOCOL = HTTP/1.1 > SERVER_NAME = default > SERVER_ADDR = 127.0.0.1 > SERVER_PORT = 80 > REQUEST_METHOD = GET > HTTP_ACCEPT = > text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 > SCRIPT_NAME = /cgi-bin/testcgi > REQUEST_URI = /cgi-bin/testcgi > PATH_INFO = > QUERY_STRING = > REMOTE_ADDR = 127.0.0.1 > REMOTE_PORT = 28054 > CONTENT_TYPE = > CONTENT_LENGTH = > TEST1 = hello > TEST2 = world > PATH = > %-- > > Initially discussed with florian@. > Thoughts? Silly bike-shedding about the grammar? OKs? > > Manual page changes after grammar is OK'ed. I'm mostly OK with it, config_getserver_fcgiparams() needs a bit of polishing, see inline. > > Paul > > > Index: config.c > === > RCS file: /cvs/src/usr.sbin/httpd/config.c,v > retrieving revision 1.55 > diff -u -p -u -p -r1.55 config.c > --- config.c 20 Jun 2018 16:43:05 - 1.55 > +++ config.c 12 Feb 2019 14:51:23 - > @@ -231,6 +231,9 @@ config_setserver(struct httpd *env, stru > __func__, srv->srv_conf.name); > return (-1); > } > + > + /* Configure FCGI parmeters if necessary. */ > + config_setserver_fcgiparams(env, srv); > } > } > > @@ -289,6 +292,90 @@ config_settls(struct httpd *env, struct > tls.tls_chunk_offset += tls.tls_chunk_len; > data += tls.tls_chunk_len; > len -= tls.tls_chunk_len; > + } > + > + return (0); > +} > + > +int > +config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) > +{ > + struct server *srv; > + struct server_config*srv_conf, *iconf; > + struct fastcgi_param*fp; > + uint32_t id; > + size_t c, nc; > + uint8_t *p = imsg->data; > + You are not checking how much data you got via the imsg. Please make sure that you are not reading past the imsg->data buffer. The lenght is accesible with the IMSG_DATA_SIZE() macro. > + memcpy(, p, sizeof(nc)); /* number of params */ > + p += sizeof(nc); > + > + memcpy(, p, sizeof(id)); /* server conf id */ > + srv_conf = serverconfig_byid(id); > + p += sizeof(id); > + > + /* Find associated server config */ > + TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { > + if (srv->srv_conf.id == id) { > + srv_conf = >srv_conf; > + break; > + } > + TAILQ_FOREACH(iconf, >srv_hosts, entry) { > + if (iconf->id == id) { > + srv_conf = iconf; > + break; > + } > + } > + } > + > + /* Fetch FCGI parameters */ > + for (c = 0; c < nc; c++) { > + if ((fp = calloc(1, sizeof(*fp))) == NULL) > + return (-1); I think a fatal is more apropriate. If we are so memory constraint that we can;t even hold our config there is no sense in blindly chugging along half configured. > + memcpy(fp, p, sizeof(*fp)); > + TAILQ_INSERT_HEAD(_conf->fcgiparams, fp, entry); > + > + p += sizeof(*fp); > + } > + > + return (0); > +} > + > +int > +config_setserver_fcgiparams(struct httpd *env, struct server *srv) > +{ > + struct privsep *ps = env->sc_ps; > + struct server_config*srv_conf = >srv_conf; > + struct fastcgi_param *fp; > + struct iovec *iov; > + size_t c = 0, nc = 0; > + > + DPRINTF("%s: sending fcgiparam for \"%s[%u]\" to %s fd %d", __func__, > + srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], > + srv->srv_s); > + > + if (TAILQ_EMPTY(_conf->fcgiparams)) /* nothing to do */ > + return (0); > + > + TAILQ_FOREACH(fp,
httpd(8): add support for FastCGI parameters
Hi, This patch adds support for FastCGI parameters. Grammar change is very simple. fastcgi param NAME VALUE Example: %-- server "default" { listen on $ext_addr port 80 location "/cgi-bin/*" { fastcgi socket "/run/slowcgi.sock" fastcgi param TEST1 hello fastcgi param TEST2 world # The /cgi-bin directory is outside of the document root root "/" } } %-- Output: %-- CGI/1.1 test script report: GATEWAY_INTERFACE = CGI/1.1 SERVER_SOFTWARE = OpenBSD httpd SERVER_PROTOCOL = HTTP/1.1 SERVER_NAME = default SERVER_ADDR = 127.0.0.1 SERVER_PORT = 80 REQUEST_METHOD = GET HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 SCRIPT_NAME = /cgi-bin/testcgi REQUEST_URI = /cgi-bin/testcgi PATH_INFO = QUERY_STRING = REMOTE_ADDR = 127.0.0.1 REMOTE_PORT = 28054 CONTENT_TYPE = CONTENT_LENGTH = TEST1 = hello TEST2 = world PATH = %-- Initially discussed with florian@. Thoughts? Silly bike-shedding about the grammar? OKs? Manual page changes after grammar is OK'ed. Paul Index: config.c === RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.55 diff -u -p -u -p -r1.55 config.c --- config.c20 Jun 2018 16:43:05 - 1.55 +++ config.c12 Feb 2019 14:51:23 - @@ -231,6 +231,9 @@ config_setserver(struct httpd *env, stru __func__, srv->srv_conf.name); return (-1); } + + /* Configure FCGI parmeters if necessary. */ + config_setserver_fcgiparams(env, srv); } } @@ -289,6 +292,90 @@ config_settls(struct httpd *env, struct tls.tls_chunk_offset += tls.tls_chunk_len; data += tls.tls_chunk_len; len -= tls.tls_chunk_len; + } + + return (0); +} + +int +config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) +{ + struct server *srv; + struct server_config*srv_conf, *iconf; + struct fastcgi_param*fp; + uint32_t id; + size_t c, nc; + uint8_t *p = imsg->data; + + memcpy(, p, sizeof(nc)); /* number of params */ + p += sizeof(nc); + + memcpy(, p, sizeof(id)); /* server conf id */ + srv_conf = serverconfig_byid(id); + p += sizeof(id); + + /* Find associated server config */ + TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { + if (srv->srv_conf.id == id) { + srv_conf = >srv_conf; + break; + } + TAILQ_FOREACH(iconf, >srv_hosts, entry) { + if (iconf->id == id) { + srv_conf = iconf; + break; + } + } + } + + /* Fetch FCGI parameters */ + for (c = 0; c < nc; c++) { + if ((fp = calloc(1, sizeof(*fp))) == NULL) + return (-1); + memcpy(fp, p, sizeof(*fp)); + TAILQ_INSERT_HEAD(_conf->fcgiparams, fp, entry); + + p += sizeof(*fp); + } + + return (0); +} + +int +config_setserver_fcgiparams(struct httpd *env, struct server *srv) +{ + struct privsep *ps = env->sc_ps; + struct server_config*srv_conf = >srv_conf; + struct fastcgi_param *fp; + struct iovec *iov; + size_t c = 0, nc = 0; + + DPRINTF("%s: sending fcgiparam for \"%s[%u]\" to %s fd %d", __func__, + srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], + srv->srv_s); + + if (TAILQ_EMPTY(_conf->fcgiparams)) /* nothing to do */ + return (0); + + TAILQ_FOREACH(fp, _conf->fcgiparams, entry) { + nc++; + } + if ((iov = calloc(nc + 2, sizeof(*iov))) == NULL) + return (-1); + + iov[c].iov_base = /* number of params */ + iov[c++].iov_len = sizeof(nc); + iov[c].iov_base = _conf->id;/* server config id */ + iov[c++].iov_len = sizeof(srv_conf->id); + + TAILQ_FOREACH(fp, _conf->fcgiparams, entry) { /* push FCGI params */ + iov[c].iov_base = fp; + iov[c++].iov_len = sizeof(*fp); + } + if (proc_composev(ps, PROC_SERVER, IMSG_CFG_FCGI, iov, c) != 0) { + log_warn("%s: failed to compose IMSG_CFG_FCGI