[Kroupware] Web interface frontend

Lutz Badenheuer kroupware@mail.kde.org
Tue, 1 Oct 2002 19:21:15 +0200


Hi Tassilo, 

Am Dienstag, 1. Oktober 2002 10:53 schrieb Tassilo Erlewein:
> sorry for my late answer. I find your ldap postfix findings quite
> useful. We think heavily about getting the whole server config into
> a special access-restricted LDAP object.
> However I'm not so sure it's generally good to have the daemons
> get their running config directly from LDAP (where possible)
> So I would propose the following:
>
> - have the web interface only interact with ldap
> - provide a backend (perl) that reads stuff from ldap and
>   fills out config file templates

That would make administration a lot easier. The e-smith server 
developers use Perl's Text::Template for this task, but recieve  
their config data from MySQL, this works really well. In the long 
term, this is obviously a _very_ good idea, enhancing clustering 
administration of our server greatly. 

On the other hand, I'd like to ask whether it is really *needed* to 
put configuration data into LDAP at this time. Postfix' configuration 
is, once set up, not subject to further changes, as well as Cyrus -- 
or did I possibly forget something? I can't say anything about 
ProFTP, but that is, according to Martin, only a requirement for 
Outlook2000 -- OL's newer versions use WebDAV. IIRC, Perl's Net::IMAP 
modules are able to manage IMAP shared folders in conjunction with 
cyrus, so for now, we should first get the account data into LDAP. 

But, on the other hand, it would be VERY useful to input server's 
configuration into LDAP and have an interface to it that outputs all 
needed config files to a special place [1], whether it may be for the 
first installation or for maintenance purposes. But it is also in my 
opinion, that at this time, it is not the right moment to think about 
the distribution and installation of newly generated files -- the 
schedule of this project seems too tight for that. :) 

[1] Eg. /usr/share/Kolab/<machine>/<service>/<path>/<file>, for 
Postfix this would be
  /usr/share/Kolab/host1.example.org/Postfix/etc/postfix/main.cf 
and 
  /usr/share/Kolab/host1.example.org/Postfix/etc/postfix/master.cf 
respectively. 

> Note that it's possible to arrange for special settings in the
> config file templates that don't get overwritten by the backend. So
> it would be possible for you to have postfix fetch whatever it
> supports directly from ldap.

I'd prefer to read a config from LDAP, storing config data into a 
Perl hash which has the names of the configuration variables as keys. 
Then, parse a local "override" file. I'll give a short example: 

--snip-----
dn: cn=ldap1, dc=example, dc=com
cn: ldap1
virtual_maps: ldap:myLDAPtag
[rest of configuration]
objectclass: ConfigLdapPostfix
--snap-----

would result in the same perl hash as constructed with

--snip-----
my %cfg = (
	dn           => 'cn=ldap1, dc=example, dc=com', 
	cn           => 'ldap1', 
	virtual_maps => ldap:myLDAPtag
	objectclass  => ConfigLdapPostfix
); 
--snap-----

This is, after the LDAP query is finished, kept in memory. Then, the 
"override" file is opened (^variable = value$, one per line like in 
Postfix itself), simply parsed by 

--snip-----
while(<OVERRIDE>) {
    s/#.*//g;
    if(m/([a-zA-Z0-9]+) ?= ?(.+)) {
        $cfg{$1} = $2;
    }
}
--snap-----

So, when reading the local file with the loop seen above, everything 
in there overrides LDAP config BEFORE you start reading the config 
file's template. 

> My understanding is, that requires we stay postfix conformant with
> regard to the ldap config object. So what you point out here could
> be very useful. Please let me know further requirements like this,
> if you like. 

Postfix' lookup tables have one limitation: a lookup can only return 
one value per key. This can perfectly be represented within ldap.

But, on the other hand, there are security indications: we would need 
root privileges to write config files, and then the same to reload 
those daemons of which the config has changed. So, I propose to think 
about distribution and installation of automatically generated 
configuration files later; for now, every moderately competent 
sysadmin should well be able to do this on his own. Later, we'll 
maybe provide some sort of agent software for the machines, rsyncing 
the generated config files to their final destinations and restarting 
the appropriate service. Maybe we should implement that in version 
2.0 or so... :) 

The easiest method to achieve this would be to insert all possible 
config directives that postfix has into an LDAP schema, and then have 
a Perl script dump all of the config into a configuration file. Using 
this method, admins of large server farms are able to add a server by 
cloning the config of one server by, for example, using gq's 
'New->use current entry' method and just replacing host names and the 
like. 

And, there is another problem with this approach: some things in 
Postfix' main.cf are not really perfect for use with LDAP. In LDAP, I 
have to use attribute names, which I can "invent" when configuring a 
Postfix machine: for example, let's have a look at virtual_maps 
configured for LDAP: 

--snip main.cf-----
virtual_maps = ldap:ldapsource
ldapsource_server_host = localhost
ldapsource_server_port = 636
ldapsource_search_base = dc=example, dc=com
--snap-----

So, "virtual_maps" is a valid name of a configuration variable in 
Postfix and is known to configuration. "ldapsource_.*" variables are 
dynamically created when Postfix sees that "ldap:ldapsource" value in 
virtual_maps. So, there should be a mechanism to put store those. 
This could be done by an objectclass like 

--snip-----
objectclass PostfixMap
  reqired
    objectclass
    maptag         // single-value
  allowed
    text
--snap-----

so that 

--snip-----
dn: cn=ldap1, dc=example, dc=com
cn: ldap1
virtual_maps: ldap:myLDAPtag
[rest of configuration]
objectclass: ConfigLdapPostfix

dn: cn=myLDAPtag, dc=example, dc=com
cn: myLDAPtag
maptag: myLDAPtag
father_dn: dn=ldap1, dc=example, dc=com
text: ldapsource_server_host = localhost
text: ldapsource_server_port = 636
text: ldapsource_search_base = dc=example, dc=com
objectclass: ldapmap
--snap-----

Just some thoughts, don't expect this to be perfect -- it has well to 
be thought and worked over, but could be used as a starting point. 

Kind regards, 
Lutz 

-- 
Lutz Badenheuer     | IT--Consulting, Development, Networksolutions
luke@the-web-ac.com | C/C++, OO-Perl, sh | Linux, SCO UNIX, Solaris