diff options
author | Graham Leggett <minfrin@apache.org> | 2016-06-14 00:33:35 +0200 |
---|---|---|
committer | Graham Leggett <minfrin@apache.org> | 2016-06-14 00:33:35 +0200 |
commit | 75b17584442b34dfa6063b91311427d8fb35da0f (patch) | |
tree | 231ff8c74178209b905cf30bd8a96cbb01b02384 /modules | |
parent | backported to 2.4.21-dev (diff) | |
download | apache2-75b17584442b34dfa6063b91311427d8fb35da0f.tar.xz apache2-75b17584442b34dfa6063b91311427d8fb35da0f.zip |
Allow other modules to become providers and add ACLs
to the DAV response. Requires apr-util v1.6+.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1748322 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules')
-rw-r--r-- | modules/dav/main/mod_dav.c | 71 | ||||
-rw-r--r-- | modules/dav/main/mod_dav.h | 43 | ||||
-rw-r--r-- | modules/dav/main/props.c | 126 | ||||
-rw-r--r-- | modules/dav/main/providers.c | 13 |
4 files changed, 248 insertions, 5 deletions
diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index a534b9ffe1..f5e94be404 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -770,6 +770,14 @@ static dav_error *dav_get_resource(request_rec *r, int label_allowed, * add it now */ dav_add_vary_header(r, r, *res_p); +#ifdef APR_XML_X2T_PARSED + /* if acls checking -> check if allowed method excluding propfind */ + if (((*res_p)->acls = dav_get_acl_providers()) && + (err = (*res_p)->acls->acl_check_method(r, *res_p))) { + return err; + } +#endif + return NULL; } @@ -926,6 +934,7 @@ static int dav_method_put(request_rec *r) int has_range; apr_off_t range_start; apr_off_t range_end; + int rc; /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, @@ -1151,7 +1160,16 @@ static int dav_method_put(request_rec *r) /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */ /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS); + rc = dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS); + +#ifdef APR_XML_X2T_PARSED + if (resource->acls) { + resource->acls->acl_post_processing(r, resource, + r->status == HTTP_CREATED); + } +#endif + + return rc; } @@ -1300,6 +1318,12 @@ static int dav_method_delete(request_rec *r) dav_log_err(r, err, APLOG_WARNING); } +#ifdef APR_XML_X2T_PARSED + if (resource->acls) { + resource->acls->acl_post_processing(r, resource, FALSE); + } +#endif + /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */ /* Apache will supply a default error for this. */ @@ -1982,6 +2006,18 @@ static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype) dav_error *err; dav_propdb *propdb; dav_get_props_result propstats = { 0 }; +#ifdef APR_XML_X2T_PARSED + dav_resource *resource = (dav_resource *)wres->resource; + + /* propfind skipped if no read privilege to a resource + ** setting acls from parent resource + */ + resource->acls = ctx->w.root->acls; + if (resource->acls && + (err = resource->acls->acl_check_read(ctx->r, resource))) { + return NULL; + } +#endif /* ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since @@ -2461,6 +2497,12 @@ static int dav_method_proppatch(request_rec *r) dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces); +#ifdef APR_XML_X2T_PARSED + if (resource->acls) { + resource->acls->acl_post_processing(r, resource, FALSE); + } +#endif + /* the response has been sent. */ return DONE; } @@ -2531,6 +2573,7 @@ static int dav_method_mkcol(request_rec *r) dav_error *err; dav_error *err2; int result; + int rc; dav_response *multi_status; /* handle the request body */ @@ -2634,7 +2677,15 @@ static int dav_method_mkcol(request_rec *r) } /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, NULL, "Collection", 0); + rc = dav_created(r, NULL, "Collection", 0); + +#ifdef APR_XML_X2T_PARSED + if (resource->acls) { + resource->acls->acl_post_processing(r, resource, r->status == 201); + } +#endif + + return rc; } /* handle the COPY and MOVE methods */ @@ -2658,6 +2709,7 @@ static int dav_method_copymove(request_rec *r, int is_move) dav_lockdb *lockdb; int replace_dest; int resnew_state; + int rc; /* Ask repository module to resolve the resource */ err = dav_get_resource(r, !is_move /* label_allowed */, @@ -3039,8 +3091,19 @@ static int dav_method_copymove(request_rec *r, int is_move) } /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, lookup.rnew->unparsed_uri, "Destination", - resnew_state == DAV_RESOURCE_EXISTS); + rc = dav_created(r, lookup.rnew->uri, "Destination", + resnew_state == DAV_RESOURCE_EXISTS); + +#ifdef APR_XML_X2T_PARSED + if (resource->acls) { + resource->acls->acl_post_processing(r, resource, FALSE); + + resource->acls->acl_post_processing(r, resnew, + r->status == HTTP_CREATED); + } +#endif + + return rc; } /* dav_method_lock: Handler to implement the DAV LOCK method diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index e354e8b44b..cab6578204 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -319,6 +319,10 @@ typedef enum { */ typedef struct dav_resource_private dav_resource_private; +#ifdef APR_XML_X2T_PARSED +typedef struct dav_acl_provider dav_acl_provider; +#endif + /* ** Resource descriptor, generated by a repository provider. ** @@ -418,6 +422,12 @@ typedef struct dav_resource { long as the dav_resource structure. */ apr_pool_t *pool; +#ifdef APR_XML_X2T_PARSED + const dav_acl_provider *acls; /* acls used for this resource */ +#endif + + void *ctx; /* additional parameter */ + } dav_resource; /* @@ -2498,6 +2508,39 @@ typedef struct { const dav_hooks_liveprop *provider; /* the provider defining this prop */ } dav_elem_private; + +/* -------------------------------------------------------------------- +** +** DAV ACL HOOKS +*/ +#ifdef APR_XML_X2T_PARSED + +typedef struct dav_acl_provider +{ + dav_error * (*acl_check_method)(request_rec *r, + const dav_resource *resource); + + dav_error * (*acl_check_read)(request_rec *r, + const dav_resource *resource); + + dav_error * (*acl_check_prop)(request_rec *r, + const dav_resource *resource, + const dav_prop_name *name, + dav_prop_insert what); + + void (*acl_post_processing)(request_rec *r, + const dav_resource *resource, + int new_resource_created); + void *ctx; +} dav_acl_provider; + +DAV_DECLARE(void) dav_acl_provider_register(apr_pool_t *p, + const dav_acl_provider *acl); + +DAV_DECLARE(const dav_acl_provider *) dav_get_acl_providers(); + +#endif + /* -------------------------------------------------------------------- ** ** DAV OPTIONS diff --git a/modules/dav/main/props.c b/modules/dav/main/props.c index 47cc509bd4..792c87db8b 100644 --- a/modules/dav/main/props.c +++ b/modules/dav/main/props.c @@ -578,6 +578,9 @@ DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, int found_contenttype = 0; int found_contentlang = 0; dav_prop_insert unused_inserted; +#ifdef APR_XML_X2T_PARSED + apr_text *text; +#endif /* if not just getting supported live properties, * scan all properties in the dead prop database @@ -622,6 +625,17 @@ DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, } } +#ifdef APR_XML_X2T_PARSED + /* check for possible special acl restrictions not provided by read privilege */ + if (propdb->resource->acls && + propdb->resource->acls->acl_check_prop && + propdb->resource->acls-> + acl_check_prop(propdb->r, propdb->resource, + &name, what)) { + goto next_key; + } +#endif + if (what == DAV_PROP_INSERT_VALUE) { int found; @@ -653,6 +667,9 @@ DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, /* add namespaces for all the liveprop providers */ dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns); } +#ifdef APR_XML_X2T_PARSED + text = hdr.last; +#endif /* ask the liveprop providers to insert their properties */ dav_run_insert_all_liveprops(propdb->r, propdb->resource, what, &hdr); @@ -682,6 +699,62 @@ DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, what, &hdr, &unused_inserted); } +#ifdef APR_XML_X2T_PARSED + if (propdb->resource->acls && + propdb->resource->acls->acl_check_prop) { + + /* unfortunately liveprops cannot be checked beforehand */ + apr_xml_doc *doc = NULL; + apr_text *t; + apr_xml_elem *elem; + apr_pool_t *pool; + apr_xml_parser *parser; + + apr_pool_create (&pool, propdb->p); + parser = apr_xml_parser_create (pool); + + apr_xml_parser_feed(parser, "<r xmlns:D=\"DAV:\" ", 18); + for (t = hdr_ns.first; t; t = t->next) { + if (t->text) + apr_xml_parser_feed(parser, t->text, strlen(t->text)); + } + apr_xml_parser_feed(parser, ">", 1); + + hdr.last = text ? text : hdr.first; + + for (text = text ? text->next : hdr.first; text; text = text->next) { + if (text->text) + apr_xml_parser_feed(parser, text->text, strlen(text->text)); + } + apr_xml_parser_feed(parser, "</r>", 4); + + apr_xml_parser_done(parser, &doc); + + for (elem = doc ? doc->root->first_child : NULL; elem; + elem = elem->next) { + dav_prop_name name[1]; + + name->ns = elem->ns == APR_XML_NS_NONE ? "" : + APR_XML_GET_URI_ITEM(doc->namespaces, elem->ns); + name->name = elem->name; + + if (propdb->resource->acls-> + acl_check_prop(propdb->r, propdb->resource, + name, what) == NULL) { + const char *buf; + + /* APR_XML_X2T_FULL_NS_LANG mangles original namespace prefixes */ + apr_xml_to_text(pool, elem, APR_XML_X2T_PARSED, + NULL, NULL, &buf, NULL); + + buf = apr_pstrcat (pool, buf, DEBUG_CR, NULL); + apr_text_append(propdb->p, &hdr, buf); + } + } + apr_pool_destroy(pool); + } +#endif + /* if not just reporting on supported live props, * terminate the result */ if (what != DAV_PROP_INSERT_SUPPORTED) { @@ -703,6 +776,9 @@ DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb, apr_xml_elem *elem = dav_find_child(doc->root, "prop"); apr_text_header hdr_good = { 0 }; apr_text_header hdr_bad = { 0 }; +#ifdef APR_XML_X2T_PARSED + apr_text_header hdr_not_auth = { 0 }; +#endif apr_text_header hdr_ns = { 0 }; int have_good = 0; dav_get_props_result result = { 0 }; @@ -744,11 +820,40 @@ DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb, priv = elem->priv; /* cache the propid; dav_get_props() could be called many times */ - if (priv->propid == 0) + if (priv->propid == 0) { dav_find_liveprop(propdb, elem); + } if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { +#ifdef APR_XML_X2T_PARSED + /* check for possible special acl restrictions not provided by read privilege + * ask for each live prop separately (e.g. read-acl privilege) */ + if (propdb->resource->acls && + propdb->resource->acls->acl_check_prop) { + name.ns = elem->ns == APR_XML_NS_NONE ? "" : + APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); + name.name = elem->name; + + if (propdb->resource->acls-> + acl_check_prop(propdb->r, propdb->resource, + &name, DAV_PROP_INSERT_VALUE)) { + + if (hdr_not_auth.first == NULL) { + apr_text_append(propdb->p, &hdr_not_auth, + "<D:propstat>" DEBUG_CR + "<D:prop>" DEBUG_CR); + } + + if (!name.ns) { + name.ns = ""; + } + dav_output_prop_name(propdb->p, &name, xi, &hdr_not_auth); + continue; + } + } +#endif + /* insert the property. returns 1 if an insertion was done. */ if ((err = dav_insert_liveprop(propdb, elem, DAV_PROP_INSERT_VALUE, &hdr_good, &inserted)) != NULL) { @@ -878,6 +983,25 @@ DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb, } } +#ifdef APR_XML_X2T_PARSED + if (hdr_not_auth.first != NULL) { + apr_text_append(propdb->p, &hdr_not_auth, + "</D:prop>" DEBUG_CR + "<D:status>HTTP/1.1 403 Forbidden</D:status>" DEBUG_CR + "</D:propstat>" DEBUG_CR); + + if (!have_good && !hdr_bad.first) { + result.propstats = hdr_not_auth.first; + } + else if (hdr_bad.first != NULL) { + hdr_bad.last->next = hdr_not_auth.first; + } + else { + hdr_good.last->next = hdr_not_auth.first; + } + } +#endif + /* add in all the various namespaces, and return them */ dav_xmlns_generate(xi, &hdr_ns); result.xmlns = hdr_ns.first; diff --git a/modules/dav/main/providers.c b/modules/dav/main/providers.c index 44870fd01b..e1e07d45bd 100644 --- a/modules/dav/main/providers.c +++ b/modules/dav/main/providers.c @@ -32,6 +32,19 @@ DAV_DECLARE(const dav_provider *) dav_lookup_provider(const char *name) return ap_lookup_provider(DAV_PROVIDER_GROUP, name, "0"); } +#ifdef APR_XML_X2T_PARSED +DAV_DECLARE(void) dav_acl_provider_register(apr_pool_t *p, + const dav_acl_provider *provider) +{ + ap_register_provider(p, DAV_PROVIDER_GROUP, "acl", "0", provider); +} + +DAV_DECLARE(const dav_acl_provider *) dav_get_acl_providers() +{ + return ap_lookup_provider(DAV_PROVIDER_GROUP, "acl", "0"); +} +#endif + DAV_DECLARE(void) dav_options_provider_register(apr_pool_t *p, const char *name, const dav_options_provider *provider) |