Greetings!
I'm planning to implement a new auth driver. It's going to be, in concept, similar to the Lua and CheckPassword drivers, in that it allows an user program to carry out the authentication and user enumeration steps. The rationale is that such a solution would provide better decoupling between Dovecot and the user authentication and enumeration logic. Existing integrated logic (auth/ directory in the source tree) is, even encompassing a great number of common use cases, ultimately inflexible. Writing custom drivers implementing logic, while being a solution to the inflexibility problem, is clearly not what drivers were engineered for: for one they don't support dynamic loading, making it necessary to recompile Dovecot to make changes, which is unacceptable in many situations, e.g. when using a packaged or containerized version of the software. In this email, I intend to explain what characteristics my driver will have and why it solves the proposed problem better than existing code (such as CheckPassword, Lua and proxy), in the hope to get useful feedback and I will pose some technical questions to which I could not find definitive answers by myself yet.
These are going to be the characteristics of my driver (with particular emphasis to the differences to the existing drivers):
- It is going to be a completely generic mechanism exposing all funcionality of Dovecot's interface, both password check and enumeration, and will fully support authentication methods with continuations.
- It is going to be performant, communicating with external programs through sockets (unix or inet).
- It is going to communicate using a simple, dynamic-schema, well-understood protocol, which is probably going to be JSON, being very easy to generate and parse.
This is why the existing drivers do not already provide what I described:
- CheckPassword is heavy (fork & 2*exec), and it's generally a mess, having initially been provided as a compatibility feature and having then been hacked to support additional functionality; it's architecturally unfeasable to support continuations with it and anyway any further extension will probably make it explode :)
- Lua works but it's limited, in that it dictates a language and also dictates that the auth logic should run on the same server as Dovecot (and under Dovecot's control). It also doesn't seem to support plain password checks, but only user-password enumeration, making it non-generic (at least this is what can be inferred from the documentation and examples.)
- Other possible solutions, such as (mis)using the proxy driver to communicate with an external program are not well documented and nothing guarantees the proxy protocol will not change anyway, being an internal feature.
And now, the technical questions. I know these could be answered by reading the code, which is something I'm doing, but I'm finding some architectural details quite difficult to grasp due to their complexity:
- From what I gather from [1], auth-worker processes only process a single request before being killed from auth. Would setting service_count to something different cause auth-workers to be reused or would it just leak the auth-workers? In the first case, is the preinit of the auth driver repeated, or is the existing instance of the auth driver reused? You could also point me to the relevant code sections which start, keep track of and initialize auth-workers.
- How does a driver specify what to run in an auth-worker as opposed to in the auth process? (This is strongly related to the first question, and maybe it is more general, so you may want to answer this one first.)
Please, feel free to only answer parts of my email. Any input on any of the matters is very welcome.
Best regards, Riccardo P. Bestetti