Re: httpd(8): add support for FastCGI parameters

2019-02-19 Thread Paul Irofti
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

2019-02-18 Thread Florian Obser
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

2019-02-18 Thread Paul Irofti
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

2019-02-17 Thread Florian Obser
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

2019-02-12 Thread Paul Irofti
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