Projects/Event Oriented Design

From K5Wiki
Jump to: navigation, search
This is an early stage project for MIT Kerberos. It is being fleshed out by its proponents. Feel free to help flesh out the details of this project. After the project is ready, it will be presented for review and approval.

This project page attempts to capture the outcome of discussions which have been held about rewriting parts of Kerberos to be event-oriented rather than thread-blocking (as is currently prevalent).


One motivation is to allow pluggable KDC extensions to make queries to slow services in order to process requests, without consuming many system resources. In an extreme case, a KDC might call a user's cell phone for confirmation of a request before honoring it--although slowness on that order would typically cause the client to retry and then give up.

Another motivation is to use existing logic in new ways. For instance, IAKERB requires client AS-REQ and TGS-REQ logic to be broken down into work units encompassing a single KDC response/request. Another example might be embedding the KDC request procesing code into a single-threaded, event-oriented architecture such as Samba.

Improving the performance of the existing KDC with the LDAP back end is a possible motivator, but is more easily accomplished in other ways such as Projects/Parallel_KDC.

Fundamental Issues

It is relatively straightforward to design an event-oriented model for a monolithic application. Typically there is a main select() or poll() loop and some way of registering callbacks for events on specific file descriptors or after a timeout or signal (in simple applications, this may be implicit in the design of global data structures). The main loop may be implemented by an external library such as glib, Qt, libevent, tevent (from Samba), or libdispatch (from Apple's Grand Central Dispatch). The application code is decomposed into non-blocking work units, with reach blocking operation registering a continuation work unit with the main loop.

The situation is more complicated once the application stops being monolithic. For example, if the KDC and KDB are made event-oriented, then the LDAP back end will need a way of connecting LDAP sockets and waiting for data to become available on them, and this must be mostly transparent to the application code (the KDC, or perhaps the consumer of some future libkdc) which is supposed to be independent of the KDB back end. If we provide our own event loop, or assume a specific external implementation, then we will not interoperate with any other event-oriented architecture; for example, if we use glib's event loop, then we would become more friendly with applications using glib but no more friendly to applications using Qt.

So far discussions of this issue have gravitated towards creating a pluggable event-loop interface with a default implementation.

In general it is simplest to assume that filesystem operations are "non-blocking" even though they may block (particularly against network filesystems), because operating system interfaces for doing non-blocking filesystem I/O are more difficult to use than interfaces for doing non-blocking socket I/O.

Specific Issues

There is no great async-friendly way of doing hostname resolution or DNS requests. The standard getaddrinfo() is thread-safe but not event-oriented. There are event-oriented DNS libraries such as c-ares which may be appropriate for DNS-specific operations such as SRV lookups, but are not necessarily appropriate for hostname lookup because they do not implement all of NSS (they assume DNS), and thus do not necessarily agree with the system hostname lookup functions. This is a possible motivation for being able to wrap blocking operations in threads or subprocesses to make them appear asynchronous. Similar issues may arise for other network libraries used by plugins.

API extensions will be required, both to allow applications to plug in the event loop implementation and to make blocking APIs event-oriented. For APIs we define, such as libkrb5, this is straightforward. For GSSAPI, it is likely that we will want to coordinate with the IETF.

Specific Areas of Code

IAKERB requires client AS-REQ and TGS-REQ code to be decomposed into work units with respect to KDC requests, but not with respect to other blocking operations. This has already been accomplished for the AS-REQ code path in 1.8, and is expected to be accomplished for the TGS-REQ code path for 1.9 as part of the IAKERB work. New APIs were created to allow applications to access the individual work units; these APIs will need to be revised again to make them async-friendly with respect to all blocking operations.

AS-REQ and TGS-REQ processing can make DNS requests in the course of determining a host-to-realm mapping (although these requests are generally considered a misfeature) or locating a KDC. The KDC generally should not need to make DNS requests, but may currently be doing so for host-realm referrals (if so, that's probably a bug).

Client AS-REQ and TGS-REQ code may block in order to access credential caches, if the ccache is implemented through an IPC interface (such as CCAPI).

AS-REQ processing may make blocking calls to the prompter, either directly or via a preauth plugin.

The k5crypto library may conceivably block if either crypto or PRNG operations are implemented via an external processing unit. It is probably simplest to pretend that crypto operations are non-blocking, however. krb5_c_random_os_entropy can block if called with strong_random set to true and the /dev/random pool is empty, but calls with strong_random set to true are fortunately rare.

The KDC could be made async-friendly to allow plugins to make blocking operations. This would require redesigning the DAL (only the parts used by the KDC), the authdata plugin framework, and the KDC side of the preauth plugin framework to allow plugin operations to take place asynchronously, and would also require the core KDC code to be decomposed into non-blocking work units (where essentially every plugin invocation is assumed to be blocking). It is probably best to work from the outside in--that is, rewrite the KDC code in terms of work units, then redesign plugin interfaces to allow non-blocking operation, then rewrite existing plugins for those interfaces (particular the LDAP KDB back end) to be event-oriented instead of blocking.