/* ### take an optional buf parameter? */
static dav_error * dav_fs_add_locknull_state(
    dav_lockdb *lockdb,
    const dav_resource *resource)
{
    dav_buffer buf = { 0 };
    apr_pool_t *p = lockdb->info->pool;
    const char *dirpath;
    const char *fname;
    dav_error *err;

    /* ### should test this result value... */
    (void) dav_fs_dir_file_name(resource, &dirpath, &fname);

    if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) {
        return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
                              "Could not load .locknull file.", err);
    }

    dav_buffer_append(p, &buf, fname);
    buf.cur_len++;   /* we want the null-term here */

    if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) {
        return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
                              "Could not save .locknull file.", err);
    }

    return NULL;
}
static dav_error *dav_really_open_db(dav_propdb *propdb, int ro)
{
    dav_error *err;

    /* we're trying to open the db; turn off the 'deferred' flag */
    propdb->deferred = 0;

    /* ask the DB provider to open the thing */
    err = (*propdb->db_hooks->open)(propdb->p, propdb->resource, ro,
                                    &propdb->db);
    if (err != NULL) {
        return dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_PROP_OPENING,
                              "Could not open the property database.",
                              err);
    }

    /*
    ** NOTE: propdb->db could be NULL if we attempted to open a readonly
    **       database that doesn't exist. If we require read/write
    **       access, then a database was created and opened.
    */

    return NULL;
}
Exemple #3
0
/*
 * dav_generic_really_open_lockdb:
 *
 * If the database hasn't been opened yet, then open the thing.
 */
static dav_error * dav_generic_really_open_lockdb(dav_lockdb *lockdb)
{
    dav_error *err;
    apr_status_t status;

    if (lockdb->info->opened) {
        return NULL;
    }

    status = apr_dbm_open(&lockdb->info->db, lockdb->info->lockdb_path,
                          lockdb->ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
                          APR_OS_DEFAULT, lockdb->info->pool);

    if (status) {
        err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
                                        status);
        return dav_push_error(lockdb->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_LOCK_OPENDB,
                              "Could not open the lock database.",
                              err);
    }

    /* all right. it is opened now. */
    lockdb->info->opened = 1;

    return NULL;
}
Exemple #4
0
DAV_DECLARE(dav_error *) dav_notify_created(request_rec *r,
                                            dav_lockdb *lockdb,
                                            const dav_resource *resource,
                                            int resource_state,
                                            int depth)
{
    dav_error *err;

    if (resource_state == DAV_RESOURCE_LOCK_NULL) {

        /*
        ** The resource is no longer a locknull resource. This will remove
        ** the special marker.
        **
        ** Note that a locknull resource has already inherited all of the
        ** locks from the parent. We do not need to call dav_inherit_locks.
        **
        ** NOTE: some lock providers record locks for locknull resources using
        **       a different key than for regular resources. this will shift
        **       the lock information between the two key types.
        */
        (void)(*lockdb->hooks->remove_locknull_state)(lockdb, resource);

        /*
        ** There are resources under this one, which are new. We must
        ** propagate the locks down to the new resources.
        */
        if (depth > 0 &&
            (err = dav_inherit_locks(r, lockdb, resource, 0)) != NULL) {
            /* ### add a higher level desc? */
            return err;
        }
    }
    else if (resource_state == DAV_RESOURCE_NULL) {

        /* ### should pass depth to dav_inherit_locks so that it can
        ** ### optimize for the depth==0 case.
        */

        /* this resource should inherit locks from its parent */
        if ((err = dav_inherit_locks(r, lockdb, resource, 1)) != NULL) {

            err = dav_push_error(r->pool, err->status, 0,
                                 "The resource was created successfully, but "
                                 "there was a problem inheriting locks from "
                                 "the parent resource.",
                                 err);
            return err;
        }
    }
    /* else the resource already exists and its locks are correct. */

    return NULL;
}
/*
** dav_fs_really_open_lockdb:
**
** If the database hasn't been opened yet, then open the thing.
*/
static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb)
{
    dav_error *err;

    if (lockdb->info->opened)
        return NULL;

    err = dav_dbm_open_direct(lockdb->info->pool,
                              lockdb->info->lockdb_path,
                              lockdb->ro,
                              &lockdb->info->db);
    if (err != NULL) {
        return dav_push_error(lockdb->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_LOCK_OPENDB,
                              "Could not open the lock database.",
                              err);
    }

    /* all right. it is opened now. */
    lockdb->info->opened = 1;

    return NULL;
}
Exemple #6
0
/*
** dav_lock_parse_lockinfo:  Validates the given xml_doc to contain a
**    lockinfo XML element, then populates a dav_lock structure
**    with its contents.
*/
DAV_DECLARE(dav_error *) dav_lock_parse_lockinfo(request_rec *r,
                                                 const dav_resource *resource,
                                                 dav_lockdb *lockdb,
                                                 const apr_xml_doc *doc,
                                                 dav_lock **lock_request)
{
    apr_pool_t *p = r->pool;
    dav_error *err;
    apr_xml_elem *child;
    dav_lock *lock;

    if (!dav_validate_root(doc, "lockinfo")) {
        return dav_new_error(p, HTTP_BAD_REQUEST, 0,
                             "The request body contains an unexpected "
                             "XML root element.");
    }

    if ((err = (*lockdb->hooks->create_lock)(lockdb, resource,
                                             &lock)) != NULL) {
        return dav_push_error(p, err->status, 0,
                              "Could not parse the lockinfo due to an "
                              "internal problem creating a lock structure.",
                              err);
    }

    lock->depth = dav_get_depth(r, DAV_INFINITY);
    if (lock->depth == -1) {
        return dav_new_error(p, HTTP_BAD_REQUEST, 0,
                             "An invalid Depth header was specified.");
    }
    lock->timeout = dav_get_timeout(r);

    /* Parse elements in the XML body */
    for (child = doc->root->first_child; child; child = child->next) {
        if (strcmp(child->name, "locktype") == 0
            && child->first_child
            && lock->type == DAV_LOCKTYPE_UNKNOWN) {
            if (strcmp(child->first_child->name, "write") == 0) {
                lock->type = DAV_LOCKTYPE_WRITE;
                continue;
            }
        }
        if (strcmp(child->name, "lockscope") == 0
            && child->first_child
            && lock->scope == DAV_LOCKSCOPE_UNKNOWN) {
            if (strcmp(child->first_child->name, "exclusive") == 0)
                lock->scope = DAV_LOCKSCOPE_EXCLUSIVE;
            else if (strcmp(child->first_child->name, "shared") == 0)
                lock->scope = DAV_LOCKSCOPE_SHARED;
            if (lock->scope != DAV_LOCKSCOPE_UNKNOWN)
                continue;
        }

        if (strcmp(child->name, "owner") == 0 && lock->owner == NULL) {
            const char *text;

            /* quote all the values in the <DAV:owner> element */
            apr_xml_quote_elem(p, child);

            /*
            ** Store a full <DAV:owner> element with namespace definitions
            ** and an xml:lang definition, if applicable.
            */
            apr_xml_to_text(p, child, APR_XML_X2T_FULL_NS_LANG, doc->namespaces,
                            NULL, &text, NULL);
            lock->owner = text;

            continue;
        }

        return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
                             apr_psprintf(p,
                                         "The server cannot satisfy the "
                                         "LOCK request due to an unknown XML "
                                         "element (\"%s\") within the "
                                         "DAV:lockinfo element.",
                                         child->name));
    }

    *lock_request = lock;
    return NULL;
}
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;

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

    if (ctx->is_liveprop) {
        err = (*priv->provider->patch_exec)(propdb->resource,
                                            ctx->prop, ctx->operation,
                                            ctx->liveprop_ctx,
                                            &ctx->rollback->liveprop);
    }
    else {
        dav_prop_name name;

        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;

        /* 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);
        }
    }

  error:
    /* push a more specific error here */
    if (err != NULL) {
        /*
        ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen
        ** any errors at this point.
        */
        ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
                                  DAV_ERR_PROP_EXEC,
                                  "Could not execute PROPPATCH.", err);
    }
}
static dav_error * dav_insert_coreprop(dav_propdb *propdb,
                                       int propid, const char *name,
                                       dav_prop_insert what,
                                       apr_text_header *phdr,
                                       dav_prop_insert *inserted)
{
    const char *value = NULL;
    dav_error *err;

    *inserted = DAV_PROP_INSERT_NOTDEF;

    /* fast-path the common case */
    if (propid == DAV_PROPID_CORE_UNKNOWN)
        return NULL;

    switch (propid) {

    case DAV_PROPID_CORE_lockdiscovery:
        if (propdb->lockdb != NULL) {
            dav_lock *locks;

            if ((err = dav_lock_query(propdb->lockdb, propdb->resource,
                                      &locks)) != NULL) {
                return dav_push_error(propdb->p, err->status, 0,
                                      "DAV:lockdiscovery could not be "
                                      "determined due to a problem fetching "
                                      "the locks for this resource.",
                                      err);
            }

            /* fast-path the no-locks case */
            if (locks == NULL) {
                value = "";
            }
            else {
                /*
                ** This may modify the buffer. value may point to
                ** wb_lock.pbuf or a string constant.
                */
                value = dav_lock_get_activelock(propdb->r, locks,
                                                &propdb->wb_lock);

                /* make a copy to isolate it from changes to wb_lock */
                value = apr_pstrdup(propdb->p, propdb->wb_lock.buf);
            }
        }
        break;

    case DAV_PROPID_CORE_supportedlock:
        if (propdb->lockdb != NULL) {
            value = (*propdb->lockdb->hooks->get_supportedlock)(propdb->resource);
        }
        break;

    case DAV_PROPID_CORE_getcontenttype:
        if (propdb->subreq == NULL) {
            dav_do_prop_subreq(propdb);
        }
        if (propdb->subreq->content_type != NULL) {
            value = propdb->subreq->content_type;
        }
        break;

    case DAV_PROPID_CORE_getcontentlanguage:
    {
        const char *lang;

        if (propdb->subreq == NULL) {
            dav_do_prop_subreq(propdb);
        }
        if ((lang = apr_table_get(propdb->subreq->headers_out,
                                 "Content-Language")) != NULL) {
            value = lang;
        }
        break;
    }

    default:
        /* fall through to interpret as a dead property */
        break;
    }

    /* if something was supplied, then insert it */
    if (value != NULL) {
        const char *s;

        if (what == DAV_PROP_INSERT_SUPPORTED) {
            /* use D: prefix to refer to the DAV: namespace URI,
             * and let the namespace attribute default to "DAV:"
             */
            s = apr_psprintf(propdb->p,
                            "<D:supported-live-property D:name=\"%s\"/>" DEBUG_CR,
                            name);
        }
        else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') {
            /* use D: prefix to refer to the DAV: namespace URI */
            s = apr_psprintf(propdb->p, "<D:%s>%s</D:%s>" DEBUG_CR,
                            name, value, name);
        }
        else {
            /* use D: prefix to refer to the DAV: namespace URI */
            s = apr_psprintf(propdb->p, "<D:%s/>" DEBUG_CR, name);
        }
        apr_text_append(propdb->p, phdr, s);

        *inserted = what;
    }

    return NULL;
}
/*
** dav_fs_save_lock_record:  Saves the lock information specified in the
**    direct and indirect lock lists about path into the lock database.
**    If direct and indirect == NULL, the key is removed.
*/
static dav_error * dav_fs_save_lock_record(dav_lockdb *lockdb, apr_datum_t key,
                                           dav_lock_discovery *direct,
                                           dav_lock_indirect *indirect)
{
    dav_error *err;
    apr_datum_t val = { 0 };
    char *ptr;
    dav_lock_discovery *dp = direct;
    dav_lock_indirect *ip = indirect;

#if DAV_DEBUG
    if (lockdb->ro) {
        return dav_new_error(lockdb->info->pool,
                             HTTP_INTERNAL_SERVER_ERROR, 0, 0,
                             "INTERNAL DESIGN ERROR: the lockdb was opened "
                             "readonly, but an attempt to save locks was "
                             "performed.");
    }
#endif

    if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
        /* ### add a higher-level error? */
        return err;
    }

    /* If nothing to save, delete key */
    if (dp == NULL && ip == NULL) {
        /* don't fail if the key is not present */
        /* ### but what about other errors? */
        (void) dav_dbm_delete(lockdb->info->db, key);
        return NULL;
    }

    while(dp) {
        val.dsize += dav_size_direct(dp);
        dp = dp->next;
    }
    while(ip) {
        val.dsize += dav_size_indirect(ip);
        ip = ip->next;
    }

    /* ### can this be apr_palloc() ? */
    /* ### hmmm.... investigate the use of a buffer here */
    ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize);
    dp  = direct;
    ip  = indirect;

    while(dp) {
        *ptr++ = DAV_LOCK_DIRECT;   /* Direct lock - lock_discovery struct follows */
        memcpy(ptr, dp, sizeof(dp->f));   /* Fixed portion of struct */
        ptr += sizeof(dp->f);
        memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken));
        ptr += sizeof(*dp->locktoken);
        if (dp->owner == NULL) {
            *ptr++ = '\0';
        }
        else {
            memcpy(ptr, dp->owner, strlen(dp->owner) + 1);
            ptr += strlen(dp->owner) + 1;
        }
        if (dp->auth_user == NULL) {
            *ptr++ = '\0';
        }
        else {
            memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
            ptr += strlen(dp->auth_user) + 1;
        }

        dp = dp->next;
    }

    while(ip) {
        *ptr++ = DAV_LOCK_INDIRECT;   /* Indirect lock prefix */
        memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken));   /* Locktoken */
        ptr += sizeof(*ip->locktoken);
        memcpy(ptr, &ip->timeout, sizeof(ip->timeout));   /* Expire time */
        ptr += sizeof(ip->timeout);
        memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize));   /* Size of key */
        ptr += sizeof(ip->key.dsize);
        memcpy(ptr, ip->key.dptr, ip->key.dsize);   /* Key data */
        ptr += ip->key.dsize;
        ip = ip->next;
    }

    if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) {
        /* ### more details? add an error_id? */
        return dav_push_error(lockdb->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_LOCK_SAVE_LOCK,
                              "Could not save lock information.",
                              err);
    }

    return NULL;
}
Exemple #10
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);
        }
    }
}