More work on access control page
authorJamie Cameron <jcameron@webmin.com>
Sun, 16 Dec 2007 22:17:02 +0000 (22:17 +0000)
committerJamie Cameron <jcameron@webmin.com>
Sun, 16 Dec 2007 22:17:02 +0000 (22:17 +0000)
ldap-server/acl_form.cgi
ldap-server/acl_save.cgi [new file with mode: 0644]
ldap-server/lang/en
ldap-server/ldap-server-lib.pl

index 4b72b19..5308e5a 100644 (file)
@@ -22,6 +22,8 @@ else {
 
 # Form header
 print &ui_form_start("acl_save.cgi", "post");
+print &ui_hidden("new", $in{'new'});
+print &ui_hidden("idx", $in{'idx'});
 print &ui_table_start($text{'eacl_header'}, undef, 2);
 
 # Granting to what object
@@ -46,7 +48,50 @@ print &ui_table_row($text{'eacl_what'},
        &ui_textbox("attrs", $p->{'attrs'}, 40) );
 
 # Access rights table
-# XXX
+@tds = ( "width=40% nowrap", "width=30%", "width=30%" );
+$wtable = &ui_columns_start([ $text{'eacl_who'},
+                             $text{'eacl_access'},
+                             $text{'eacl_control'} ], 100, 0, \@tds);
+$i = 0;
+foreach $b (@{$p->{'by'}}, { }, { }, { }) {
+       $kwho = $b->{'who'} eq 'self' || $b->{'who'} eq 'users' ||
+               $b->{'who'} eq 'anonymous' || $b->{'who'} eq '*' ||
+               $b->{'who'} eq '';
+       $kacc = !$b->{'access'} ? 'read' :
+               &indexof($b->{'access'}, @acl_access_levels) >= 0 ?
+                       $b->{'access'} : undef;
+       $wtable .= &ui_columns_row([
+               # Who are we granting?
+               &ui_select("wmode_$i",
+                          $kwho ? $b->{'who'} : 'other',
+                          [ [ '', "&nbsp;" ],
+                            [ '*', $text{'eacl_every'} ],
+                            [ 'self', $text{'eacl_self'} ],
+                            [ 'users', $text{'eacl_users'} ],
+                            [ 'anonymous', $text{'eacl_anonymous'} ],
+                            [ 'other', $text{'eacl_other'} ] ],
+                          1, 0, 0, 0,
+                          "style='width:45%' onChange='form.who_$i.disabled = (form.wmode_$i.value != \"other\")'").
+               &ui_textbox("who_$i", $kwho ? "" : $b->{'who'}, 30,
+                           $kwho, undef, "style='width:45%'"),
+
+               # What access level? Show textbox if complex
+               $kacc ? &ui_select("access_$i", $kacc,
+                                  [ map { [ $_, $text{'access_l'.$_} ] }
+                                        @acl_access_levels ], 1, 0, 0, 0,
+                                  "style='width:90%'")
+                     : &ui_textbox("access_$i", $b->{'access'}, 20,
+                                   0, undef, "style='width:90%'"),
+
+               # Additional attrs
+               &ui_textbox("control_$i", join(" ", @{$b->{'control'}}), 30,
+                           0, undef, "style='width:90%'"),
+               ], \@tds);
+       # XXX http://www.openldap.org/faq/data/cache/452.html
+       $i++;
+       }
+$wtable .= &ui_columns_end();
+print &ui_table_row(undef, $wtable, 2);
 
 # Form and page end
 print &ui_table_end();
diff --git a/ldap-server/acl_save.cgi b/ldap-server/acl_save.cgi
new file mode 100644 (file)
index 0000000..f626d16
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/local/bin/perl
+# Create, update or delete one access control rule
+
+require './ldap-server-lib.pl';
+&error_setup($text{'eacl_err'});
+&local_ldap_server() == 1 || &error($text{'slapd_elocal'});
+$access{'acl'} || &error($text{'acl_ecannot'});
+&ReadParse();
+
+# Get the current rule
+&lock_file($config{'config_file'});
+$conf = &get_config();
+@access = &find("access", $conf);
+if (!$in{'new'}) {
+       $acl = $access[$in{'idx'}];
+       $p = &parse_ldap_access($acl);
+       }
+
+if ($in{'delete'}) {
+       # Just take out of access list
+       @access = grep { $_ me $acl } @access;
+       }
+else {
+       # Validate and store inputs, starting with object
+       if ($in{'what'} == 0) {
+               $p->{'what'} = '*';
+               }
+       else {
+               $in{'dn'} =~ /^\S+=\S+$/ || &error($text{'eacl_edn'});
+               $p->{'what'} = 'dn='.($in{'style'} ? '.'.$in{'style'} : '').
+                              $in{'dn'};
+               }
+
+       # Object filter and attribute list
+       delete($p->{'filter'});
+       if ($in{'filter_on'}) {
+               $in{'filter'} =~ /^\S+$/ || &error($text{'eacl_efilter'});
+               $p->{'filter'} = $in{'filter'};
+               }
+       delete($p->{'attrs'});
+       if ($in{'attrs_on'}) {
+               $in{'attrs'} =~ /^\S+$/ || &error($text{'eacl_eattrs'});
+               $p->{'attrs'} = $in{'attrs'};
+               }
+
+       # Each granted user
+       # XXX
+
+       # Add to access directive list
+       if ($in{'new'}) {
+               $acl = { 'name' => 'access',
+                        'values' => [ ] };
+               push(@access);
+               }
+       &store_ldap_access($acl, $p);
+       }
+
+# Write out access directives
+&save_directive($conf, "access", @access);
+&flush_file_lines($config{'config_file'});
+&unlock_file($config{'config_file'});
+
+# Log and return
+&webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "modify",
+           "access", $p->{'who'});
+&redirect("edit_acl.cgi");
+
index f657573..35c2f54 100644 (file)
@@ -100,6 +100,7 @@ acl_move=Move
 acl_none=No access control rules have been defined yet. All objects in the LDAP database will be readable by all users.
 acl_delete=Delete Selected Rules
 acl_add=Add a new access control rule.
+acl_return=access control rules
 
 browser_title=Browse Database
 browser_econn=The LDAP browser cannot be used : $1
@@ -261,16 +262,25 @@ access_desc=$2 by $1
 access_self=self
 access_users=authenticated users
 access_anon=anonymous users
+access_none=no access
+access_auth=authenticate
+access_compare=compare
+access_search=search
 access_read=read
 access_write=write
-access_auth=authenticate
 access_all=anyone
 access_any=All objects
+access_lnone=No access
+access_lauth=Authenticate
+access_lcompare=Compare
+access_lsearch=Search
+access_lread=Read
+access_lwrite=Write
 
 eacl_title1=Create Access Control Rule
 eacl_title2=Edit Access Control Rule
 eacl_header=LDAP database access control rule details
-eacl_what=Granting access to
+eacl_what=Objects being granted
 eacl_what1=All objects
 eacl_what0=Object with DN
 eacl_mtype=match type
@@ -281,3 +291,16 @@ eacl_subtree=entire subtree
 eacl_children=only children
 eacl_filter=Limit with object filter :
 eacl_attrs=Limit to listed attributes :
+eacl_who=Grant access to
+eacl_access=Access level
+eacl_control=Advanced options
+eacl_self=Self
+eacl_users=Authenticated users
+eacl_anonymous=Anonymous clients
+eacl_other=Other DN..
+eacl_every=Everyone
+eacl_err=Failed to save access control rule
+eacl_edn=Missing or invalid DN - should be like <tt>uid=joe,dc=my-domain,dc=com</tt>
+eacl_efilter=Missing or invalid filter - should be like <tt>(objectClass=posixAccount)</tt>
+eacl_eattrs=Missing or invalid comma-separated list of attributes
+
index ad0231a..a1f5bf8 100644 (file)
@@ -12,6 +12,7 @@ if ($@) { $net_ldap_error = $@; }
 
 @search_attrs = ( 'objectClass', 'cn', 'dn', 'uid' );
 @acl_dn_styles = ( 'regex', 'base', 'one', 'subtree', 'children' );
+@acl_access_levels = ( 'none', 'auth', 'compare', 'search', 'read', 'write' );
 
 # connect_ldap_db()
 # Attempts to connect to an LDAP server. Returns a handle on success or an
@@ -190,7 +191,7 @@ local @rv = map { $_->{'values'}->[0] } &find(@_);
 return wantarray ? @rv : $rv[0];
 }
 
-# save_directive(&config, name, value, ...)
+# save_directive(&config, name, value|&values|&directive, ...)
 # Update the value(s) of some entry in the config file
 sub save_directive
 {
@@ -202,8 +203,11 @@ local $changed;
 for(my $i=0; $i<@old || $i<@values; $i++) {
        local ($line, @unqvalues, @qvalues);
        if (defined($values[$i])) {
-               @unqvalues = ref($values[$i]) ? @{$values[$i]}
-                                             : ( $values[$i] );
+               @unqvalues = ref($values[$i]) eq 'ARRAY' ?
+                               @{$values[$i]} :
+                            ref($values[$i]) eq 'HASH' ?
+                               @{$values[$i]->{'values'}} :
+                               ( $values[$i] );
                @qvalues = map { /^[^'" ]+$/ ? $_ :
                                 /"/ ? "'$_'" : "\"$_\"" } @unqvalues;
                $line = join(" ", $name, @qvalues);
@@ -427,8 +431,8 @@ while(@v) {
        shift(@v);              # Remove by
        local $by = { 'who' => shift(@v),
                      'access' => shift(@v) };
-       if (@v && $v[0] ne 'by') {
-               $by->{'control'} = shift(@v);
+       while(@v && $v[0] ne 'by') {
+               push(@{$by->{'control'}}, shift(@v));
                }
        local $whodesc = $by->{'who'} eq 'self' ? $text{'access_self'} :
                         $by->{'who'} eq 'users' ? $text{'access_users'} :
@@ -451,5 +455,27 @@ else {
 return $p;
 }
 
+# store_ldap_access(&directive, &acl-struct)
+# Updates the values of a directive from an ACL structure
+sub store_ldap_access
+{
+local ($a, $p) = @_;
+local @v = ( 'to' );
+push(@v, $p->{'what'});
+if ($p->{'filter'}) {
+       push(@v, "filter=$p->{'filter'}");
+       }
+if ($p->{'attrs'}) {
+       push(@v, "attrs=$p->{'attrs'}");
+       }
+foreach my $b (@{$p->{'by'}}) {
+       push(@v, "by");
+       push(@v, $b->{'who'});
+       push(@v, $b->{'access'});
+       push(@v, @{$b->{'control'}});
+       }
+$a->{'values'} = \@v;
+}
+
 1;