Start of work on LDAP support
authorJamie Cameron <jcameron@webmin.com>
Wed, 15 Sep 2010 00:45:11 +0000 (17:45 -0700)
committerJamie Cameron <jcameron@webmin.com>
Wed, 15 Sep 2010 00:45:11 +0000 (17:45 -0700)
acl/acl-lib.pl
acl/edit_sql.cgi
acl/lang/en
acl/save_sql.cgi
lang/en
web-lib-funcs.pl

index 74edf68..7ab90e1 100755 (executable)
@@ -96,9 +96,7 @@ close(PWFILE);
 
 # If a user DB is enabled, get users from it too
 if ($miniserv{'userdb'}) {
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to user database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Fetch users with SQL
@@ -175,9 +173,7 @@ close(GROUPS);
 
 # If a user DB is enabled, get groups from it too
 if ($miniserv{'userdb'}) {
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to group database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Fetch groups with SQL
@@ -261,9 +257,7 @@ my @mods = &list_modules();
 
 if ($miniserv{'userdb'} && !$miniserv{'userdb_addto'}) {
        # Adding to user database
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
         &error("Failed to connect to user database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Add user with SQL
@@ -393,9 +387,7 @@ local $_;
 
 if ($user{'proto'}) {
        # In users and groups DB
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to user database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Get old password, for change detection
@@ -657,9 +649,7 @@ if ($miniserv{'session'}) {
 
 if ($miniserv{'userdb'}) {
        # Also delete from user database
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to user database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Find the user with SQL query
@@ -724,9 +714,7 @@ my %miniserv;
 
 if ($miniserv{'userdb'} && !$miniserv{'userdb_addto'}) {
        # Adding to group database
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
         &error("Failed to connect to group database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Add group with SQL
@@ -793,9 +781,7 @@ my %miniserv;
 
 if ($group{'proto'}) {
        # In users and groups DB
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to group database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Update primary details
@@ -876,9 +862,7 @@ local $lref = &read_file_lines("$config_directory/webmin.groups");
 
 if ($miniserv{'userdb'}) {
        # Also delete from group database
-       my ($proto, $user, $pass, $host, $prefix, $args) =
-               &split_userdb_string($miniserv{'userdb'});
-       my $dbh = &connect_userdb($miniserv{'userdb'});
+       my ($dbh, $proto) = &connect_userdb($miniserv{'userdb'});
        &error("Failed to connect to group database : $dbh") if (!ref($dbh));
        if ($proto eq "mysql" || $proto eq "postgresql") {
                # Find the group with SQL query
@@ -1701,7 +1685,32 @@ if ($proto eq "mysql" || $proto eq "postgresql") {
        return undef;
        }
 elsif ($proto eq "ldap") {
-       # XXX
+       # Load LDAP module
+       eval 'use Net::LDAP;';
+       return &text('sql_emod', 'Net::LDAP') if ($@);
+
+       # Try to connect
+       my $dbh = &connect_userdb($str);
+       ref($dbh) || return $dbh;
+
+       # Check that base DN exists
+       if (!$notablecheck) {
+               my $superprefix = $prefix;
+               $superprefix =~ s/^[^,]+,//;    # Make parent DN
+               my $rv = $dbh->search(base => $superprefix,
+                                     scope => 'one');
+               my $niceprefix = lc($prefix);
+               $niceprefix =~ s/\s//g;
+               my $found = 0;
+               foreach my $d ($rv->all_entries) {
+                       my $niced = lc($d->dn());
+                       $niced =~ s/\s//g;
+                       $found++ if ($niced eq $niceprefix);
+                       }
+               $found || return &text('sql_eldapdn', $prefix);
+               }
+       &disconnect_userdb($str, $dbh);
+       return undef;
        }
 else {
        return "Unknown user database type $proto";
index 3e6b6d5..5c51771 100755 (executable)
@@ -49,6 +49,13 @@ $postgresqlgrid = &ui_grid_table(\@postgresqlgrid, 2, 100);
 push(@ldapgrid,
      $text{'sql_host'},
      &ui_textbox("ldap_host", $proto eq "ldap" ? $host : "", 30));
+push(@ldapgrid,
+     $text{'sql_ssl'},
+     &ui_radio("ldap_ssl", $args->{'scheme'} eq 'ldaps' ? 1 :
+                          $args->{'tls'} ? 2 : 0,
+              [ [ 0, $text{'sql_ssl0'} ],
+                [ 1, $text{'sql_ssl1'} ],
+                [ 2, $text{'sql_ssl2'} ] ]));
 push(@ldapgrid,
      $text{'sql_user'},
      &ui_textbox("ldap_user", $proto eq "ldap" ? $user : "", 30));
@@ -58,7 +65,14 @@ push(@ldapgrid,
 push(@ldapgrid,
      $text{'sql_prefix'},
      &ui_textbox("ldap_prefix", $proto eq "ldap" ? $prefix : "", 30));
-# XXX object classes?
+push(@ldapgrid,
+     $text{'sql_userclass'},
+     &ui_textbox("ldap_userclass", $proto eq "ldap" && $args->{'userclass'} ?
+                                    $args->{'userclass'} : "webminUser", 30));
+push(@ldapgrid,
+     $text{'sql_groupclass'},
+     &ui_textbox("ldap_groupclass", $proto eq "ldap" && $args->{'groupclass'} ?
+                                    $args->{'groupclass'} : "webminGroup",30));
 $ldapgrid = &ui_grid_table(\@ldapgrid, 2, 100);
 
 print &ui_table_row(undef,
index fcf3bfb..c084361 100644 (file)
@@ -393,6 +393,14 @@ sql_host=Hostname
 sql_user=Username
 sql_pass=Password
 sql_db=Database name
+sql_ssl=Connection encryption
+sql_ssl0=None
+sql_ssl1=SSL
+sql_ssl2=TLS
+sql_userclass=Object class for users
+sql_groupclass=Object class for groups
+sql_euserclass=Missing or invalid object class for users
+sql_egroupclass=Missing or invalid object class for groups
 sql_none=Use only local files to store users and groups
 sql_mysql=Use MySQL database
 sql_postgresql=Use PostgreSQL database
@@ -401,11 +409,8 @@ sql_prefix=Create under DN
 sql_addto0=Add new users to database selected above
 sql_addto1=Add new users to local files
 sql_emod=Missing required Perl module <tt>$1</tt>
-sql_emysqldriver=Failed to load MySQL DBI driver
-sql_emysqlconnect=Failed to connect to MySQL database : $1
-sql_epostgresqldriver=Failed to load PostgreSQL DBI driver
-sql_epostgresqlconnect=Failed to connect to PostgreSQL database : $1
 sql_etable=Failed to query required table $1 : $2
+sql_eldapdn=Base LDAP DN $1 was not found
 sql_err=Failed to save user and group database settings
 sql_ehost=Missing or un-resolvable hostname
 sql_euser=Missing or invalid username (no spaces allowed)
index 3a747a9..f5d61e3 100755 (executable)
@@ -27,6 +27,23 @@ elsif ($p eq 'ldap') {
        $in{$p."_prefix"} =~ /^\S+$/ || &error($text{'sql_eprefix'});
        $in{$p."_prefix"} =~ /=/ || &error($text{'sql_eprefix2'});
        $prefix = $in{$p."_prefix"};
+       $args = { };
+       if ($in{'ldap_ssl'} == 0) {
+               $args->{'scheme'} = 'ldap';
+               }
+       elsif ($in{'ldap_ssl'} == 1) {
+               $args->{'scheme'} = 'ldaps';
+               }
+       elsif ($in{'ldap_ssl'} == 2) {
+               $args->{'scheme'} = 'ldap';
+               $args->{'tls'} = 1;
+               }
+       $in{'ldap_userclass'} =~ /^[a-z0-9]+$/i ||
+               &error($text{'sql_euserclass'});
+       $args->{'userclass'} = $in{'ldap_userclass'};
+       $in{'ldap_groupclass'} =~ /^[a-z0-9]+$/i ||
+               &error($text{'sql_egroupclass'});
+       $args->{'groupclass'} = $in{'ldap_groupclass'};
        }
 
 # Create and test connection string
diff --git a/lang/en b/lang/en
index 19cf209..da5ea33 100644 (file)
--- a/lang/en
+++ b/lang/en
@@ -339,3 +339,13 @@ wsearch_hmod=Module
 wsearch_moddir=URL path /$1/
 wsearch_searching=Searching for $1 . .
 wsearch_found=found $1 results :
+
+sql_emysqldriver=Failed to load MySQL DBI driver
+sql_emysqlconnect=Failed to connect to MySQL database : $1
+sql_epostgresqldriver=Failed to load PostgreSQL DBI driver
+sql_epostgresqlconnect=Failed to connect to PostgreSQL database : $1
+sql_eldapdriver=Failed to load LDAP perl module
+sql_eldapconnect=Failed to connect to LDAP server $1
+sql_eldaptls=Failed to start TLS encryption for LDAP : $1
+sql_eldaplogin=Failed to login to LDAP server as $1 : $2
+
index 161ed39..2000918 100755 (executable)
@@ -9019,8 +9019,39 @@ elsif ($proto eq "postgresql") {
        return wantarray ? ($dbh, $proto) : $dbh;
        }
 elsif ($proto eq "ldap") {
-       # XXX
-       return "LDAP not done yet";
+       # Connect with perl LDAP module
+       eval "use Net::LDAP";
+       $@ && return $text{'sql_eldapdriver'};
+       my ($host, $port) = split(/:/, $host);
+       my $scheme = $args->{'scheme'} || 'ldap';
+       if (!$port) {
+               $port = $scheme eq 'ldaps' ? 636 : 389;
+               }
+       my $ldap = Net::LDAP->new($host,
+                                 port => $port,
+                                 'scheme' => $scheme);
+       $ldap || return &text('sql_eldapconnect', $host);
+       my $mesg;
+       if ($args->{'tls'}) {
+               # Switch to TLS mode
+               eval { $mesg = $ldap->start_tls(); };
+               if ($@ || !$mesg || $mesg->code) {
+                       return &text('sql_eldaptls',
+                           $@ ? $@ : $mesg ? $mesg->error : "Unknown error");
+                       }
+               }
+       # Login to the server
+       if ($pass) {
+               $mesg = $ldap->bind(dn => $user, password => $pass);
+               }
+       else {
+               $mesg = $ldap->bind(dn => $user, anonymous => 1);
+               }
+       if (!$mesg || $mesg->code) {
+               return &text('sql_eldaplogin', $user,
+                            $mesg ? $mesg->error : "Unknown error");
+               }
+       return wantarray ? ($ldap, $proto) : $ldap;
        }
 else {
        return "Unknown protocol $proto";