summaryrefslogtreecommitdiffstats
path: root/modules/dav
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2016-06-14 00:33:35 +0200
committerGraham Leggett <minfrin@apache.org>2016-06-14 00:33:35 +0200
commit75b17584442b34dfa6063b91311427d8fb35da0f (patch)
tree231ff8c74178209b905cf30bd8a96cbb01b02384 /modules/dav
parentbackported to 2.4.21-dev (diff)
downloadapache2-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/dav')
-rw-r--r--modules/dav/main/mod_dav.c71
-rw-r--r--modules/dav/main/mod_dav.h43
-rw-r--r--modules/dav/main/props.c126
-rw-r--r--modules/dav/main/providers.c13
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)