On 6 November 2013 19:06, Jeff Trawick <traw...@gmail.com> wrote: > 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.
Thanks, I hadn't realized that. I thought this was just pseudo-code when you posted this earlier! Now done in r1539487. > > 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). Many thanks for the analysis. I've added a comment summarizing this in the same revision as above (r1539487). I'm now intending to make similar changes for the PerlAddAuthnProvider case to protect that against a future crash if support for the second handler is ever added there too. Does the following look OK? In particular, is it correct to be returning AUTH_GENERAL_ERROR, or should it be AUTH_USER_NOT_FOUND like the existing early returns are? Index: src/modules/perl/modperl_util.c =================================================================== --- src/modules/perl/modperl_util.c (revision 1539487) +++ src/modules/perl/modperl_util.c (working copy) @@ -1116,52 +1116,67 @@ const char *realm, char **rethash) { authn_status ret = AUTH_USER_NOT_FOUND; - int count; - SV *rh; const char *key; auth_callback *ab; - MP_dINTERPa(r, NULL, NULL); - if (global_authn_providers == NULL) { - MP_INTERP_PUTBACK(interp, aTHX); - return ret; + if (global_authn_providers == NULL || + apr_hash_count(global_authn_providers) == 0) + { + return AUTH_USER_NOT_FOUND; } key = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE); ab = apr_hash_get(global_authn_providers, key, APR_HASH_KEY_STRING); if (ab == NULL || ab->cb2) { - MP_INTERP_PUTBACK(interp, aTHX); - return ret; + return AUTH_USER_NOT_FOUND; } - rh = sv_2mortal(newSVpv("", 0)); { - dSP; - ENTER; - SAVETMPS; - PUSHMARK(SP); - XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::RequestRec", r))); - XPUSHs(sv_2mortal(newSVpv(user, 0))); - XPUSHs(sv_2mortal(newSVpv(realm, 0))); - XPUSHs(newRV_noinc(rh)); - PUTBACK; - count = call_sv(ab->cb2, G_SCALAR); - SPAGAIN; + /* PerlAddAuthnProvider currently does not support an optional second + * handler, so ab->cb2 should always be NULL above and we will never get + * here. If such support is added in the future then this code will be + * reached, but cannot succeed in the absence of an interpreter. The + * second handler would be called at init to obtain a password hash for + * the realm, but in the current design there is no interpreter available + * at that time. + */ + MP_dINTERPa(r, NULL, NULL); + if (!interp) { + return AUTH_GENERAL_ERROR; + } - if (count == 1) { - const char *tmp = SvPV_nolen(rh); - ret = (authn_status) POPi; - if (*tmp != '\0') { - *rethash = apr_pstrdup(r->pool, tmp); + { + SV* rh = sv_2mortal(newSVpv("", 0)); + int count; + dSP; + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::RequestRec", r))); + XPUSHs(sv_2mortal(newSVpv(user, 0))); + XPUSHs(sv_2mortal(newSVpv(realm, 0))); + XPUSHs(newRV_noinc(rh)); + PUTBACK; + count = call_sv(ab->cb2, G_SCALAR); + SPAGAIN; + + if (count == 1) { + const char *tmp = SvPV_nolen(rh); + ret = (authn_status) POPi; + if (*tmp != '\0') { + *rethash = apr_pstrdup(r->pool, tmp); + } } + + PUTBACK; + FREETMPS; + LEAVE; } - PUTBACK; - FREETMPS; - LEAVE; + MP_INTERP_PUTBACK(interp, aTHX); } - MP_INTERP_PUTBACK(interp, aTHX); return ret; } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@perl.apache.org For additional commands, e-mail: dev-h...@perl.apache.org