sub split_userdb_string
{
my ($str) = @_;
-if ($str =~ /^([a-z]+):\/\/([^:]+):([^\@]+)\@([a-z0-9\.\-\_]+)\/([^\?]+)(\?(.*))?$/) {
+if ($str =~ /^([a-z]+):\/\/([^:]*):([^\@]*)\@([a-z0-9\.\-\_]+)\/([^\?]+)(\?(.*))?$/) {
my ($proto, $user, $pass, $host, $prefix, $argstr) =
- ($1, $2, $3, $3, $5, $7);
+ ($1, $2, $3, $4, $5, $7);
my %args = map { split(/=/, $_, 2) } split(/\&/, $argstr);
return ($proto, $user, $pass, $host, $prefix, \%args);
}
return $proto."://".$user.":".$pass."\@".$host."/".$prefix.$argstr;
}
-# validate_userdb(string)
+# validate_userdb(string, [no-table-check])
# Checks if some user database is usable, and if not returns an error message
sub validate_userdb
{
-my ($str) = @_;
+my ($str, $notablecheck) = @_;
my ($proto, $user, $pass, $host, $prefix, $args) = &split_userdb_string($str);
if ($proto eq "mysql" || $proto eq "postgresql") {
# Load DBI driver
ref($dbh) || return $dbh;
# Validate critical tables
- my %tables = ( "webmin_user" => [ "id", "name", "pass" ],
- "webmin_group" => [ "id", "name", "desc" ],
- "webmin_user_attr" => [ "id", "attr", "value" ],
- "webmin_group_attr" => [ "id", "attr", "value" ],
- "webmin_user_acl" => [ "id", "module", "attr", "value" ],
- "webmin_group_acl" => [ "id", "module", "attr", "value"],
- );
- foreach my $t (keys %tables) {
- my @cols = @{$tables{$t}};
- my $sql = "select ".join(",", @cols)." from $t limit 1";
- my $cmd = $dbh->prepare($sql);
- if (!$cmd || !$cmd->execute()) {
- return &text('sql_etable', $t,
- &html_escape($dbh->errstr));
+ if (!$notablecheck) {
+ my %tables =
+ ( "webmin_user" => [ "id", "name", "pass" ],
+ "webmin_group" => [ "id", "name", "desc" ],
+ "webmin_user_attr" => [ "id", "attr", "value" ],
+ "webmin_group_attr" => [ "id", "attr", "value" ],
+ "webmin_user_acl" => [ "id", "module", "attr", "value" ],
+ "webmin_group_acl" => [ "id", "module", "attr", "value"],
+ );
+ foreach my $t (keys %tables) {
+ my @cols = @{$tables{$t}};
+ my $sql = "select ".join(",", @cols)." from $t limit 1";
+ my $cmd = $dbh->prepare($sql);
+ if (!$cmd || !$cmd->execute()) {
+ return &text('sql_etable', $t,
+ &html_escape($dbh->errstr));
+ }
+ $cmd->finish();
}
- $cmd->finish();
}
&disconnect_userdb($str, $dbh);
return undef;
}
}
+# userdb_table_sql(string)
+# Returns SQL statements needed to create all required tables
+sub userdb_table_sql
+{
+my ($str) = @_;
+return ( "create table webmin_user (id int(20), name varchar(255), pass varchar(255))",
+ "create table webmin_group (id init(20), name varchar(255), desc varchar(255))",
+ "create table webmin_user_attr (id int(20), attr varchar(32), value varchar(255))",
+ "create table webmin_group_attr (id int(20), attr varchar(32), value varchar(255))",
+ "create table webmin_user_acl (id int(20), module varchar(32), attr varchar(32), value varchar(255))",
+ "create table webmin_group_acl (id int(20), module varchar(32), attr varchar(32), value varchar(255))",
+ );
+}
+
1;
--- /dev/null
+#!/usr/local/bin/perl
+# Show form for an external user / group database
+
+require './acl-lib.pl';
+$access{'sql'} || &error($text{'sql_ecannot'});
+&ui_print_header(undef, $text{'sql_title'}, "");
+&get_miniserv_config(\%miniserv);
+
+print &ui_form_start("save_sql.cgi");
+print &ui_table_start($text{'sql_header'}, undef, 2);
+
+($proto, $user, $pass, $host, $prefix, $args) =
+ &split_userdb_string($miniserv{'userdb'});
+
+# Build inputs for MySQL backend
+@mysqlgrid = ( );
+push(@mysqlgrid,
+ $text{'sql_host'},
+ &ui_textbox("mysql_host", $proto eq "mysql" ? $host : "", 30));
+push(@mysqlgrid,
+ $text{'sql_user'},
+ &ui_textbox("mysql_user", $proto eq "mysql" ? $user : "", 30));
+push(@mysqlgrid,
+ $text{'sql_pass'},
+ &ui_textbox("mysql_pass", $proto eq "mysql" ? $pass : "", 30));
+push(@mysqlgrid,
+ $text{'sql_db'},
+ &ui_textbox("mysql_db", $proto eq "mysql" ? $prefix : "", 30));
+$mysqlgrid = &ui_grid_table(\@mysqlgrid, 2, 100);
+
+# Build inputs for PostgreSQL backend
+@postgresqlgrid = ( );
+push(@postgresqlgrid,
+ $text{'sql_host'},
+ &ui_textbox("postgresql_host", $proto eq "postgresql" ? $host : "", 30));
+push(@postgresqlgrid,
+ $text{'sql_user'},
+ &ui_textbox("postgresql_user", $proto eq "postgresql" ? $user : "", 30));
+push(@postgresqlgrid,
+ $text{'sql_pass'},
+ &ui_textbox("postgresql_pass", $proto eq "postgresql" ? $pass : "", 30));
+push(@postgresqlgrid,
+ $text{'sql_db'},
+ &ui_textbox("postgresql_db", $proto eq "postgresql" ? $prefix : "", 30));
+$postgresqlgrid = &ui_grid_table(\@postgresqlgrid, 2, 100);
+
+# Build inputs for LDAP backend
+@ldapgrid = ( );
+push(@ldapgrid,
+ $text{'sql_host'},
+ &ui_textbox("ldap_host", $proto eq "ldap" ? $host : "", 30));
+push(@ldapgrid,
+ $text{'sql_user'},
+ &ui_textbox("ldap_user", $proto eq "ldap" ? $user : "", 30));
+push(@ldapgrid,
+ $text{'sql_pass'},
+ &ui_textbox("ldap_pass", $proto eq "ldap" ? $pass : "", 30));
+push(@ldapgrid,
+ $text{'sql_prefix'},
+ &ui_textbox("ldap_prefix", $proto eq "ldap" ? $prefix : "", 30));
+# XXX object classes?
+$ldapgrid = &ui_grid_table(\@ldapgrid, 2, 100);
+
+print &ui_table_row(undef,
+ &ui_radio_table("proto", $proto,
+ [ [ '', $text{'sql_none'} ],
+ [ 'mysql', $text{'sql_mysql'}, $mysqlgrid ],
+ [ 'postgresql', $text{'sql_postgresql'}, $postgresqlgrid ],
+ [ 'ldap', $text{'sql_ldap'}, $ldapgrid ] ]), 2);
+
+print &ui_table_row(undef,
+ &ui_radio("addto", int($miniserv{'userdb_addto'}),
+ [ [ 0, $text{'sql_addto0'} ],
+ [ 1, $text{'sql_addto1'} ] ]), 2);
+
+print &ui_table_end();
+print &ui_form_end([ [ undef, $text{'save'} ] ]);
+
+&ui_print_footer("", $text{'index_return'});
log_pass=Changed password restrictions
log_unix=Changed unix user authentication
log_sync=Changed unix user synchronization
+log_sql=Changed user and group database
gedit_ecannot=You are not allowed to edit groups
gedit_title=Edit Webmin Group
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_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)
+sql_epass=Invalid password (no spaces allowed)
+sql_edb=Invalid database name (no spaces allowed)
+sql_eprefix=Missing or invalid base DN (no spaces allowed)
+sql_eprefix2=Invalid-looking base DN - should be like <tt>dc=mydomain,dc=com</tt>
+sql_title2=Create Missing Tables
+sql_tableerr=User and group database settings were successfully saved, but some tables needed by Webmin are missing : $1
+sql_tableerr2=Click the <b>Create Tables</b> to have them created automatically, or manually run the SQL below.
+sql_make=Create Tables
--- /dev/null
+#!/usr/local/bin/perl
+# Save user and group database
+
+require './acl-lib.pl';
+$access{'pass'} || &error($text{'sql_ecannot'});
+&get_miniserv_config(\%miniserv);
+&ReadParse();
+&error_setup($text{'sql_err'});
+$p = $in{'proto'};
+
+# Parse inputs
+if ($p eq 'mysql' || $p eq 'postgresql' || $p eq 'ldap') {
+ gethostbyname($in{$p."_host"}) ||
+ $in{$p."_host"} =~ /^(\S+):(\d+)$/ && gethostbyname($1) ||
+ &error($text{'sql_ehost'});
+ $in{$p."_user"} =~ /^\S+$/ || &error($text{'sql_euser'});
+ $in{$p."_pass"} =~ /^\S*$/ || &error($text{'sql_epass'});
+ $host = $in{$p."_host"};
+ $user = $in{$p."_user"};
+ $pass = $in{$p."_pass"};
+ }
+if ($p eq 'mysql' || $p eq 'postgresql') {
+ $in{$p."_db"} =~ /^\S+$/ || &error($text{'sql_edb'});
+ $prefix = $in{$p."_db"};
+ }
+elsif ($p eq 'ldap') {
+ $in{$p."_prefix"} =~ /^\S+$/ || &error($text{'sql_eprefix'});
+ $in{$p."_prefix"} =~ /=/ || &error($text{'sql_eprefix2'});
+ $prefix = $in{$p."_prefix"};
+ }
+
+# Create and test connection string
+if ($p) {
+ $str = &join_userdb_string($p, $user, $pass, $host,
+ $prefix, $args);
+ $err = &validate_userdb($str, 1);
+ &error($err) if ($err);
+ }
+
+&lock_file($ENV{'MINISERV_CONFIG'});
+$miniserv{'userdb'} = $str;
+$miniserv{'userdb_addto'} = $in{'addto'};
+&put_miniserv_config(\%miniserv);
+&unlock_file($ENV{'MINISERV_CONFIG'});
+&reload_miniserv();
+&webmin_log("sql");
+
+# Make sure tables exist
+$err = &validate_userdb($str, 0);
+if ($err) {
+ &ui_print_header(undef, $text{'sql_title2'}, "");
+
+ print &text('sql_tableerr', $err),"<p>\n";
+ print $text{'sql_tableerr2'},"<p>\n";
+ print &ui_form_start("maketables.sql");
+ print &ui_form_end([ [ undef, $text{'sql_make'} ] ]);
+
+ print &ui_table_start(undef, undef, 2);
+ foreach $sql (&userdb_table_sql($str)) {
+ print &ui_table_row(undef,
+ "<pre>".&html_escape($sql)."</pre>", 2);
+ }
+ print &ui_table_end();
+
+ &ui_print_footer("", $text{'index_return'});
+ }
+else {
+ &redirect("");
+ }
+