return \@conf;
}
-# save_directive(name, &values, &parent-directives, &config)
+# save_directive(name, &values, &parent-directives, &config, [always-at-end])
# Updates the config file(s) and the directives structure with new values
# for the given directives.
# If a directive's value is merely being changed, then its value only needs
# a new directive is being added. If other directives of this
# type exist, add it after them. Otherwise, put it at the end of
# the first file in the section
- if ($change) {
+ if ($change && !$_[4]) {
# Have changed some old directive.. add this new one
# after it, and update change
local(%v, $j);
Record names or values entered like ns.foo.com in the domain foo.com automatically have a . added to make them absolute as the user presumably expected, rather than being coverted to ns.foo.com.foo.com.
Update serial number (by default) when editing records manually.
Try downloading root zone files from the IP for rs.internic.net if the hostname cannot be resolved, to avoid catch-22 problem.
+Access control lists are now automatically re-ordered to handle dependencies.
&error_setup($text{'acls_err'});
&ReadParse();
+# Convert inputs into ACL structures
+%depmap = ( );
&lock_file(&make_chroot($config{'named_conf'}));
$conf = &get_config();
for($i=0; defined($name = $in{"name_$i"}); $i++) {
'members' => [ map { my ($n, @w)=split(/\s+/, $_);
{ 'name' => $n,
'values' => \@w } } @vals ] });
+
+ # Record this ACL as a dependency of some ACL it refers to
+ foreach (@vals) {
+ my ($n, @w)=split(/\s+/, $_);
+ if ($n !~ /^[0-9\.]+$/) {
+ push(@{$depmap{$n}}, $name);
+ }
+ }
}
+# Sort the list so that depended-on ACLs come first
+@acls = sort { my $an = $a->{'values'}->[0];
+ my $bn = $b->{'values'}->[0];
+ &indexof($an, @{$depmap{$bn}}) >= 0 ? 1 :
+ &indexof($bn, @{$depmap{$an}}) >= 0 ? -1 : 0 } @acls;
+
&save_directive(&get_config_parent(), 'acl', \@acls, 0, 0, 1);
&flush_file_lines();
&unlock_file(&make_chroot($config{'named_conf'}));
}
if ($access{'pass'} && &can_change_pass($user) && !$in{'pass_def'}) {
$user->{'pass'} = &acl::encrypt_password($in{'pass'});
+ $user->{'temppass'} = 0;
}
&acl::modify_user($user->{'name'}, $user);
print "$text{'change_done'}<p>\n";
# custom-lib.pl
# Functions for storing custom commands
-# XXX variable in file editors
-# XXX don't need quoting option
-# XXX don't need upload type, or password, or text box, or option
do '../web-lib.pl';
&init_config();
acl_feedback0=Íåò
acl_feedback1=Äà, íî íå âêëþ÷àòü ôàéëû íàñòðîéêè
acl_feedback2=Äà
-acl_feedback3=Äà, âìåñòå ñ êîíôèãóðàöèîííûìè ôàéëàìè
acl_gedit=Âèäèìûå ãðóïïû
acl_gedit_all=Âñå ãðóïïû
acl_gedit_except=Âñå ãðóïïû êðîìå óêàçàííûõ
acl_gedit_none=Íè îäíîé ãðóïïû
acl_gedit_only=Òîëüêî óêàçàííûå ãðóïïû
acl_home=Äîìàøíèé êàòàëîã ïîëüçîâàòåëÿ
-acl_nodot=Ñêðûòü ôàéëû, èìåíà êîòîðûõ íà÷èíàþòñÿ ñ ñèìâîëà (.) â ñåëåêòîðå ôàéëîâ?
-acl_readonly=Ïîëüçîâàòåëü â äåìîíñòðàöèîííîì ðåæèìå?<br>(Íåêîòîðûå ìîäóëè ìîãóò áûòü íåäîñòóïíû)
acl_root=Êîðíåâîé êàòàëîã
acl_rpc=Ïðèíèìàòü çàïðîñû RPC?
acl_rpc0=Íåò
category_servers=Ñëóæáû
category_syslet=Ñèñëåòû
category_system=Ñèñòåìà
-category_webmin=ZTL
-chooser_date=Âûáðàòü Äàòó
+category_webmin=Webmin
chooser_dir=Êàòàëîã $1
chooser_ok=ÎÊ
chooser_title1=Âûáîð ôàéëà..
config_eaccess=Ó âàñ íåäîñòàòî÷íî ïðàâ äëÿ äîñòóïà ê ýòîìó ìîäóëþ
config_ecannot=Ó âàñ íåäîñòàòî÷íî ïðàâ íà íàñòðîéêó ýòîãî ìîäóëÿ
config_err=Íå óäàëîñü ñîõðàíèòü íàñòðîéêè
-config_ewebmin=Ïàðàìåòð type 14 ðàáîòàåò òîëüêî â ZTL
config_header=Íàñòðîéêè ìîäóëÿ $1
config_nochange=Íå èçìåíÿòü
config_none=Íåò
day_6=Ñóááîòà
default=Ïî óìîë÷àíèþ
delete=Óäàëèòü
-efileclose=Íåâîçìîæíî ïèñàòü â $1 êîãäà çàêðûâàåòñÿ : $2
-efileopen=Íåâîçìîæíî îòêðûòü $1 äëÿ çàïèñè : $2
efilewrite=Íå óäàëîñü çàïèñàòü â $1 : $2
elock_tries=Íå óäàëîñü çàáëîêèðîâàòü ôàéë $1 ïîñëå $2 ìèíóò
emodule=Äîñòóï çàïðåùåí : Ïîëüçîâàòåëü $1 íå èìååò ïðàâ íà èñïîëüçîâàíèå ìîäóëÿ $2
error=Îøèáêà
-error_previous=ïðåäûäóùàÿ ñòðàíèöà
feedback_all=All modules
feedback_attach=Additional files to attach
feedback_config=Include module configuration in email?
feedback_configdesc=If this is selected, the email will include the configuration of the related module and the contents of any config files that the module uses. For example, if the feedback was related to the <i>Users and Groups</i> module, your <tt>/etc/passwd</tt> and <tt>/etc/shadow</tt> files would be sent.
-feedback_desc=This form allows you to report bugs on make suggestions to the ZTL developers regarding any problems or missing features that you have found. When the Send button is clicked, the details entered into the form will be emailed to $1.
-feedback_desc2=This feedback will be sent to the developer of End User ZTL, not your system administrator, ISP or hosting company. Please write your feedback in english, even if you are currently running ZTL in another language.
+feedback_desc=This form allows you to report bugs on make suggestions to the Webmin developers regarding any problems or missing features that you have found. When the Send button is clicked, the details entered into the form will be emailed to $1.
+feedback_desc2=This feedback will be sent to the developer of Usermin, not your system administrator, ISP or hosting company. Please write your feedback in english, even if you are currently running Webmin in another language.
feedback_ecannot=You are not allowed to send feedback
feedback_ecannot2=You are not allowed to send feedback containing config files
feedback_econfig=You do not have full access to the selected module.
feedback_prog=Sent feedback to $1 using sendmail program $2
feedback_send=Send Feedback
feedback_text=Description of problem or suggestion
-feedback_title=ZTL Feedback
+feedback_title=Webmin Feedback
feedback_to=Send feedback to addresses
feedback_via=Sent feedback to $1 via SMTP server $2
find=Íàéòè
header_config=Íàñòðîéêà ìîäóëÿ
header_help=Ñïðàâêà..
header_module=Ìåíþ ìîäóëÿ
-header_servers=Ñåðâåðû ZTL
-header_statusmsg=$1 âîø¸ë â $2 $3 íà $4 ($5)
-header_webmin=Ãëàâíîå ìåíþ ZTL
+header_servers=Ñåðâåðû Webmin
+header_webmin=Ãëàâíîå ìåíþ Webmin
help_eexec=Îøèáêà $1 : $2
help_efile=Íå óäàëîñü ïðî÷èòàòü ôàéë ñïðàâêè $1
help_eheader=Îòñóòñòâóåò <çàãîëîâîê> ðàçäåëà
help_err=Íå óäàëîñü âûâåñòè ñïðàâêó
helpsearch=Ïîèñê â ñïðàâêå..
index=ìåíþ
-index_chpass=Èçìåíèòü Ïàðîëü
-index_configure_mod=Êîíôèãóðèðîâàòü ýòî ìîäóëü
-index_diskspace=Äèñêîâîå Ïðîñòðàíñòâî
-index_hostname=Õîñò
-index_logout_hint=Âûéòè èç èíòåðôåéñà Ïîëüçâàòåëÿ ZTL
-index_mainpage=Ãëàâíàÿ Ñòðàíèöà
-index_mainpage2=Ãëàâíàÿ Ñòðàíèöà
-index_mainpage_url=/home/index.cgi
-index_os=ÎÑ
-index_remoteip=Óäàë¸ííûé IP
-index_return=èíäåêñ
-index_time=Âðåìÿ
-index_title_login=Âîéòè â èíòåðôåéñ Ïîëüçîâàòåëÿ ZTL
-index_title_system=Èíôîðìàöèÿ î Ñèñòåìå
-index_title_user=Èíôîðìàöèÿ î Ïîëüçîâàòåëå
-index_uptime=Âðåìÿ Ðàáîòû
-index_user=Unix Ïîëüçîâàòåëü
-index_ver=âåð.
-link_essl=Perl ìîäóëü Net::SSLeay, íåîáõîäèìûé ÷òîáû óñòàíîâèòü HTTPS ñîåäèíåíèÿ, íå óñòàíîâëåí â Âàøåé ñèñòåìå.
-longcategory_=Ìîäóëè, êîòîðûå íå îòíîñÿòñÿ íè ê êàêîé äðóãîé êàòåãîðèè
-longcategory_cluster=Ìîäóëè, êîòîðûå ìîãóò óïðàâëÿòü íåñêîëüêèìè ñåðâåðàìè èç îäíîãî èíòåðôåéñà
-longcategory_hardware=Ìîäóëè äëÿ ïðèíòåðà, äèñêîâ è äðóãîé êîíôèãóðàöèè àïïàðàòíîãî îáåñïå÷åíèÿ
-longcategory_info=Ìîäóëè, îòîáðàæàþùèå èíôîðìàöèþ î Âàøåé ñèñòåìå
-longcategory_net=Ìîäóëè äëÿ êîíôèãóðàöèè ñåòè è ñåòåâûõ ñåðâèñîâ
-longcategory_servers=Ìîäóëè äëÿ êîíôèãóðàöèè web, email, FTP è äðóãèõ ñåðâèñîâ
-longcategory_system=Ìîäóëè äëÿ ïîëüçîâàòåëåé, ôàéëîâûõ ñèñòåì è äðóãèõ íàñòðîåê ñèñòåìû
-longcategory_webmin=Ìîäóëè äëÿ êîíôèãóðèðîâàíèÿ ZTL
main_feedback=Îòçûâ..
main_homepage=Äîìàøíÿÿ ñòðàíèöà
main_logout=Âûéòè
-main_none=Âû íå èìååòå äîñòóïà íè ê îäíîìó ìîäóëþ ZTL.
-main_readonly=(ðåæèì ÷òåíèÿ)
+main_none=Âû íå èìååòå äîñòóïà íè ê îäíîìó ìîäóëþ Webmin.
main_return=Âåðíóòüñÿ ê $1
main_skill=Îïûòíîñòü
main_switch=Ñìåíèòü ïîëüçîâàòåëÿ..
-main_title=ZTL $1 íà $2 ($3)
-main_title2=ZTL
+main_title=Webmin $1 íà $2 ($3)
+main_title2=Webmin
main_version=Âåðñèÿ $1 íà $2 ($3)
modify=Èçìåíèòü
-modules_all=Âñå ìîäóëè
-modules_cancel=Âûõîä
-modules_clear=Î÷èñòèòü
-modules_ok=Îê
-modules_sel=Âûáðàííûå Ìîäóëè
-modules_title1=Âûáðàòü Ìîäóëè ..
-modules_title2=Âûáðàòü Ìîäóëü ..
month_1=ßíâàðü
month_10=Îêòÿáðü
month_11=Íîÿáðü
month_9=Ñåíòÿáðü
no=Íåò
ok=ÎÊ
-pam_header=Âîéòè â ZTL
-pam_login=Ïðîäîëæèòü
-pam_mesg=Âû äîëæíû îòâåòèòü íà íèæåóêàçàííûé âîïðîñ ÷òîáû âîéòè íà ñåðâåð ZTL íà $1.
-pam_mesg2=Âû äîëæíû îòâåòèòü íà íèæåóêàçàííûé âîïðîñ ÷òîáû âîéòè â ñèñòåìó.
-pam_restart=Ïåðåçàãðóçèòü
-password_clear=Î÷èñòèòü
-password_done=Âàø ïàðîëü áûë óäà÷íî èçìåí¸í. Âû ìîæåòå òåïåðü <a href='$1'>çàéòè îïÿòü</a> ñ íîâûì ïàðîëåì.
-password_emodpam=Perl ìîäóëü Authen::PAM, íåîáõîäèìûé ÷òîáû ïðîâîäèòü èçìåíåíèÿ ïàðîëåé, íå óñòàíîâëåí!
-password_enew1=Íîâûõ ïàðîëåé íå áûëî ââåäåíî
-password_enew2=Âàø íîâûé ïàðîëü íå ïîäõîäèò
-password_eold=Òåêóùèé ïàðîëü- íåïðàâèëüíûé
-password_epam=Îøèáêà PAM : $1
-password_err=Íåâîçìîæíî èçìåíèòü ïàðîëü
-password_euser=Âàøå èìÿ ó÷¸òíîé çàïèñè íå áûëî íàéäåíî ôàéëå ïàðîëåé!
-password_expired=Âàø ïàðîëü áîëüøå íåäåéñòâèòåëåí, äîëæåí áûòü âûáðàí íîâûé
-password_header=Âûáåðèòå Íîâûé Ïàðîëü
-password_new1=Íîâûé ïàðîëü
-password_new2=Åù¸ ðàç íîâûé ïàðîëü
-password_ok=Èçìåíèòü
-password_old=Òåêóùèé ïàðîëü
-password_user=Èìÿ ïîëüçîâàòåëÿ
-programname=ZTL
+programname=Webmin
progress_data=Ïîëó÷åíî $1 áàéò ($2 %)
progress_data2=Ïîëó÷åíî $1 áàéò
progress_done=.. Çàãðóçêà çàâåðøåíà.
-progress_incache=Íàéäåíî $1 â êýøå ..
progress_nosize=Çàãðóçêà $1 ..
progress_size=Çàãðóçêà $1 ($2 áàéò) ..
-readparse_cdheader=Îòñóòñòâóåò çàãîëîâîê Ðàññòàíîâêè Êîíòåíòà
-readparse_enc=Îæèäàëàñü êîäèðîâêà form-data, íî èñïîëüçîâàëàñü íîðìàëüíàÿ êîäèðîâêà
-readparse_max=Ðàçìåð äàííûõ äîñòèã ìàêñèìàëüíîãî ðàçìåðà $1 áàéò
referer_again=Áîëüøå íå ïîêàçûâàòü ýòî ïðåäóïðåæäåíèå.
-referer_ok=Ïðîäîëæèòü âûïîëíåíèå ïðîãðàììû ZTL
+referer_ok=Ïðîäîëæèòü âûïîëíåíèå ïðîãðàììû Webmin
referer_title=Ïðåäóïðåæäåíèå î áåçîïàñíîñòè
-referer_warn=<b>Âíèìàíèå!</b> ZTL îïðåäåëèë, ÷òî ññûëêà íà ïðîãðàììó $2 áûëà ïðîèçâåäåíà ñ URL $1, êîòîðûé íàõîäèòñÿ âíå ñåðâåðà ZTL. Ýòî ìîæåò áûòü ïîïûòêîé îáìàíóòü âàø ñåðâåð ñ öåëüþ çàïóñêà îïàñíîé êîìàíäû..
-referer_warn_unknown=<b>Âíèìàíèå!</b> ZTL îïðåäåëèë, ÷òî ññûëêà íà ïðîãðàììó $1 áûëà ïðîèçâåäåíà ñ íåèçâåñòíîãî URL, êîòîðûé íàõîäèòñÿ âíå ñåðâåðà ZTL. Ýòî ìîæåò áûòü ïîïûòêîé îáìàíóòü âàø ñåðâåð ñ öåëüþ çàïóñêà îïàñíîé êîìàíäû..
+referer_warn=<b>Âíèìàíèå!</b> Webmin îïðåäåëèë, ÷òî ññûëêà íà ïðîãðàììó $2 áûëà ïðîèçâåäåíà ñ URL $1, êîòîðûé íàõîäèòñÿ âíå ñåðâåðà Webmin. Ýòî ìîæåò áûòü ïîïûòêîé îáìàíóòü âàø ñåðâåð ñ öåëüþ çàïóñêà îïàñíîé êîìàíäû..
+referer_warn_unknown=<b>Âíèìàíèå!</b> Webmin îïðåäåëèë, ÷òî ññûëêà íà ïðîãðàììó $1 áûëà ïðîèçâåäåíà ñ íåèçâåñòíîãî URL, êîòîðûé íàõîäèòñÿ âíå ñåðâåðà Webmin. Ýòî ìîæåò áûòü ïîïûòêîé îáìàíóòü âàø ñåðâåð ñ öåëüþ çàïóñêà îïàñíîé êîìàíäû..
reset=Ñáðîñèòü
save=Ñîõðàíèòü
sday_0=Âñ
sday_6=Ñá
session_clear=Î÷èñòèòü
session_failed=Ïîïûòêà âõîäà íå óäàëàñü. Ïîïðîáóéòå åùå ðàç.
-session_header=Âõîä â ZTL
+session_header=Âõîä â Webmin
session_login=Âõîä
session_logout=Ïðîèçâåäåí óñïåøíûé âûõîä. Ïðè æåëàíèè âû ìîæåòå âîéòè åùå ðàç.
-session_mesg=Äëÿ âõîäà â ñåðâåð ZTL íà $1 íåîáõîäèìî óêàçàòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü.
+session_mesg=Äëÿ âõîäà â ñåðâåð Webmin íà $1 íåîáõîäèìî óêàçàòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü.
session_mesg2=Äëÿ âõîäà íåîáõîäèìî óêàçàòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü.
session_pass=Ïàðîëü
session_save=Çàïîìíèòü èìÿ ïîëüçîâàòåëÿ è ïàðîëü?
smonth_7=Èþë
smonth_8=Àâã
smonth_9=Ñåí
-st_ftp=FTP Äîñòóï
-st_mail=Ïî÷òîâûé ÿùèê
-st_smb=Êëèåíò Windows
switch_remote_euser=Ïîëüçîâàòåëü Unix $1 íå ñóùåñòâóåò.
-ui_checkmandatory=Íè÷åãî íå áûëî âûáðàíî
-ui_edate=Íåïðàâèëüíàÿ äàòà
-ui_errors=Ðàçëè÷íûå îøèáêè áûëè íàéäåíû :
-ui_etime=Íåïðàâèëüíîå âðåìÿ
-ui_mandatory=Ýòî ïîëå- îáÿçàòåëüíî
-ui_nothing=Íè÷åãî íå ââåäåíî
-ui_paging=Ïîêàçûâàòü ñòðîêè ñ $1 ïî $2 èç $3
-ui_rowlabel=$2 â ñòðîêå $1 :
-ui_searchcol=Íàéòè ñòðîêè ãäå
-ui_searchfor=Âêëþ÷àåò â ñåáÿ òåêñò
-ui_searchok=Èñêàòü
-ui_selall=Âûáðàòü âñ¸.
-ui_selinv=Èíâåðòèðîâàòü âûáîðêó.
users_all=Âñå ïîëüçîâàòåëè
users_cancel=Îòìåíà
users_clear=Î÷èñòèòü
users_ok=ÎÊ
-users_sel=Âûáðàííûå Ïîëüçîâàòåëè
-users_title1=Âûáðàòü Ïîëüçîâàòåëåé..
-users_title2=Âûáðàòü Ïîëüçîâàòåëÿ..
+users_sel=Âûáðàííûå ïîëüçîâàòåëè
+users_title1=Âûáîð ïîëüçîâàòåëåé..
+users_title2=Âûáîð ïîëüçîâàòåëÿ..
yes=Äà
--- /dev/null
+Initial version
--- /dev/null
+
+do 'wrappers-lib.pl';
+
+# backup_config_files()
+# Returns files and directories that can be backed up
+sub backup_config_files
+{
+return ( $config{'hosts_allow'}, $config{'hosts_deny'} );
+}
+
+# pre_backup(&files)
+# Called before the files are actually read
+sub pre_backup
+{
+return undef;
+}
+
+# post_backup(&files)
+# Called after the files are actually read
+sub post_backup
+{
+return undef;
+}
+
+# pre_restore(&files)
+# Called before the files are restored from a backup
+sub pre_restore
+{
+return undef;
+}
+
+# post_restore(&files)
+# Called after the files are restored from a backup
+sub post_restore
+{
+return undef;
+}
+
+1;
+
--- /dev/null
+hosts_allow=/etc/hosts.allow
+hosts_deny=/etc/hosts.deny
--- /dev/null
+hosts_allow=TCP wrappers allow file,0
+hosts_deny=TCP wrappers deny file,0
--- /dev/null
+#!/usr/local/bin/perl
+# Delete multiple rules
+
+require './tcpwrappers-lib.pl';
+&ReadParse();
+&error_setup($text{'del_err'});
+
+@d = split(/\0/, $in{'d'});
+@d || &error($text{'del_enone'});
+$file = $in{'allow'} ? $config{'hosts_allow'} : $config{'hosts_deny'};
+@rules = &list_rules($file);
+
+# Do the delete
+&lock_file($file);
+
+foreach $d (@d) {
+ ($rule) = grep { $_->{'id'} == $d } @rules;
+ $rule || &error($text{'edit_eid'});
+ &delete_rule($file, $rule);
+}
+
+&unlock_file($file);
+&webmin_log("delete", "rules", scalar(@d));
+
+&redirect("");
--- /dev/null
+#!/usr/local/bin/perl
+# Creating or editing rule
+
+require './tcpwrappers-lib.pl';
+&ReadParse();
+
+@xservices = &list_services();
+unshift @xservices, "ALL" if (@xservices);
+
+if ($in{'new'}) {
+ &ui_print_header(undef, $text{'edit_title1'}, "", "edit_rule");
+} else {
+ &ui_print_header(undef, $text{'edit_title2'}, "", "edit_rule");
+ @rules = &list_rules($in{'allow'} ? $config{'hosts_allow'} : $config{'hosts_deny'});
+ ($rule) = grep { $_->{'id'} == $in{'id'} } @rules;
+ $rule || &error($text{'edit_eid'});
+
+ # parse services (daemons)
+ if ($rule->{'service'} =~ /^(.+) EXCEPT (.*)$/) {
+ @services = split /,\s?|\s+/, $1;
+ @eservices = split /,\s?|\s+/, $2;
+ } else {
+ @services = split /,\s?|\s+/, $rule->{'service'};
+ }
+
+ if (@xservices) {
+ # try to find all services (daemons) in xinetd/inetd
+ foreach my $rule_service (@services, @eservices) {
+ $found = 0;
+ foreach my $xinet_service (@xservices) { $found = 1 if ($rule_service eq $xinet_service); }
+ unless ($found) {
+ # not found -> let user to edit custom service
+ @xservices = ();
+ }
+ }
+ }
+ # parse hosts
+ if ($rule->{'host'} =~ /^(.+) EXCEPT (.*)$/) {
+ $hosts = $1;
+ $ehosts = $2
+ } else {
+ $hosts = $rule->{'host'};
+ }
+}
+
+# Form header
+print &ui_form_start("save_rule.cgi", "post");
+print &ui_hidden("new", $in{'new'}),"\n";
+print &ui_hidden("id", $in{'id'}),"\n";
+print &ui_hidden($in{'allow'} ? 'allow' : 'deny', 1),"\n";
+#print &ui_table_start($text{'edit_header'}, "width=100%", 5);
+print &ui_table_start($text{'edit_header'}, "", 5);
+
+
+# Services
+if (@xservices) {
+ # listed from (x)inetd
+ print &ui_table_row("<b>$text{'edit_service'}</b> ", &ui_select("service", \@services, \@xservices, 10, 1));
+ print &ui_table_row("EXCEPT", &ui_select("service_except", \@eservices, \@xservices, 10, 1));
+} else {
+ print &ui_table_row("<b>$text{'edit_service'}</b> ", &ui_textbox("service_custom", join(",",@services), 23));
+ print &ui_table_row("EXCEPT", &ui_textbox("service_except_custom", join(",",@eservices), 23));
+}
+print &ui_table_hr();
+
+# Hosts
+@wildcards = ("ALL","KNOWN","UNKNOWN","LOCAL","PARANOID");
+$found = '';
+foreach my $w (@wildcards) {
+ $found = $w if ($w eq $hosts);
+}
+print &ui_table_row("<b>$text{'edit_hosts'}</b> ", &ui_opt_textbox("host_text", ($found ? "" : $hosts), 41, &ui_select("host_select", $found, \@wildcards)), 3);
+print &ui_table_row("", "<b>EXCEPT</b> ".&ui_textbox("host_except", $ehosts, 50), 3);
+print &ui_table_hr();
+
+# Shell commands
+@directives = ('none', 'spawn', 'twist');
+@cmds = split /:/, $rule->{'cmd'} if (!$in{'new'});
+print &ui_table_row($text{'edit_cmd'}, "", 3);
+for ($i = 0; $i <= $#cmds; $i++) {
+ $cmds[$i] =~ s/^\s*//;
+ my $choosed = $cmds[$i] =~ /^(spawn|twist)/ ? $1 : 'none';
+ $cmds[$i] =~ s/^\s*${choosed}\s*// if ($cmds[$i] =~ /^\s*(spawn)|(twist)/);
+ print &ui_table_row("", &ui_select("cmd_directive_$i", $choosed, \@directives).' '.&ui_textbox("cmd_$i", $cmds[$i], 50), 3);
+}
+# Row for new command
+print &ui_table_row("", &ui_select("cmd_directive_$i", undef, \@directives).' '.&ui_textbox("cmd_$i", "", 50), 3);
+print &ui_hidden("cmd_count", $i),"\n";
+
+
+# Form footer
+print &ui_table_end();
+print &ui_form_end([
+ $in{'new'} ? ( [ "create", $text{'create'} ] )
+ : ( [ "save", $text{'save'} ],
+ [ "delete", $text{'delete'} ] ) ]);
+
+&ui_print_footer("", $text{'index_return'});
--- /dev/null
+<header>TCP Wrappers</header>
+
+<h3>Patterns</h3>
+The access control language implements the following patterns:
+<ul>
+<li>A string that begins with a '.' character. A host name is matched if the last components of its name match the specified pattern. For example, the pattern '.tue.nl' matches the host name 'wzv.win.tue.nl'.</li>
+<li>A string that ends with a '.' character. A host address is matched if its first numeric fields match the given string. For example, the pattern '131.155.' matches the address of (almost) every host on the Eindhoven University network (131.155.x.x).</li>
+<li>A string that begins with an '@' character is treated as an NIS (formerly YP) netgroup name. A host name is matched if it is a host member of the specified netgroup. Netgroup matches are not supported for daemon process names or for client user names.</li>
+<li>An expression of the form 'n.n.n.n/m.m.m.m' is interpreted as a 'net/mask' pair. An IPv4 host address is matched if 'net' is equal to the bitwise AND of the address and the 'mask'. For example, the net/mask pattern '131.155.72.0/255.255.254.0' matches every address in the range '131.155.72.0' through '131.155.73.255'.</li>
+<li>An expression of the form '[n:n:n:n:n:n:n:n]/m' is interpreted as a '[net]/prefixlen' pair. An IPv6 host address is matched if 'prefixlen' bits of 'net' is equal to the 'prefixlen' bits of the address. For example, the [net]/prefixlen pattern '[3ffe:505:2:1::]/64' matches every address in the range '3ffe:505:2:1:'? through '3ffe:505:2:1:ffff:ffff:ffff:ffff'.</li>
+<li>A string that begins with a '/' character is treated as a file name. A host name or address is matched if it matches any host name or address pattern listed in the named file. The file format is zero or more lines with zero or more host name or address patterns separated by whitespace. A file name pattern can be used anywhere a host name or address pattern can be used.</li>
+<li>Wildcards '*' and '?' can be used to match hostnames or IP addresses. This method of matching cannot be used in conjunction with 'net/mask' matching, hostname matching beginning with '.' or IP address matching ending with '.'.</li>
+</ul>
+
+<h3>Wildcards</h3>
+The access control language supports explicit wildcards:
+<table border>
+<tr><td><b>ALL</b></td><td>The universal wildcard, always matches.</td></tr>
+<tr><td><b>LOCAL</b></td><td>Matches any host whose name does not contain a dot character.</td></tr>
+<tr><td><b>UNKNOWN</b></td><td>
+ Matches any user whose name is unknown, and matches any host whose name or address are unknown. This pattern should be used with care: host names may be
+ unavailable due to temporary name server problems. A network address will be unavailable when the software cannot figure out what type of network it is
+ talking to.</td></tr>
+<tr><td><b>KNOWN</b></td><td>Matches any user whose name is known, and matches any host whose name and address are known. This pattern should be used with care: host names may be
+ unavailable due to temporary name server problems. A network address will be unavailable when the software cannot figure out what type of network it is
+ talking to.</td></tr>
+<tr><td><b>PARANOID</b></td><td>
+ Matches any host whose name does not match its address. When tcpd is built with -DPARANOID (default mode), it drops requests from such clients even
+ before looking at the access control tables. Build without -DPARANOID when you want more control over such requests.</td></tr>
+</table>
+
+<h3>Operators</h3>
+<b>EXCEPT</b> Intended use is of the form: 'list_1 EXCEPT list_2'; this construct matches anything that matches list_1 unless it matches list_2. The EXCEPT operator
+ can be used in daemon_lists and in client_lists. The EXCEPT operator can be nested: if the control language would permit the use of parentheses, 'a EXCEPT
+ b EXCEPT c' would parse as '(a EXCEPT (b EXCEPT c))'.
+
+<h3>Shell Commands</h3>
+ If the first-matched access control rule contains a shell command, that command is subjected to %<letter> substitutions (see next section). The result is exe-
+ cuted by a /bin/sh child process with standard input, output and error connected to /dev/null. Specify an '&' at the end of the command if you do not want to
+ wait until it has completed.<p />
+
+ Shell commands should not rely on the PATH setting of the inetd. Instead, they should use absolute path names, or they should begin with an explicit PATH=what-
+ ever statement.
+<h3>% Expansions</h3>
+The following expansions are available within shell commands:
+<table>
+<tr><td>%a (%A)</td><td>The client (server) host address.</td></tr>
+<tr><td>%c</td><td>Client information: user@host, user@address, a host name, or just an address, depending on how much information is available.</td></tr>
+<tr><td>%d</td><td>The daemon process name (argv[0] value).</td></tr>
+<tr><td>%h (%H)</td><td>The client (server) host name or address, if the host name is unavailable.</td></tr>
+<tr><td>%n (%N)</td><td>The client (server) host name (or "unknown" or "paranoid").</td></tr>
+<tr><td>%p</td><td>The daemon process id.</td></tr>
+<tr><td>%s</td><td>Server information: daemon@host, daemon@address, or just a daemon name, depending on how much information is available.</td></tr>
+<tr><td>%u</td><td>The client user name (or "unknown").</td></tr>
+<tr><td>%%</td><td>Expands to a single '%? character.</td></tr>
+</table>
+Characters in % expansions that may confuse the shell are replaced by underscores.
+
+<hr />
--- /dev/null
+<header>TCP Wrappers</header>
+
+<h3>Introduction</h3>
+This module uses a simple access control language that is based on client (host name/address, user name), and server (process name, host name/address)
+patterns.<p />
+An extended version of the access control language is described in the hosts_options(5) document. The extensions are turned on at program build time by building
+with -DPROCESS_OPTIONS.
+
+<h3>Access Control Files</h3>
+The access control software consults two files. The search stops at the first match:
+<ul>
+<li>Access will be granted when a (daemon,client) pair matches an entry in the /etc/hosts.allow file.</li>
+<li>Otherwise, access will be denied when a (daemon,client) pair matches an entry in the /etc/hosts.deny file.</li>
+<li>Otherwise, access will be granted.</li>
+</ul>
+A non-existing access control file is treated as if it were an empty file. Thus, access control can be turned off by providing no access control files.
+
+
+<hr />
--- /dev/null
+#!/usr/local/bin/perl
+# index.cgi
+
+require './tcpwrappers-lib.pl';
+
+&ui_print_header(undef, $text{'index_title'}, "", "intro", 1, 1);
+
+# ALLOWED HOSTS & DENIED HOSTS
+foreach my $type ('allow', 'deny') {
+ my $file = $type eq 'allow' ? $config{'hosts_allow'} : $config{'hosts_deny'};
+ @rules = &list_rules($file);
+ print "<font size=+1>".($type eq 'allow' ? $text{'index_allowtitle'} : $text{'index_denytitle'})."</font><p />\n";
+ if (@rules) {
+ print &ui_form_start("delete_rules.cgi", "post");
+ print &ui_hidden($type, 1),"\n";
+ print &select_all_link("d"),"\n";
+ print &select_invert_link("d"),"\n";
+ print "<a href='edit_rule.cgi?$type=1&new=1'>$text{'index_add'}</a><br />\n";
+
+ @tds = ( "width=5" );
+ print &ui_columns_start([
+ "",
+ $text{'index_service'},
+ $text{'index_hosts'},
+ $text{'index_cmd'},
+ ], "width=100%", 0, \@tds);
+ foreach my $r (@rules) {
+ print &ui_checked_columns_row([
+ "<a href='edit_rule.cgi?$type=1&id=$r->{'id'}'>$r->{'service'}</a>",
+ $r->{'host'},
+ $r->{'cmd'} ? join("<br>", split /:/, $r->{'cmd'}) : $text{'index_none'},
+ ], \@tds, "d", $r->{'id'});
+ }
+ print &ui_columns_end();
+
+ print &select_all_link("d"),"\n";
+ print &select_invert_link("d"),"\n";
+ print "<a href='edit_rule.cgi?$type=1&new=1'>$text{'index_add'}</a><br />\n";
+ print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]);
+ } else {
+ if (-r $file) {
+ print "<b>".&text('index_norule', $file)."</b><br />\n";
+ print "<a href='edit_rule.cgi?$type=1&new=1'>$text{'index_add'}</a><p />\n";
+ } else {
+ print "<br>".&text('index_nofile', $file)."</b><p />\n";
+ }
+ }
+ print "<hr />\n" if ($type eq 'allow');
+}
+
+&ui_print_footer("/", $text{'index_return'});
--- /dev/null
+index_title=TCP Wrappers
+index_return=index
+index_allowtitle=Povolený pøístup
+index_denytitle=Zakázaný pøístup
+index_norule=Soubor '$1' neobsahuje ¾ádná pravidla.
+index_nofile=Soubor '$1' neexistuje - zkontrolujte va¹i <a href="/config.cgi?tcpwrappers">konfiguraci modulu</a>
+index_add=Pøidat pravidlo
+index_service=Démon
+index_hosts=Klienti
+index_cmd=Pøíkaz
+index_delete=Smazat oznaèené
+index_none=není
+
+edit_title1=Vytvoøit pravidlo
+edit_title2=Upravit pravidlo
+edit_eid=Pravidlo nebylo nalezeno
+edit_header=Nastavení pravidla
+edit_service=Démoni
+edit_hosts=Klienti
+edit_cmd=Pøíkazy
+edit_efound=Démon '$1' nebyl nalezen v konfiguraci xinetd.
+
+save_errtitle=Chyba pøi ukládání pravidla
+save_ehost=Klient obsahuje nepovolené znaky
+save_ecmd=Pøíkaz obsahuje nepovolené znaky
+
+del_errtitle=Chyba pøi mazání pravidla
+del_enone=Není oznaèeno ¾ádné pravidlo
--- /dev/null
+index_title=TCP Wrappers
+index_return=index
+index_allowtitle=Allowed hosts
+index_denytitle=Denied hosts
+index_norule=File '$1' doesn't contain any rules.
+index_nofile=File '$1' doesn't exist - check your <a href="/config.cgi?tcpwrappers">module configuration</a>
+index_add=Add rule
+index_service=Daemon
+index_hosts=Hosts
+index_cmd=Command
+index_delete=Delete Selected
+index_none=none
+
+edit_title1=Create rule
+edit_title2=Edit rule
+edit_eid=This rule was not found
+edit_header=Rule options
+edit_service=Service
+edit_hosts=Hosts
+edit_cmd=Shell commands
+edit_efound=Daemon '$1' was not found in xinetd configuration.
+
+save_errtitle=Error on save rule
+save_ehost=Host input contains bad characters
+save_ecmd=Command input contains bad characters
+save_eservice=Daemon names contain bad characters
+
+del_errtitle=Error on rules delete
+del_enone=No rules marked to delete
--- /dev/null
+name=tcpwrappers
+desc=TCP Wrappers
+category=net
+version=0.3
+longdesc=Configure the TCP wrappers networking access control files
--- /dev/null
+#!/usr/local/bin/perl
+# Create, update or delete a rule
+
+require './tcpwrappers-lib.pl';
+&ReadParse();
+&error_setup($text{'save_errtitle'});
+$file = $in{'allow'} ? $config{'hosts_allow'} : $config{'hosts_deny'};
+@rules = &list_rules($file);
+
+if (!$in{'new'}) {
+ ($rule) = grep { $_->{'id'} == $in{'id'} } @rules;
+ $rule || &error($text{'edit_eid'});
+}
+
+&lock_file($file);
+if ($in{'delete'}) {
+ # Delete one rule
+ &delete_rule($file, $rule);
+} else {
+ # Check input
+ &error($text{'save_eservice'}) if ($in{'service_custom'} && $in{'service_custom'} !~ /^[\w\d\s\-\/\.,]+$/);
+ &error($text{'save_eservice'}) if ($in{'service_except_custom'} && $in{'service_except_custom'} !~ /^[\w\d\s\-\/\.,]+$/);
+
+ &error($text{'save_ehost'}) if ($in{'host_text_def'} == 0 && $in{'host_text'} !~ /^[\w\d\s\-\/\@\.,]+$/);
+ &error($text{'save_ehost'}) if ($in{'host_except'} && $in{'host_except'} !~ /^[\w\d\s\-\/\@\.,]+$/);
+
+ for (my $i = 0; $i <= $in{'cmd_count'}; $i++) {
+ &error($text{'save_ecmd'}) if ($in{'cmd_'.$i} && $in{'cmd_'.$i} !~ /^[\w\d\s\-\/\@\%\|\(\)\'\"\&\.,]+$/);
+ }
+
+}
+
+# Build rule record
+if ($in{'service_custom'}) {
+ $service = $in{'service_custom'}." EXCEPT ".$in{'service_except_custom'};
+} else {
+ # listed from (x)inetd
+ $service = join(",", split /\0/, $in{'service'});
+ if ($in{'service_except'}) {
+ $service .= " EXCEPT ".join(",", split /\0/, $in{'service_except'});
+ }
+}
+
+$host = $in{'host_text_def'} ? $in{'host_select'} : $in{'host_text'};
+if ($in{'host_except'}) {
+ $host .= " EXCEPT ".$in{'host_except'};
+}
+
+$cmd = '';
+for (my $i = 0; $i <= $in{'cmd_count'}; $i++) {
+ next unless ($in{'cmd_'.$i});
+ $cmd .= $cmd ? " : " : '';
+ $cmd .= $in{'cmd_directive_'.$i} ne 'none' ? $in{'cmd_directive_'.$i}.' ' : '';
+ $cmd .= $in{'cmd_'.$i};
+}
+
+my %newrule = ( 'service' => $service,
+ 'host' => $host,
+ 'cmd' => $cmd
+ );
+
+# Save to file
+if ($in{'new'}) {
+ &create_rule($file, \%newrule);
+} else {
+ &modify_rule($file, $rule, \%newrule);
+}
+
+&unlock_file($file);
+&webmin_log($in{'new'} ? "create" : $in{'delete'} ? "delete" : "modify", "rule", $rule->{'id'});
+&redirect("");
--- /dev/null
+# tcpwrappers-lib.pl
+# Library for TCP Wrappers
+
+do '../web-lib.pl';
+&init_config();
+do '../ui-lib.pl';
+
+# list_rules($filename)
+# Parse rules from /etc/hosts.*
+# File format described in "man 5 hosts_access"
+sub list_rules {
+ my $file = shift;
+ my @ret;
+ my $id = 0;
+
+ open(HOSTS, $file) || return ();
+ my $line;
+ my $last_line = '';
+ my $lnum = 0;
+ while ($line = <HOSTS>) {
+ my ($slnum, $elnum) = ($lnum, $lnum);
+ s/\r|\n//g;
+
+ while ($line =~ /^(.*)\\/) {
+ # Continuation line! Read the next one and append it
+ local $before = $1;
+ local $nxt = <HOSTS>;
+ $nxt =~ s/\r|\n//g;
+ $line = $before.$nxt;
+ $elnum++; $lnum++;
+ }
+
+ if ($line =~ /^\#(.*)/) {
+ # Comment
+ $cmt = $cmt ? $cmt."\n".$1 : $1;
+ } elsif ($line =~ /^\s*$/) {
+ $cmt = undef;
+ } else {
+ my @cmtlines = split(/\n/, $cmt);
+ $cmt = undef;
+ my ($service, $host, $cmd) = split /:/, $line, 3;
+ $service =~ s/^\s*//; $service =~ s/\s*$//;
+ $host =~ s/^\s*//; $host =~ s/\s*$//;
+
+ push @ret, { 'id' => $id++,
+ 'service' => $service,
+ 'host' => $host,
+ 'cmd' => $cmd,
+ 'line' => $slnum-scalar(@cmtlines),
+ 'eline' => $elnum
+ };
+ }
+ $lnum++;
+ }
+ close FILE;
+
+ return @ret;
+}
+
+# list_services()
+# List system services from (x)inetd or return ()
+sub list_services {
+ my @ret;
+
+ if (&foreign_installed("xinetd")) {
+ &foreign_require("xinetd", "xinetd-lib.pl");
+ my @conf = &foreign_call('xinetd', 'get_xinetd_config');
+ foreach $x (@conf) {
+ next if ($x->{'quick'}{'server'}[0] !~ /\/([^\/]+)$/);
+ push @ret, $1;
+ }
+ } elsif (&foreign_installed("inetd")) {
+ &foreign_require("inetd", "inetd-lib.pl");
+ my @conf = &foreign_call('inetd', 'list_inets');
+ foreach $x (@conf) {
+ next unless ($x->[9] =~ /^(\S+)/);
+ push @ret, $1;
+ }
+ }
+
+ return &unique(@ret);
+}
+
+# delete_rule($filename, &rule)
+# Removes one rule entry from the file
+sub delete_rule {
+ my ($filename, $rule) = @_;
+
+ my $lref = &read_file_lines($filename);
+ my $len = $rule->{'eline'} - $rule->{'line'} + 1;
+ splice(@$lref, $rule->{'line'}, $len);
+ &flush_file_lines($filename);
+}
+
+# create_rule($filename, &rule)
+# Adds new rule
+sub create_rule {
+ my ($file, $rule) = @_;
+
+ my $lref = &read_file_lines($file);
+ my $newline = $rule->{'service'}.' : '.$rule->{'host'}.($rule->{'cmd'} ? ' : '.$rule->{'cmd'} : '');
+ push(@$lref, $newline);
+ &flush_file_lines($file);
+}
+
+# modify_rule($filename, &old_rule, &new_rule)
+# Updates rule
+sub modify_rule {
+ my ($filename, $oldrule, $newrule) = @_;
+
+ my @newline = ($newrule->{'service'}.' : '.$newrule->{'host'}.($newrule->{'cmd'} ? ' : '.$newrule->{'cmd'} : ''));
+
+ my $lref = &read_file_lines($filename);
+ my $len = $oldrule->{'eline'} - $oldrule->{'line'} + 1;
+ splice(@$lref, $oldrule->{'line'}, $len, @newline);
+ &flush_file_lines($filename);
+}
+
+1;
syswrite $fh, $str, length($str);
}
+
# check_ipaddress(ip)
# Check if some IP address is properly formatted
sub check_ipaddress
# Check if some IP address is properly formatted for IPv6
sub check_ip6address
{
-local @blocks = split(/:/, $_[0]);
-return 0 if (@blocks == 0 || @blocks > 8);
-local $b;
-local $empty = 0;
-foreach $b (@blocks) {
- return 0 if ($b ne "" && $b !~ /^[0-9a-f]{1,4}$/i);
- $empty++ if ($b eq "");
- }
-return 0 if ($empty > 1 && !($_[0] =~ /^::/ && $empty == 2));
-return 1;
+ local @blocks = split(/:/, $_[0]);
+ return 0 if (@blocks == 0 || @blocks > 8);
+
+ # The address/netmask format is accepted. So we're looking for a "/" to isolate a possible netmask.
+ # After that, we delete the netmask to control the address only format, but we verify whether the netmask
+ # value is in [0;128].
+ local $ib = $#blocks;
+ local $where = index($blocks[$ib],"/");
+ local $m=0;
+ if ($where != -1) {
+ local $b = substr($blocks[$ib],0,$where);
+ $m = substr($blocks[$ib],$where+1,length($blocks[$ib])-($where+1));
+ $blocks[$ib]=$b;
+ }
+
+ # The netmask must take its value in [0;128]
+ return 0 if ($m <0 || $m >128);
+
+ # Check the different blocks of the address : 16 bits block in hexa notation.
+ # Possibility of 1 empty block or 2 if the address begins with "::".
+ local $b;
+ local $empty = 0;
+ foreach $b (@blocks) {
+ return 0 if ($b ne "" && $b !~ /^[0-9a-f]{1,4}$/i);
+ $empty++ if ($b eq "");
+ }
+ return 0 if ($empty > 1 && !($_[0] =~ /^::/ && $empty == 2));
+ return 1;
}
+
+
# generate_icon(image, title, link, [href], [width], [height],
# [before-title], [after-title])
# Prints HTML for an icon image