From 7f9a78b2d468027642c76d2a3f346bc5ee992263 Mon Sep 17 00:00:00 2001 From: hickert Date: Wed, 2 Apr 2008 13:35:02 +0000 Subject: [PATCH] Updated sudo stuff git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@10117 594d385d-05f5-0310-b6e9-bd551577e9d8 --- .../plugins/admin/sudo/class_sudoGeneric.inc | 39 +++ .../admin/sudo/class_sudoManagement.inc | 10 +- .../plugins/admin/sudo/class_sudoOptions.inc | 249 ++++++++++++++++++ gosa-core/plugins/admin/sudo/options.tpl | 6 + 4 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 gosa-core/plugins/admin/sudo/class_sudoOptions.inc create mode 100644 gosa-core/plugins/admin/sudo/options.tpl diff --git a/gosa-core/plugins/admin/sudo/class_sudoGeneric.inc b/gosa-core/plugins/admin/sudo/class_sudoGeneric.inc index 158f9e7f5..bc11e3b8a 100644 --- a/gosa-core/plugins/admin/sudo/class_sudoGeneric.inc +++ b/gosa-core/plugins/admin/sudo/class_sudoGeneric.inc @@ -51,6 +51,45 @@ class sudo extends plugin $this->$attr = $tmp; } } + + /******* + Prepare Flags + *******/ + + $options = array(); + // BOOLEAN + $options[]=array("NAME"=>"long_otp_prompt" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"ignore_dot" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"mail_always" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"mail_badpass" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"mail_no_user" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"mail_no_host" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"mail_no_perms" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"tty_tickets" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"authenticate" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"root_sudo" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"log_host" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"log_year" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"shell_noargs" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"set_home" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"always_set_home" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"path_info" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"preserve_groups" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"fqdn" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"insults" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"requiretty" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"env_editor" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"rootpw" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"runaspw" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"targetpw" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"set_logname" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"stay_setuid" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"env_reset" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"use_loginclass" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"noexec" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + $options[]=array("NAME"=>"ignore_local_sudoers" , "TYPE"=>"BOOLEAN", "VALUE" => "1"); + + //STRINGS } function execute() diff --git a/gosa-core/plugins/admin/sudo/class_sudoManagement.inc b/gosa-core/plugins/admin/sudo/class_sudoManagement.inc index e9757df05..19db54eb4 100644 --- a/gosa-core/plugins/admin/sudo/class_sudoManagement.inc +++ b/gosa-core/plugins/admin/sudo/class_sudoManagement.inc @@ -405,15 +405,19 @@ class sudoManagement extends plugin $this->list = array(); $base = $this->base; - $Regex = $this->DivListSudo->Regex; - $UserRegex = $this->DivListSudo->UserRegex; + $Regex = trim($this->DivListSudo->Regex); + $UserRegex = trim($this->DivListSudo->UserRegex); $SubSearch = $this->DivListSudo->SubSearch; /******************** Create filter depending on selected checkboxes ********************/ $values = array("cn","description","sudoUser","sudoCommand","sudoOption"); - $ff = "(&(|(cn=".$Regex.")(description=".$Regex."))(sudoUser=".$UserRegex.")(objectClass=sudoRole))"; + if($UserRegex == "*"){ + $ff = "(&(|(cn=".$Regex.")(description=".$Regex."))(objectClass=sudoRole))"; + }else{ + $ff = "(&(|(cn=".$Regex.")(description=".$Regex."))(sudoUser=".$UserRegex.")(objectClass=sudoRole))"; + } $res = get_list($ff, "sudo",$base,$values, GL_SIZELIMIT); $tmp = array(); foreach($res as $attrs){ diff --git a/gosa-core/plugins/admin/sudo/class_sudoOptions.inc b/gosa-core/plugins/admin/sudo/class_sudoOptions.inc new file mode 100644 index 000000000..ce519a454 --- /dev/null +++ b/gosa-core/plugins/admin/sudo/class_sudoOptions.inc @@ -0,0 +1,249 @@ +$attr = array(); + if(isset($this->attrs[$attr])){ + $tmp = array(); + for($i = 0 ; $i < $this->attrs[$attr]['count']; $i++){ + $tmp[] = $this->attrs[$attr][$i]; + } + $this->$attr = $tmp; + } + } + + $options = array(); + $option[]= array('NAME' => 'long_otp_prompt' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'ignore_dot' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_always' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_badpass' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_user' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_host' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_perms' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'tty_tickets' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'authenticate' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'root_sudo' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'log_host' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'log_year' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'shell_noargs' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'set_home' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'always_set_home' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'path_info' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'preserve_groups' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'fqdn' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'insults' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'requiretty' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_editor' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'rootpw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'runaspw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'targetpw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'set_logname' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'stay_setuid' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_reset' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'use_loginclass' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'noexec' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'ignore_local_sudoers' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passwd_tries' , 'TYPE' => 'INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'loglinelen' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestamp_timeout' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passwd_timeout' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'umask' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailsub' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'badpass_message' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestampdir' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestampowner' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passprompt' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'runas_default' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog_goodpri' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog_badpri' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'editor' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'noexec_file' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'lecture' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'lecture_file' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'logfile' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailerpath' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailerflags' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailto' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'exempt_group' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'verifypw' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'listpw' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_check' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_delete' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_keep' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'long_otp_prompt' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'ignore_dot' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_always' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_badpass' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_user' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_host' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mail_no_perms' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'tty_tickets' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'authenticate' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'root_sudo' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'log_host' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'log_year' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'shell_noargs' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'set_home' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'always_set_home' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'path_info' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'preserve_groups' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'fqdn' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'insults' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'requiretty' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_editor' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'rootpw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'runaspw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'targetpw' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'set_logname' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'stay_setuid' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_reset' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'use_loginclass' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'noexec' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'ignore_local_sudoers' , 'TYPE' => 'BOOLEAN' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passwd_tries' , 'TYPE' => 'INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'loglinelen' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestamp_timeout' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passwd_timeout' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'umask' , 'TYPE' => 'BOOL_INTEGER' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailsub' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'badpass_message' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestampdir' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'timestampowner' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'passprompt' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'runas_default' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog_goodpri' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog_badpri' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'editor' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'noexec_file' , 'TYPE' => 'STRINGS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'lecture' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'lecture_file' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'logfile' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'syslog' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailerpath' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailerflags' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'mailto' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'exempt_group' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'verifypw' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'listpw' , 'TYPE' => 'STRING_BOOL' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_check' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_delete' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $option[]= array('NAME' => 'env_keep' , 'TYPE' => 'LISTS' , 'DEFAULT' => ''); + $this->options = $option; + } + + function execute() + { + /* Call parent execute */ + plugin::execute(); + + + /********************* + NEGATE values + *********************/ + foreach($_POST as $name => $value){ + if(preg_match("/^neg_/",$name)){ + $attr = preg_replace("/^neg_([^_]*)_.*$/","\\1",$name); + $value= preg_replace("/^neg_[^_]*_([0-9]*)_.*$/","\\1",$name); + + $attrs = $this->$attr; + if(isset( $attrs[$value])){ + $v = $attrs[$value]; + if(preg_match("/^!/",$v)){ + $attrs[$value] = preg_replace("/^!/","",$v); + }else{ + $attrs[$value] = "!".$v; + } + $this->$attr = $attrs; + } + break; // Do it once, image inputs will be posted twice + } + } + + /********************* + Delete values + *********************/ + foreach($_POST as $name => $value){ + if(preg_match("/^del_/",$name)){ + $attr = preg_replace("/^del_([^_]*)_.*$/","\\1",$name); + $value= preg_replace("/^del_[^_]*_([0-9]*)_.*$/","\\1",$name); + $attrs = $this->$attr; + if(isset( $attrs[$value])){ + unset($attrs[$value]); + $this->$attr = $attrs; + } + break; // Do it once, image inputs will be posted twice + } + } + + $smarty = get_smarty(); + $smarty->assign("map", array("STRINGS" => _("string"), "BOOLEAN" => _("bool"), + "INTEGER" => _("integer") , "BOOL_INTEGER" => _("integer")."-"._("bool") , + "STRING_BOOL" => _("string")."-"._("bool"),"LISTS" => _("lists"))); + $smarty->assign("sudoOption",$this->sudoOption); + $smarty->assign("options",$this->options); + return($smarty->fetch(get_template_path('options.tpl', TRUE))); + } + + function remove_from_parent() + { + } + + /* Save data to object */ + function save_object() + { + plugin::save_object(); + } + + /* Save to LDAP */ + function save() + { + plugin::save(); + $this->cleanup(); + $ldap = $this->config->get_ldap_link(); + $ldap->cd($this->config->current['BASE']); + $ldap->cd($this->dn); + $ldap->modify($this->attrs);; + } + + function check() + { + $message = plugin::check(); + return ($message); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/gosa-core/plugins/admin/sudo/options.tpl b/gosa-core/plugins/admin/sudo/options.tpl new file mode 100644 index 000000000..d04439664 --- /dev/null +++ b/gosa-core/plugins/admin/sudo/options.tpl @@ -0,0 +1,6 @@ + + -- 2.30.2