On Wed, Nov 6, 2013 at 1:20 PM, Steve Hay <steve.m....@googlemail.com>wrote:

> On 6 November 2013 14:27, Jeff Trawick <traw...@gmail.com> wrote:
> > On Wed, Nov 6, 2013 at 8:50 AM, Steve Hay <steve.m....@googlemail.com>
> > wrote:
> >>
> >> On 6 November 2013 13:50, Steve Hay <steve.m....@googlemail.com> wrote:
> >> > On 6 November 2013 12:27, Jeff Trawick <traw...@gmail.com> wrote:
> >> >> On Wed, Nov 6, 2013 at 4:02 AM, Steve Hay <
> steve.m....@googlemail.com>
> >> >> wrote:
> >> >>>
> >> >>> On 6 November 2013 00:48, Jeff Trawick <traw...@gmail.com> wrote:
> >> >>> > Back to the httpd24threading branch:
> >> >>> >
> >> >>> > * modperl_interp_pool_select() has this notion of phase, which
> must
> >> >>> > either
> >> >>> > be startup or request context.
> >> >>> > * It thinks it is startup only if the pool passed in is
> >> >>> > s->process->pconf.
> >> >>> > * Sometimes it is passed s->process->pool (parent of pconf), such
> as
> >> >>> > from
> >> >>> > perl_parse_require_line().
> >> >>> > * perl_parse_require_line() can sometimes be called from request
> >> >>> > context.
> >> >>> > * When perl_parse_require_line() calls
> modperl_interp_pool_select(),
> >> >>> > request
> >> >>> > context can never be identified because perl_parse_require_line()
> >> >>> > never
> >> >>> > passes in r->pool (which I guess would be cmd->pool).
> >> >>> > * etc.
> >> >>> >
> >> >>> > This would seem to be the way to get the right pool to
> >> >>> > modperl_interp_pool_select().
> >> >>> >
> >> >>> > Index: src/modules/perl/modperl_util.c
> >> >>> >
> ===================================================================
> >> >>> > --- src/modules/perl/modperl_util.c     (revision 1539040)
> >> >>> > +++ src/modules/perl/modperl_util.c     (working copy)
> >> >>> > @@ -989,7 +989,7 @@
> >> >>> >      int count;
> >> >>> >      void *key;
> >> >>> >      auth_callback *ab;
> >> >>> > -    MP_dINTERP_POOLa(cmd->server->process->pool, cmd->server);
> >> >>> > +    MP_dINTERP_POOLa(cmd->pool, cmd->server);
> >> >>> >
> >> >>> >      if (global_authz_providers == NULL) {
> >> >>> >          MP_INTERP_PUTBACK(interp, aTHX);
> >> >>> >
> >> >>> > That still doesn't bring happiness (no interpreter returned,
> >> >>> > resulting
> >> >>> > in a
> >> >>> > crash trying to dereference interp).
> >> >>> >
> >> >>>
> >> >>> I'm getting the same crash-on-startup behaviour now myself after a
> >> >>> fresh rebuild of everything (now using httpd-2.4.6 and
> perl-5.19.5). I
> >> >>> will look back over the changes made on the threading branch and/or
> my
> >> >>> merges of them into the httpd24 branch. Hopefully the answer lies
> >> >>> there somewhere. I'll be very grateful for any help I can get with
> >> >>> this though -- I didn't do the original work on either of those
> >> >>> branches...
> >> >>
> >> >>
> >> >> With the "fix" above in place, modperl_init_vhost() seems to be the
> >> >> next
> >> >> crucial code.  We go down this path:
> >> >>
> >> >>     if (base_server == s) {
> >> >>         MP_TRACE_i(MP_FUNC, "base server is not vhost, skipping %s",
> >> >>                    vhost);
> >> >>         return OK;
> >> >>     }
> >> >>
> >> >> and fall through this FIXME in modperl_interp_pool_select():
> >> >>
> >> >>                 if (!scfg->mip) {
> >> >>                     /* FIXME: We get here if global "server_rec" ==
> s,
> >> >> scfg->mip
> >> >>                      * is not created then. I'm not sure if that's
> bug
> >> >> or
> >> >>                      * bad/good design decicision. For now just
> return
> >> >> NULL.
> >> >>                      */
> >> >>                     return NULL;
> >> >>                 }
> >> >>
> >> >> (Note: disabling the base_server == s check in modperl_init_vhost()
> >> >> brings
> >> >> no happiness either, though perhaps it is a step in the right
> >> >> direction.)
> >> >>
> >> >> This path is new with httpd 2.4; 2.2 didn't have authz_providers.
> >> >>
> >> >> This seems to be a whack-a-mole issue.  I'd expect that there is some
> >> >> easy
> >> >> way to grab the interpreter for any arbitrary startup path, but I
> don't
> >> >> see
> >> >> it.  Maybe it is worthwhile seeing if we already went through some
> >> >> paths
> >> >> where we were able to grab an interpreter.
> >> >>
> >> >
> >> > The last change on the httpd24 branch (r1503193) is what added the
> >> > FIXME above, but it also made a change in perl_parse_require_line()
> >> > which I've lost in the course of merging the threading branch in: it
> >> > made that function tolerant of modperl_interp_pool_select() returning
> >> > NULL (which is exactly what happens in the FIXME case).
> >> >
> >> > If modperl_interp_pool_select() returns NULL then
> >> > perl_parse_require_line() just returns NULL itself in r1503193, but in
> >> > httpd24threading I've hidden the use of modperl_interp_pool_select()
> >> > within the MP_dINTERP_POOLa() macro (as per the general style of
> >> > changes in the threading branch), but that macro crashes if
> >> > modperl_interp_pool_select() has returned NULL.
> >> >
> >> > The diff below makes that macro tolerant of
> >> > modperl_interp_pool_select() returning NULL, and makes
> >> > perl_parse_require_line() tolerant of interp ending up NULL, like it
> >> > used to be in r1503193.
> >> >
> >> > With this diff in place (which includes your earlier change), the
> >> > server now starts up for me and tests appear to be running as normal.
> >>
> >> Oops! In my excitement I forgot the diff!:
> >>
> >> Index: src/modules/perl/modperl_interp.h
> >> ===================================================================
> >> --- src/modules/perl/modperl_interp.h   (revision 1539262)
> >> +++ src/modules/perl/modperl_interp.h   (working copy)
> >> @@ -68,9 +68,12 @@
> >>  #define MP_INTERP_POOLa(p, s)
>   \
> >>      MP_TRACE_i(MP_FUNC, "selecting interp: p=%pp, s=%pp", (p), (s));
>  \
> >>      interp = modperl_interp_pool_select((p), (s));
>  \
> >> -    MP_TRACE_i(MP_FUNC, "  --> got (0x%pp)->refcnt=%d",
>   \
> >> -               interp, interp->refcnt);
>   \
> >> -    aTHX = interp->perl
> >> +    if (interp) {
>   \
> >> +        MP_TRACE_i(MP_FUNC, "  --> got (0x%pp)->refcnt=%d",
>   \
> >> +                   interp, interp->refcnt);
>   \
> >> +        aTHX = interp->perl;
>  \
> >> +    }
>   \
> >> +    NOOP
> >>
> >>  #define MP_dINTERP_POOLa(p, s)
>  \
> >>      MP_dINTERP;
>   \
> >> Index: src/modules/perl/modperl_util.c
> >> ===================================================================
> >> --- src/modules/perl/modperl_util.c     (revision 1539262)
> >> +++ src/modules/perl/modperl_util.c     (working copy)
> >> @@ -989,8 +989,11 @@
> >>      int count;
> >>      void *key;
> >>      auth_callback *ab;
> >> -    MP_dINTERP_POOLa(cmd->server->process->pool, cmd->server);
> >> +    MP_dINTERP_POOLa(cmd->pool, cmd->server);
> >>
> >> +    if (!interp)
> >> +       return ret;
> >> +
> >>      if (global_authz_providers == NULL) {
> >>          MP_INTERP_PUTBACK(interp, aTHX);
> >>          return ret;
> >
> >
> > I don't think it will ever have an interpreter except when processing a
> > require from htaccess.  Still, it doesn't crash, and I get the same test
> > results as in my prior post.
> >
> > I think this should trigger an error if we get past these checks with no
> > interpreter:
> >
> > if (global_authz_providers == NULL ||
> apr_hash_count(global_authz_providers)
> > == 0) {
> >     /* put back an interpreter if we got one */
> >     return ret; /* still NULL; why not make it obvious? */
> > }
> >
> > apr_pool_userdata_get(&key, AUTHZ_PROVIDER_NAME_NOTE, cmd->temp_pool);
> > ab = apr_hash_get(global_authz_providers, (char *) key,
> > APR_HASH_KEY_STRING);
> > if (ab == NULL || ab->cb2 == NULL) {
> >     /* put back an interpreter if we got one */
> >     return ret; /* still NULL; why not make it obvious? */
> > }
> >
> > if (!interp) {
> >     return "Require handler is not currently supported in this context."
> > }
> >
> > And the ordering issue (create interpreter vs. handle Require parsing)
> still
> > needs to be resolved.
>
> I've committed my change to make the macro more robust, plus your
> change to delay trying to fetch an interpreter -- with an early return
> if it still fails -- in revisions 1539412 and 1539414. Thanks for your
> help with this!
>

Cool!

BTW, to return an error from a require line parser, you actually return the
error string (like a directive parser).  Here's an example of one from
mod_ssl that just ensures there are no arguments:

static const char *ssl_authz_require_ssl_parse(cmd_parms *cmd,
                                               const char *require_line,
                                               const void **parsed)
{
    if (require_line && require_line[0])
        return "'Require ssl' does not take arguments";

    return NULL;
}

So returning the error string in the unhandled case (instead of NULL) would
probably be good.

BUT:


> I don't know what to do about trying to fix it for real (i.e. the
> ordering problem that you refer to). I'm hoping someone else on the
> list might be able to help?
>

I'm trying to follow this through from a directive like in the testcase:

PerlAddAuthzProvider my-user TestAPI::access2_24->authz_handler

mod_perl.c has

MP_CMD_SRV_TAKE2("PerlAddAuthzProvider", authz_provider,
"PerlAddAuthzProvider"),

authz_provider takes exactly 2 arguments (or httpd will trigger an error).
 The first argument (like "my-user") is name and the second argument (like
"TestAPI::access2_24->authz_handler") is cb in the following call:

modperl_register_auth_provider_name(p, AUTHZ_PROVIDER_GROUP, name,
                                        AUTHZ_PROVIDER_VERSION, cb, NULL,
                                        AP_AUTH_INTERNAL_PER_CONF);

in modperl_register_auth_provider(), cb and the following NULL are
callback1 and callback2, and we have

    ab->cb1 = callback1;
    ab->cb2 = callback2;

    return register_auth_provider(pool, provider_group, provider_name_dup,
                                  provider_version, ab, type);

(callback2 always NULL for an authz provider)

register_auth_provider(), for an authz provider like this, stores ab (the
two callbacks, one always NULL), in the global_authz_providers hash then
calls the httpd API to point to authz_perl_provider for the authz provider
with this name (e.g., "my-user").

authz_perl_provider is the thing that says call perl_parse_require_line;
perl_parse_require_line is our new friend that tries real hard to get an
interpreter in case cb2 is non-NULL, which it never will be, until
PerlAddAuthzProvider is updated to allow an optional 2nd handler which
would be called at init to check a require line for errors.

Similarly it would seem that the authn variant, for which a second handler
would have the task of obtaining a password hash for the realm, also cannot
be configured.

>From the application/script standpoint, I think the drawback of not being
able to provide a require line parser is that I'd be required to look at it
a steady state and possibly encounter configuration errors that could have
been reported at startup  (a.k.a. not the end of the world; nothing really
to parse for some authz providers).



>
>
> >
> > I guess TestAPI::access2_24.pm needs more code to declare a require
> parser.
> > Any idea how to do that, just to see something found in the hash?
>
> Sorry, I don't know that right now either, but I will look into it too.
>

After looking, I think there's no way (see above).

-- 
Born in Roswell... married an alien...
http://emptyhammock.com/

Reply via email to