Example #1
0
static dav_error *dav_acl_patch_validate(const dav_resource * resource,
                                         const apr_xml_elem * elem,
                                         int operation,
                                         void **context,
                                         int *defer_to_dead)
{
    apr_pool_t *pool = resource->pool;
    dav_repos_resource *db_r = resource->info->db_r;
    dav_repos_db *db = resource->info->db;
    request_rec *rec = resource->info->rec;
    dav_elem_private *priv = elem->priv;
    dav_error *err = NULL;

    TRACE();

    if (priv->propid == DAV_PROPID_group_member_set) {
	*defer_to_dead = 0;
        if (db_r->resourcetype!=dav_repos_GROUP || operation!=DAV_PROP_OP_SET)
            return dav_new_error(pool, HTTP_FORBIDDEN, 0,
                                 "Not a set operation on a group");
            
        apr_xml_elem *href_elem = dav_find_child(elem, "href");
        apr_hash_t *new_members = apr_hash_make(pool);
        apr_array_header_t *to_remove = NULL;

        while (href_elem && !err) {
            const char *prin_uri = dav_xml_get_cdata(href_elem, pool, 1);
            const char *prin_name = get_name_from_principal_URL(rec, prin_uri);
            if (prin_name == NULL)
                err = dav_new_error
                  (pool, HTTP_CONFLICT, 0, "Not a DAV:principal-URL");
            else
                apr_hash_set(new_members, prin_name, APR_HASH_KEY_STRING, "");
            href_elem = href_elem->next;
        }
        if (err) return err;
        if (apr_hash_count(new_members))
            err = dbms_calculate_group_changes(db, db_r, new_members,&to_remove);
        else
            err = dbms_get_group_members(db, db_r, &to_remove);
        if (err) return err;
        apr_hash_set(new_members, "-to-remove-", APR_HASH_KEY_STRING, to_remove);
        *context = new_members;
    }
    return err;
}
DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb,
                                                apr_xml_doc *doc)
{
    const dav_hooks_db *db_hooks = propdb->db_hooks;
    apr_xml_elem *elem = dav_find_child(doc->root, "prop");
    apr_text_header hdr_good = { 0 };
    apr_text_header hdr_bad = { 0 };
    apr_text_header hdr_ns = { 0 };
    int have_good = 0;
    dav_get_props_result result = { 0 };
    char *marks_liveprop;
    dav_xmlns_info *xi;
    int xi_filled = 0;

    /* ### NOTE: we should pass in TWO buffers -- one for keys, one for
       the marks */

    /* we will ALWAYS provide a "good" result, even if it is EMPTY */
    apr_text_append(propdb->p, &hdr_good,
                   "<D:propstat>" DEBUG_CR
                   "<D:prop>" DEBUG_CR);

    /* ### the marks should be in a buffer! */
    /* allocate zeroed-memory for the marks. These marks indicate which
       liveprop namespaces we've generated into the output xmlns buffer */

    /* same for the liveprops */
    marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1);

    xi = dav_xmlns_create(propdb->p);

    for (elem = elem->first_child; elem; elem = elem->next) {
        dav_elem_private *priv;
        dav_error *err;
        dav_prop_insert inserted;
        dav_prop_name name;

        /*
        ** First try live property providers; if they don't handle
        ** the property, then try looking it up in the propdb.
        */

        if (elem->priv == NULL) {
            elem->priv = apr_pcalloc(propdb->p, sizeof(*priv));
        }
        priv = elem->priv;

        /* cache the propid; dav_get_props() could be called many times */
        if (priv->propid == 0)
            dav_find_liveprop(propdb, elem);

        if (priv->propid != DAV_PROPID_CORE_UNKNOWN) {

            /* 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) {
                /* ### need to propagate the error to the caller... */
                /* ### skip it for now, as if nothing was inserted */
            }
            if (inserted == DAV_PROP_INSERT_VALUE) {
                have_good = 1;

                /*
                ** Add the liveprop's namespace URIs. Note that provider==NULL
                ** for core properties.
                */
                if (priv->provider != NULL) {
                    const char * const * scan_ns_uri;

                    for (scan_ns_uri = priv->provider->namespace_uris;
                         *scan_ns_uri != NULL;
                         ++scan_ns_uri) {
                        long ns;

                        ns = dav_get_liveprop_ns_index(*scan_ns_uri);
                        if (marks_liveprop[ns])
                            continue;
                        marks_liveprop[ns] = 1;

                        dav_insert_xmlns(propdb->p, "lp", ns, *scan_ns_uri,
                                         &hdr_ns);
                    }
                }

                /* property added. move on to the next property. */
                continue;
            }
            else if (inserted == DAV_PROP_INSERT_NOTDEF) {
                /* nothing to do. fall thru to allow property to be handled
                   as a dead property */
            }
#if DAV_DEBUG
            else {
#if 0
                /* ### need to change signature to return an error */
                return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0,
                                     0,
                                     "INTERNAL DESIGN ERROR: insert_liveprop "
                                     "did not insert what was asked for.");
#endif
            }
#endif
        }

        /* The property wasn't a live property, so look in the dead property
           database. */

        /* make sure propdb is really open */
        if (propdb->deferred) {
            /* ### what to do with db open error? */
            (void) dav_really_open_db(propdb, 1 /*ro*/);
        }

        if (elem->ns == APR_XML_NS_NONE)
            name.ns = "";
        else
            name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns);
        name.name = elem->name;

        /* only bother to look if a database exists */
        if (propdb->db != NULL) {
            int found;

            if ((err = (*db_hooks->output_value)(propdb->db, &name,
                                                 xi, &hdr_good,
                                                 &found)) != NULL) {
                /* ### what to do? continue doesn't seem right... */
                continue;
            }

            if (found) {
                have_good = 1;

                /* if we haven't added the db's namespaces, then do so... */
                if (!xi_filled) {
                    (void) (*db_hooks->define_namespaces)(propdb->db, xi);
                    xi_filled = 1;
                }
                continue;
            }
        }

        /* not found as a live OR dead property. add a record to the "bad"
           propstats */

        /* make sure we've started our "bad" propstat */
        if (hdr_bad.first == NULL) {
            apr_text_append(propdb->p, &hdr_bad,
                            "<D:propstat>" DEBUG_CR
                            "<D:prop>" DEBUG_CR);
        }

        /* output this property's name (into the bad propstats) */
        dav_output_prop_name(propdb->p, &name, xi, &hdr_bad);
    }

    apr_text_append(propdb->p, &hdr_good,
                    "</D:prop>" DEBUG_CR
                    "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
                    "</D:propstat>" DEBUG_CR);

    /* default to start with the good */
    result.propstats = hdr_good.first;

    /* we may not have any "bad" results */
    if (hdr_bad.first != NULL) {
        /* "close" the bad propstat */
        apr_text_append(propdb->p, &hdr_bad,
                        "</D:prop>" DEBUG_CR
                        "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
                        "</D:propstat>" DEBUG_CR);

        /* if there are no good props, then just return the bad */
        if (!have_good) {
            result.propstats = hdr_bad.first;
        }
        else {
            /* hook the bad propstat to the end of the good one */
            hdr_good.last->next = hdr_bad.first;
        }
    }

    /* add in all the various namespaces, and return them */
    dav_xmlns_generate(xi, &hdr_ns);
    result.xmlns = hdr_ns.first;

    return result;
}
Example #3
0
DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx)
{
    dav_propdb *propdb = ctx->propdb;
    dav_error *err = NULL;
    dav_elem_private *priv = ctx->prop->priv;
    const dav_hooks_acl *acl_hooks = dav_get_acl_hooks(ctx->r);
    dav_prop_name name;

    ctx->rollback = apr_pcalloc(propdb->p, sizeof(*ctx->rollback));

    if (ctx->prop->ns == APR_XML_NS_NONE)
        name.ns = "";
    else
        name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, ctx->prop->ns);
    name.name = ctx->prop->name;


    if (ctx->is_liveprop) {
        err = (*priv->provider->patch_exec)(propdb->resource,
                                            ctx->prop, ctx->operation,
                                            ctx->liveprop_ctx,
                                            &ctx->rollback->liveprop);
    }
    else {
        /* save the old value so that we can do a rollback. */
        if ((err = (*propdb->db_hooks
                    ->get_rollback)(propdb->db, &name,
                                    &ctx->rollback->deadprop)) != NULL)
            goto error;

        if (ctx->operation == DAV_PROP_OP_SET) {

            /* Note: propdb->mapping was set in dav_prop_validate() */
            err = (*propdb->db_hooks->store)(propdb->db, &name, ctx->prop,
                                             propdb->mapping);

            /*
            ** If an error occurred, then assume that we didn't change the
            ** value. Remove the rollback item so that we don't try to set
            ** its value during the rollback.
            */
            /* ### euh... where is the removal? */
        }
        else if (ctx->operation == DAV_PROP_OP_DELETE) {

            /*
            ** Delete the property. Ignore errors -- the property is there, or
            ** we are deleting it for a second time.
            */
            /* ### but what about other errors? */
            (void) (*propdb->db_hooks->remove)(propdb->db, &name);
        }
    }

    if(acl_hooks) {

        /* update any DAV:property ACE(s) that depend on this property */
        const char *newval = 
            dav_xml_get_cdata(dav_find_child(ctx->prop, "href"), propdb->p, 1);

        /* @NOTE: works only in presence of transactions,
         * currently no rollback state being stored for ACE changes */
        /* assuming cdata is NULL for D:remove prop elem */
        if(newval)
            (*acl_hooks->update_principal_property_aces)(
                (dav_resource *)propdb->resource, &name, newval);
    }

error:
    /* push a more specific error here */
    if (err != NULL) {
        if (err->status == HTTP_CONFLICT) {
            /* semantics of the value are not appropriate for the property */
            ctx->err = err;
        } else {
            /*
            ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen
            ** any other errors at this point.
            */
            ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
                                      DAV_ERR_PROP_EXEC,
                                      "Could not execute PROPPATCH.", err);
        }
    }
}
Example #4
0
File: acl.c Project: Jux/limestone
dav_error *dav_repos_deliver_principal_property_search(request_rec * r,
						       const dav_resource *
						       resource,
						       const apr_xml_doc *
						       doc,
						       ap_filter_t *
						       output)
{
    /* this buffers the output for a bit and is automatically flushed,
       at appropriate times, by the Apache filter system. */
    apr_bucket_brigade *bb;

    apr_pool_t *pool = resource->pool;
    dav_repos_db *db = resource->info->db;
    dav_repos_resource *db_r = (dav_repos_resource *) resource->info->db_r;
    apr_xml_elem *principal_property_search;
    apr_xml_elem *elem;
    apr_xml_elem *prop;
    apr_xml_elem *props;
    apr_xml_elem *match;
    int flag;

    TRACE();

    principal_property_search = dav_find_child(doc->root,
					       "principal-property-search");

    props = dav_find_child(doc->root, "prop");

    sabridge_get_collection_children(db, db_r, 1, "read",
                                     NULL, NULL, NULL);

    bb = apr_brigade_create(pool, output->c->bucket_alloc);
    r->status = HTTP_MULTI_STATUS;
    send_xml(bb, output, "<D:multistatus xmlns:D=\"DAV:\">" DEBUG_CR);

    while (db_r != NULL) {
	flag = 1;
	for (elem = principal_property_search->first_child;
	     elem && flag; elem = elem->next) {
	    if (!strcmp(elem->name, "property-search")) {
		prop = dav_find_child(elem, "prop");
		match = dav_find_child(elem, "match");
		dav_repos_build_lpr_hash(db_r);
		const char *val = apr_hash_get(db_r->lpr_hash,
					       prop->first_child->name,
					       APR_HASH_KEY_STRING);
		if (!strstr(val, match->first_cdata.first->text))
		    flag = 0;
	    }
	}
	if (flag) {
	    send_xml(bb, output, "<D:response>");
	    send_xml(bb, output,
		     dav_repos_mk_href(pool, db_r->uri));
	    send_xml(bb, output, "<D:propstat>");
	    send_xml(bb, output, "<D:prop>");
	    for (props = props->first_child; props; props = props->next) {
		const char *val;
		val =
		    apr_hash_get(db_r->lpr_hash, props->name,
				 APR_HASH_KEY_STRING);
		const char *str =
		    apr_psprintf(pool, "<D:%s>%s</D:%s>" DEBUG_CR,
				 props->name, 
                                 apr_xml_quote_string(pool, val, 0), 
                                 props->name);
		send_xml(bb, output, str);
	    }

	    send_xml(bb, output, "</D:prop>");
	    send_xml(bb, output,
		     "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR);

	    send_xml(bb, output, "</D:propstat>");
	    send_xml(bb, output, "</D:response>");
	}

	db_r = db_r->next;
    }

    send_xml(bb, output, "</D:multistatus>");

    /* flush the contents of the brigade */
    ap_fflush(output, bb);

    return NULL;
}
Example #5
0
File: acl.c Project: Jux/limestone
dav_error *dav_repos_deliver_principal_match(request_rec * r,
					     const dav_resource * resource,
					     const apr_xml_doc * doc,
					     ap_filter_t * output)
{
    /* this buffers the output for a bit and is automatically flushed,
       at appropriate times, by the Apache filter system. */
    apr_bucket_brigade *bb;

    apr_pool_t *pool = resource->pool;
    dav_repos_db *db = resource->info->db;
    dav_repos_resource *db_r = (dav_repos_resource *) resource->info->db_r;
    apr_xml_elem *principal_properties;
    char *req_username = r->user;
    long principal_id;
    dav_error *err = NULL;

    TRACE();

    if (!req_username) req_username = "******";

    if((err = dbms_get_principal_id_from_name(pool, db, req_username, 
                                              &principal_id))) {
        return err;
    }

    principal_properties =
	dav_find_child(doc->root, "principal-property");

    sabridge_get_collection_children(db, db_r, DAV_INFINITY, "read",
                                     NULL, NULL, NULL);

    bb = apr_brigade_create(pool, output->c->bucket_alloc);
    r->status = HTTP_MULTI_STATUS;
    send_xml(bb, output, "<D:multistatus xmlns:D=\"DAV:\">" DEBUG_CR);

    while ((db_r = db_r->next)) {
	// Currently supporting DAV:owner only
	if ((principal_properties && 
             !strcmp(principal_properties->name, "owner") && 
             db_r->owner_id == principal_id) || 
            (!principal_properties &&	// Found no principal_properties
             !strcmp(db_r->displayname, req_username)))
	{
	    send_xml(bb, output, "<D:response>");
	    const char *str =
		apr_psprintf(pool, "<D:href>%s</D:href>"
			     DEBUG_CR, apr_xml_quote_string(pool, db_r->uri, 0));
	    send_xml(bb, output, str);
	    send_xml(bb, output,
		     "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR);
	    send_xml(bb, output, "</D:response>");
	}
    }

    send_xml(bb, output, "</D:multistatus>");

    /* flush the contents of the brigade */
    ap_fflush(output, bb);
    return NULL;
}
Example #6
0
File: acl.c Project: Jux/limestone
dav_error *dav_repos_deliver_acl_principal_prop_set(request_rec * r,
						    const dav_resource *
						    resource,
						    const apr_xml_doc *
						    doc,
						    ap_filter_t * output)
{
    /* this buffers the output for a bit and is automatically flushed,
       at appropriate times, by the Apache filter system. */
    apr_bucket_brigade *bb;

    apr_pool_t *pool = resource->pool;
    dav_repos_db *db = resource->info->db;
    dav_repos_resource *db_r = (dav_repos_resource *) resource->info->db_r;
    apr_xml_elem *props;
    dav_repos_resource *principals = NULL;

    TRACE();

    props = dav_find_child(doc->root, "prop");

    dbms_get_principals(db, pool, db_r, principals);

    bb = apr_brigade_create(pool, output->c->bucket_alloc);
    r->status = HTTP_MULTI_STATUS;
    send_xml(bb, output, "<D:multistatus xmlns:D=\"DAV:\">" DEBUG_CR);

    while (principals != NULL) {
	sabridge_get_property(db, principals);
	dav_repos_build_lpr_hash(principals);
	send_xml(bb, output, "<D:response>");
	send_xml(bb, output, dav_repos_mk_href(pool, principals->uri));
	send_xml(bb, output, "<D:propstat>");
	send_xml(bb, output, "<D:prop>");
	for (props = props->first_child; props; props = props->next) {
	    const char *val;
	    val =
		apr_hash_get(principals->lpr_hash, props->name,
			     APR_HASH_KEY_STRING);
	    const char *str =
		apr_psprintf(pool, "<D:%s>%s</D:%s>" DEBUG_CR,
			     props->name, apr_xml_quote_string(pool, val, 0), 
                             props->name);
	    send_xml(bb, output, str);
	}

	send_xml(bb, output, "</D:prop>");
	send_xml(bb, output,
		 "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR);

	send_xml(bb, output, "</D:propstat>");
	send_xml(bb, output, "</D:response>");

	principals = principals->next;
    }

    send_xml(bb, output, "</D:multistatus>");

    /* flush the contents of the brigade */
    ap_fflush(output, bb);

    return NULL;

}