]> git.proxmox.com Git - pmg-api.git/blobdiff - PMG/LDAPConfig.pm
reload postfix instead of restart on config change
[pmg-api.git] / PMG / LDAPConfig.pm
index 9355d229218ef6db1e8aebc230f7835533fd7e43..9e4fd9e7e4a90083843f384644604eb0b8098fdf 100644 (file)
@@ -12,31 +12,72 @@ use PVE::SectionConfig;
 
 use base qw(PVE::SectionConfig);
 
+PVE::JSONSchema::register_format('ldap-simple-attr', \&verify_ldap_simple_attr);
+sub verify_ldap_simple_attr {
+    my ($attr, $noerr) = @_;
+
+    if ($attr =~ m/^[a-zA-Z0-9]+$/) {
+       return $attr;
+    }
+
+    die "value '$attr' does not look like a simple ldap attribute name\n" if !$noerr;
+
+    return undef;
+}
+
+my $inotify_file_id = 'pmg-ldap.conf';
+my $config_filename = '/etc/pmg/ldap.conf';
+
 my $defaultData = {
     propertyList => {
        type => { description => "Section type." },
-       section => {
-           description => "Secion ID.",
+       profile => {
+           description => "Profile ID.",
            type => 'string', format => 'pve-configid',
        },
     },
 };
 
+
 sub properties {
     return {
+       disable => {
+           description => "Flag to disable/deactivate the entry.",
+           type => 'boolean',
+           optional => 1,
+       },
+       comment => {
+           description => "Description.",
+           type => 'string',
+           optional => 1,
+           maxLength => 4096,
+       },
        mode => {
-           description => "LDAP protocol mode ('ldap' or 'ldaps').",
+           description => "LDAP protocol mode ('ldap', 'ldaps' or 'ldap+starttls').",
            type => 'string',
-           enum => ['ldap', 'ldaps'],
+           enum => ['ldap', 'ldaps', 'ldap+starttls'],
            default => 'ldap',
        },
+       verify => {
+           description => "Verify server certificate. Only useful with ldaps or ldap+starttls.",
+           type => 'boolean',
+           default => 0,
+           optional => 1,
+       },
+       cafile => {
+           description => "Path to CA file. Only useful with option 'verify'",
+           type => 'string',
+           optional => 1,
+       },
        server1 => {
            description => "Server address.",
            type => 'string', format => 'address',
+           maxLength => 256,
        },
        server2 => {
            description => "Fallback server address. Userd when the first server is not available.",
            type => 'string', format => 'address',
+           maxLength => 256,
        },
        port => {
            description => "Specify the port to connect to.",
@@ -66,21 +107,26 @@ sub properties {
        },
        accountattr => {
            description => "Account attribute name name.",
-           type => 'string',
-           pattern => '[a-zA-Z0-9]+',
-           default => 'sAMAccountName',
+           type => 'string', format => 'ldap-simple-attr-list',
+           default => 'sAMAccountName, uid',
        },
        mailattr => {
            description => "List of mail attribute names.",
-           type => 'string', format => 'string-list',
-           pattern => '[a-zA-Z0-9]+',
-           default => "mail, userPrincipalName, proxyAddresses, othermailbox",
+           type => 'string', format => 'ldap-simple-attr-list',
+           default => "mail, userPrincipalName, proxyAddresses, othermailbox, mailAlternativeAddress",
+       },
+       groupclass => {
+           description => "List of objectclasses for groups.",
+           type => 'string', format => 'ldap-simple-attr-list',
+           default => "group, univentionGroup, ipausergroup",
        },
     };
 }
 
 sub options {
     return {
+       disable => { optional => 1 },
+       comment => { optional => 1 },
        server1 => {  optional => 0 },
        server2 => {  optional => 1 },
        port => { optional => 1 },
@@ -92,6 +138,9 @@ sub options {
        filter => { optional => 1 },
        accountattr => { optional => 1 },
        mailattr => { optional => 1 },
+       groupclass => { optional => 1 },
+       verify => { optional => 1 },
+       cafile => { optional => 1 },
     };
 }
 
@@ -103,20 +152,68 @@ sub private {
     return $defaultData;
 }
 
-sub decode_value {
-    my ($class, $type, $key, $value) = @_;
+sub parse_section_header {
+    my ($class, $line) = @_;
 
-    $value = decode_base64($value) if $key eq 'bindpw';
+    if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+       my ($type, $profileId) = ($1, $2);
+       my $errmsg = undef; # set if you want to skip whole section
+       eval { PVE::JSONSchema::pve_verify_configid($profileId); };
+       $errmsg = $@ if $@;
+       my $config = {}; # to return additional attributes
+       return ($type, $profileId, $errmsg, $config);
+    }
+    return undef;
+}
 
-    return $value;
+sub parse_config {
+    my ($class, $filename, $raw) = @_;
+
+    my $cfg = $class->SUPER::parse_config($filename, $raw);
+
+    foreach my $profile (keys %{$cfg->{ids}}) {
+       my $data = $cfg->{ids}->{$profile};
+
+       $data->{comment} = PVE::Tools::decode_text($data->{comment})
+           if defined($data->{comment});
+
+       $data->{bindpw} = decode_base64($data->{bindpw})
+           if defined($data->{bindpw});
+    }
+
+    return $cfg;
 }
 
-sub encode_value {
-    my ($class, $type, $key, $value) = @_;
+sub write_config {
+    my ($class, $filename, $cfg) = @_;
+
+    foreach my $profile (keys %{$cfg->{ids}}) {
+       my $data = $cfg->{ids}->{$profile};
+
+       $data->{comment} = PVE::Tools::encode_text($data->{comment})
+           if defined($data->{comment});
+
+       $data->{bindpw} = encode_base64($data->{bindpw}, '')
+           if defined($data->{bindpw});
+    }
+
+    $class->SUPER::write_config($filename, $cfg);
+}
+
+sub new {
+    my ($type) = @_;
+
+    my $class = ref($type) || $type;
+
+    my $cfg = PVE::INotify::read_file($inotify_file_id);
+
+    return bless $cfg, $class;
+}
 
-    $value = encode_base64($value, '') if $key eq 'bindpw';
+sub write {
+    my ($self) = @_;
 
-    return $value;
+    PVE::INotify::write_file($inotify_file_id, $self);
 }
 
 my $lockfile = "/var/lock/pmgldapconfig.lck";
@@ -139,7 +236,7 @@ sub read_pmg_ldap_conf {
 
     local $/ = undef; # slurp mode
 
-    my $raw = <$fh>;
+    my $raw = defined($fh) ? <$fh> : '';
 
     return __PACKAGE__->parse_config($filename, $raw);
 }
@@ -149,14 +246,18 @@ sub write_pmg_ldap_conf {
 
     my $raw = __PACKAGE__->write_config($filename, $cfg);
 
-    chmod(0600, $fh);
+    my $gid = getgrnam('www-data');
+    chown(0, $gid, $fh);
+    chmod(0640, $fh);
 
     PVE::Tools::safe_print($filename, $fh, $raw);
 }
 
-PVE::INotify::register_file('pmg-ldap.conf', "/etc/proxmox/ldap.conf",
+PVE::INotify::register_file($inotify_file_id, $config_filename,
                            \&read_pmg_ldap_conf,
-                           \&write_pmg_ldap_conf);
+                           \&write_pmg_ldap_conf,
+                           undef,
+                           always_call_parser => 1);
 
 
 1;