KCALDAV(8)

NAME
kcaldav - simple CalDAV server

SYNOPSIS
kcaldav

DESCRIPTION
The kcaldav CGI program minimally implements CalDAV, with an emphasis on strong authorisation and simplicity. To use kcaldav, you'll need to first install a calendar database in the compile-time root directory /caldav with kcaldav.passwd(1). The root directory is relative to the CGI script's file-system root.

Once installed, you can point your calendar client to owned collections or the calendar home (depending on the client) within the calendar root.

For example, assume the script has been installed into /var/www/cgi-bin and is reachable at

    https://localhost/cgi-bin/kcaldav

Moreover, assume your calendar root /caldav is based in the web server's chroot(2) in /var/www. It contains a kcaldav.db created by kcaldav.passwd(1) specifying a single principal kristaps having a single calendar collection calendar. This can be created with

    # kcaldav.passwd -C -u kristaps

If your CalDAV client supports the calendar-home-set feature, you can point it to the principal URL:

    http://localhost/cgi-bin/kcaldav/kristaps/

If the calendar-home-set feature is not supported by your client (e.g., with Thunderbird), you may need to point directly to the managed calendar:

    http://localhost/cgi-bin/kcaldav/kristaps/calendar/

A simpler setup might occur all in one directory, such as fully installing into the user directory, public_html, of a given user. Here I assume that the directory has CGI-execute permissions set and the CGI script kcaldav.cgi and its database installed into /home/foo/public_html.

The user can then access calenders on

    http://localhost/~foo/kcaldav.cgi/kristaps/

In either case, please use HTTPS! Although kcaldav uses HTTP authentication to the fullest, that still doesn't protect you from snooping.

  System-Wide Calendar Administration
Let the root directory be /caldav, a directory within the CGI script's chroot(2) file-system, which is read-writable by the CGI script running as user www. Let the dummy user kcaldav be the owner of kcaldav files. First make kcaldav.passwd(1) set-user-ID for modifying the file.

    # chown kcaldav /usr/local/bin/kcaldav.passwd
    # chmod u+s /usr/local/bin/kcaldav.passwd

Create user principals as follows:

    # kcaldav.passwd -f /caldav -C -u user1
    # kcaldav.passwd -f /caldav -C -u user2
    # ...

Now any local user can modify her principal's password without administrator intervention.

    user1% kcaldav.passwd -f /caldav

  Local Calendar Administration
Let the root directory be /home/foo/caldav, which is readable by the web server running as user www and read-writable by the logged-in user foo. First, create the database and add principals as necessary.

    % kcaldav.passwd -C -u foo -f /home/foo/caldav

  Web Calendar Administration
kcaldav has built-in support for web-based administration by logged-in (using HTTP authentication) principals through a web application of HTML5, JavaScript, and CSS pages using kcaldav as a JSON backend. Let's assume these page have been installed into /var/www/htdocs/kcaldav. Principals can then access the server root,

    http://localhost/kcaldav/home.html

to see their configuration.

The principal foo can modify collection information online. Note: you will need to make sure that the calendar database is read-writable by the web server. In general, the directory containing the database will also need to be writable by the web server for creating its temporary transaction files.

HTTP METHODS
In this section, I describe each HTTP method supported.

  DELETE
The DELETE method is handled according to RFC 4918. Principals must have DELETE access. Resource deletions process the “If-Match” header, if applied, for conditional deletion.

Collection deletions begin by removing the kcaldav.conf file, which renders the directory opaque to kcaldav. Following that, all files are removed followed by the directory itself. Note: it is possible to remove the principal's home URL!

  GET
The GET method is supported for calendar resources (defined by content-type) as defined by RFC 4918. The “If-None-Match” header is processed and checks the file etag (MD5 sum). In all cases, the principal must have been delegated read access.

For the JSON content-type (i.e., web application resources), kcaldav routes into a management framework. Only the index.html resource in the server root directory is supported. Requests for the empty root (“\”) are aliased to index.html.

  POST
The POST method is supported only for text/html requests for specific management (JSON content-type) resources. POST methods on calendar collections are interpreted by the management framework as JSON form requests to change collection properties. The principal must have been delegated write access.

  PROPFIND
The PROPFIND method queries collection or resource properties. The principal must have been delegated read access. It accepts the “Depth” header for recursive reports. The following is a table of get-able properties.

calendar-color | Apple extension
calendar-data | RFC 4791, 9.6
calendar-description | RFC 4791, 5.2.1
calendar-home-set | RFC 4791, 6.2.1
calendar-proxy-read-for | caldav-proxy.txt, 5.3.1
calendar-proxy-write-for | caldav-proxy.txt, 5.3.2
calendar-timezone | RFC 4791, 5.2.2
calendar-user-address-set | RFC 6638, 2.4.1
current-user-principal | RFC 5379, 3
current-user-privilege-set | RFC 3744, 5.4
displayname | RFC 4918, 15.2
getcontenttype | RFC 4918, 15.5
getctag | caldav-ctag-02, 4.1
getetag | RFC 4918, 15.6
group-member-set | RFC 3744, 4.3; caldav-proxy.txt
group-membership | RFC 3744, 4.4; caldav-proxy.txt
min-date-time | RFC 4791, 5.2.6
owner | RFC 4918, 14.17
principal-URL | RFC 3744, 4.2
quota-available-bytes | RFC 4331, 3
quota-used-bytes | RFC 4331, 4
resourcetype | RFC 4918, 15.9
schedule-calendar-transp | RFC 6638, 9.1
supported-calendar-component-set | RFC 4791, 5.2.3
supported-calendar-data | RFC 4791, 9.6

  PROPPATCH
If the web server has write access to collection kcaldav.conf files and the principal has been delegated write access, its properties may be modified. The following is a table of settable properties.

calendar-colour | Apple extension
calendar-description | RFC 4791, 5.2.1
displayname | RFC 4918, 15.2

  PUT
The PUT method is supported for calendar resources where the principal has been delegated write access.

The “If-Match” and “If” headers are both accepted to check against etags (MD5 sums) and conditionally replace resources.

  REPORT
The REPORT method is handled similarly to PROPFIND. It accepts the “Depth” header for recursive reports.

IMPLEMENTATION NOTES
The kcaldav system is fairly complicated, though as simple as it can be. It focusses on safety and security throughout. In this section, I describe several important topics regarding implementation.

  Authentication
kcaldav requires HTTP “QOP” digest authentication. A nonce database kcaldav.nonce.db is maintained in the root calendar directory, consisting of nonce values and their current nonce counts. The kcaldav.nonce.db file is bound in size, with requests for new nonces evicting the oldest request. The use of nonces and nonce counts guarantees that principals are not subject to replay attacks. Nonces are 16-bytes of random data from arc4random_buf(3).

To protect against attackers starving the nonce database by endlessly requesting nonces (evicting valid nonces), kcaldav uses a series of checks.

When a client first accesses the system (without authentication), it is given a random, unrecorded nonce.

When the client re-authenticates using the random nonce and principal credentials, the system first checks that the user is valid. The nonce is then checked in the database. If it is not found (the case for principals re-authenticating with the random nonce), authentication is requested again with the “stale” directive and a new nonce entry in the database. Replay nonces request a full re-authentication. This step ensures that the principal is valid, though it could be a replay attack from a nonce entry since evicted.

Finally, the client re-authenticates with the recorded nonce and is able to access the system.

The remaining attack is for an adversary to build up a database of known historical responses and replay them all at once.

  Date and Time
Well-defined calendar date and time is required for computing ranges of free-busy, multiget filters, and so on. kcaldav parses valid RFC 2445 (iCalendar) calendar dates fully, encompassing arbitrary repeat-rules and so on. Parsing UTC time-stamps is well-defined using the formula from the “Single Unix Specification” section 15 on “Seconds since epoch”. Parsing embedded time-zone time-stamps is far more complicated, but fully supported as defined by RFC 2445 using both the SUS algorithm and Zeller's congruence to compute time components. Other CalDAV implementations make use of tzfile(5) databases: since kcaldav assumes it is in a chroot(2) and that this database is unavailable, it parses all time-zone definitions directly.

One of the most complex components of RFC 2445 is the repeat-rule, such as that used for time-zone daylight and standard sub-component definitions. kcaldav enumerates over all possible repeat-rule instances, and is thus able to accomodate for arbitrarily-complicated repeat rules.

SEE ALSO
kcaldav.passwd(1)

STANDARDS
The kcaldav utility minimally implements RFC 4918 (WebDAV), RFC 4791 (CalDAV), and of course RFC 2616 (HTTP). It also implements the following extensions:

caldav-ctag-02
    The “ctag” Calendar Server Extension.

caldav-proxy.txt
    Read-write delegation support.

RFC 2617
    “Digest” authentication of all users.

RFC 3744
    ACL queries on the authenticated principal (not ACEs).

RFC 4331
    Available and used bytes in the collection file-system via fstatfs(2).

RFC 5397
    The current principal address.

RFC 7232
    Conditional HTTP responses (etag, “If-Match”, etc.).