diff --git a/setup/inc/class.setup_cmd_config.inc.php b/setup/inc/class.setup_cmd_config.inc.php new file mode 100644 index 0000000000..e430504aaf --- /dev/null +++ b/setup/inc/class.setup_cmd_config.inc.php @@ -0,0 +1,445 @@ + + * @package setup + * @copyright (c) 2007 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +/** + * setup command: create / change eGW configuration + */ +class setup_cmd_config extends setup_cmd +{ + /** + * Constructor + * + * @param string $domain string with domain-name or array with all arguments + * @param string $config_user=null user to config the domain (or header_admin_user) + * @param string $config_passwd=null pw of above user + * @param string $arguments=null array with command line argruments + * @param boolean $verbose=false if true, echos out some status information during the run + */ + function __construct($domain,$config_user=null,$config_passwd=null,$arguments=null,$verbose=false) + { + if (!is_array($domain)) + { + $domain = array( + 'domain' => $domain, + 'config_user' => $config_user, + 'config_passwd' => $config_passwd, + 'arguments' => $arguments, + 'verbose' => $verbose, + ); + } + //echo __CLASS__.'::__construct()'; _debug_array($domain); + admin_cmd::__construct($domain); + } + + /** + * run the command: write the configuration to the database + * + * @param boolean $check_only=false only run the checks (and throw the exceptions), but not the command itself + * @return string success message + * @throws Exception(lang('Wrong credentials to access the header.inc.php file!'),2); + * @throws Exception('header.inc.php not found!'); + */ + protected function exec($check_only=false) + { + if ($check_only && $this->remote_id) + { + return true; // can only check locally + } + // instanciate setup object and check authorisation + $this->check_setup_auth($this->config_user,$this->config_passwd,$this->domain); + + $this->check_installed($this->domain,15,$this->verbose); + + // fixing authtypes in self::$options + self::auth_types(true); + + $values = array(); + if ($this->arguments) // we have command line arguments + { + $save_ea_profile = $this->_parse_cli_arguments($values); + } + else + { + $save_ea_profile = $this->_parse_properties($values); + } + + // store the config + foreach($values as $name => $value) + { + self::$egw_setup->db->insert(self::$egw_setup->config_table,array( + 'config_value' => $value, + ),array( + 'config_app' => 'phpgwapi', + 'config_name' => $name, + ),__LINE__,__FILE__); + } + if (count($values)) + { + if ($save_ea_profile) $this->_save_ea_profile(); + + $this->restore_db(); + + return lang('Configuration changed.'); + } + $this->restore_db(); + + return lang('Nothing to change.'); + } + + /** + * Return or echo the most common config options + * + * @param boolean $echoit=false if true the config is additionally echo'ed out + * @return array with name => value pairs + */ + static function get_config($echoit=false) + { + self::$egw_setup->db->select(self::$egw_setup->config_table,'config_name,config_value',array( + 'config_app' => 'phpgwapi', + "(config_name LIKE '%\\_dir' OR (config_name LIKE 'mail%' AND config_name != 'mail_footer') OR config_name LIKE 'smtp\\_%' OR config_name LIKE 'ldap%' OR config_name IN ('webserver_url','system_charset','auth_type','account_repository'))", + ),__LINE__,__FILE__); + + $config = array(); + while (($row = self::$egw_setup->db->row(true))) + { + $config[$row['config_name']] = $row['config_value']; + } + if ($echoit) + { + echo lang('Current configuration:')."\n"; + foreach($config as $name => $value) + { + echo str_pad($name.':',22).$value."\n"; + } + } + return $config; + } + + /** + * Available options and allowed arguments + * + * @var array + */ + static $options = array( + '--config' => array(), // name=value,... + '--files-dir' => 'files_dir', + '--vfs-root-user' => 'vfs_root_user', + '--backup-dir' => 'backup_dir', + '--temp-dir' => 'temp_dir', + '--webserver-url' => 'webserver_url', + '--mailserver' => array( //server,{IMAP|IMAPS|POP|POPS},[domain],[{standard(default)|vmailmgr = add domain for mailserver login|email = use email of user (Standard Maildomain should be set)}] + 'mail_server', + array('name' => 'mail_server_type','allowed' => array('imap','imaps','pop3','pop3s'),'default'=>'imap'), + 'mail_suffix', + array('name' => 'mail_login_type','allowed' => array( + 'username (standard)' => 'standard', + 'username@domain (virtual mail manager)' => 'vmailmgr', + 'email (Standard Maildomain should be set)' => 'email', + ),'default'=>'standard'), + ), + '--cyrus' => array( + 'imapAdminUsername', + 'imapAdminPW', + array('name' => 'imapType','default' => 3), + array('name' => 'imapEnableCyrusAdmin','default' => 'yes'), + ), + '--sieve' => array( + array('name' => 'imapSieveServer','default' => 'localhost'), + array('name' => 'imapSievePort','default' => 2000), + array('name' => 'imapEnableSieve','default' => 'yes'), // null or yes + ), + '--postfix' => array( + array('name' => 'editforwardingaddress','allowed' => array('yes',null)), + array('name' => 'smtpType','default' => 2), + ), + '--smtpserver' => array( //smtp server,[smtp port],[smtp user],[smtp password] + 'smtp_server',array('name' => 'smtp_port','default' => 25),'smtp_auth_user','smtp_auth_passwd','' + ), + '--account-auth' => array( + array('name' => 'account_repository','allowed' => array('sql','ldap'),'default'=>'sql'), + array('name' => 'auth_type','allowed' => array('sql','ldap','mail','ads','http','sqlssl','nis','pam'),'default'=>'sql'), + array('name' => 'sql_encryption','allowed' => array('md5','blowfish_crypt','md5_crypt','crypt'),'default'=>'md5'), + 'check_save_password','allow_cookie_auth'), + '--ldap-host' => 'ldap_host', + '--ldap-root-dn' => 'ldap_root_dn', + '--ldap-root-pw' => 'ldap_root_pw', + '--ldap-context' => 'ldap_context', + '--ldap-search-filter' => 'ldap_search_filter', + '--ldap-group-context' => 'ldap_group_context', + '--allow-remote-admin' => 'allow_remote_admin', + '--install-id' => 'install_id', + ); + + /** + * Parses properties from this object + * + * @param array &$value contains set values on return + * @return boolean do we need to save the emailadmin profile + */ + private function _parse_properties(&$values) + { + $this->_merge_defaults(); + + $save_ea_profile = false; + $values = array(); + foreach(self::$options as $arg => $option) + { + foreach(is_array($option) ? $option : array($option) as $n => $data) + { + $name = is_array($data) ? $data['name'] : $data; + + if (isset($this->$name)) + { + $save_ea_profile |= $this->_parse_value($arg,$n,$option,$this->$name,$values); + } + } + } + return $save_ea_profile; + } + + /** + * Parses command line arguments in $this->arguments + * + * @param array &$value contains set values on return + * @return boolean do we need to save the emailadmin profile + */ + private function _parse_cli_arguments(&$values) + { + $arguments = $this->arguments; + $values = array(); + $save_ea_profile = false; + $args = $this->arguments; + while(($arg = array_shift($args))) + { + if (!isset(self::$options[$arg])) + { + throw new egw_exception_wrong_userinput(lang("Unknown option '%1' !!!",$arg),90); + } + $options = is_array(self::$options[$arg]) ? explode(',',array_shift($args)) : array(array_shift($args)); + + if ($arg == '--config') + { + foreach($options as $option) + { + list($name,$value) = explode('=',$option,2); + $values[$name] = $value; + } + continue; + } + $options[] = ''; $options[] = ''; + foreach($options as $n => $value) + { + $save_ea_profile |= $this->_parse_value($arg,$n,self::$options[$arg],$value,$values); + } + } + return $save_ea_profile; + } + + /** + * Parses a single value + * + * @param string $arg current cli argument processed + * @param int $n number of the property + * @param array/string $data string with type or array containing values for type, allowed + * @param mixed $value value to set + * @param array &$values where the values get set + */ + private function _parse_value($arg,$n,$data,$value,array &$values) + { + if ($value === '' && is_array($data) && !isset($data[$n]['default'])) return false; + + $name = is_array($data) || $n ? $data[$n] : $data; + + if (is_array($name)) + { + if (!$value && isset($name['default'])) $value = $name['default']; + + if (isset($name['allowed']) && !in_array($value,$name['allowed'])) + { + throw new egw_exception_wrong_userinput(lang("'%1' is not allowed as %2. arguments of option %3 !!!",$value,1+$n,$arg)." ($name[name])",91); + } + $name = $name['name']; + } + $values[$name] = $value; + + return in_array($arg,array('--mailserver','--smtpserver','--cyrus','--postfix','--sieve')); + } + + /** + * Updates the default EMailAdmin profile from the eGW config + */ + function _save_ea_profile($config=array()) + { + self::$egw_setup->db->select(self::$egw_setup->config_table,'config_name,config_value',array( + 'config_app' => 'phpgwapi', + "((config_name LIKE 'mail%' AND config_name != 'mail_footer') OR config_name LIKE 'smtp%' OR config_name LIKE 'imap%' OR config_name='editforwardingaddress')", + ),__LINE__,__FILE__); + while (($row = self::$egw_setup->db->row(true))) + { + $config[$row['config_name']] = $row['config_value']; + } + $config['smtpAuth'] = $config['smtp_auth_user'] ? 'yes' : null; + + $emailadmin = new emailadmin_bo(-1,false); // false=no session stuff + $emailadmin->setDefaultProfile($config); + + if ($this->verbose) + { + echo "\n".lang('EMailAdmin profile updated:')."\n"; + foreach($config as $name => $value) + { + echo str_pad($name.':',22).$value."\n"; + } + } + } + + /** + * Return the options from the $options array + * + * @return array with name => array(value=>label,...) pairs + */ + static function options() + { + $options = array(); + foreach(self::$options as $option) + { + if (is_array($option)) + { + foreach($option as $n => $data) + { + if (is_array($data) && isset($data['allowed'])) + { + if ($data['name'] == 'auth_type') + { + $options[$data['name']] = self::auth_types(); + continue; + } + foreach($data['allowed'] as $label => $value) + { + if (is_int($label)) + { + $label = (string) $value === '' ? 'No' : strtoupper($value); + } + $options[$data['name']][$value] = lang($label); + } + } + } + } + } + return $options; + } + + /** + * Read auth-types (existing auth backends) from filesystem and fix our $options array + * + * @return array + */ + static function auth_types() + { + // default backends in order of importance + static $auth_types = array( + 'sql' => 'SQL', + 'ldap' => 'LDAP', + 'mail' => 'Mail', + 'ads' => 'Active Directory', + 'http' => 'HTTP', + 'fallback' => 'Fallback LDAP --> SQL', + 'sqlssl' => 'SQL / SSL', + ); + static $scan_done; + if (!$scan_done++) + { + // now add auth backends found in filesystem + foreach(scandir(EGW_INCLUDE_ROOT.'/phpgwapi/inc') as $class) + { + if (preg_match('/^class\.auth_([a-z]+)\.inc\.php$/',$class,$matches) && + !isset($auth_types[$matches[1]])) + { + $auth_types[$matches[1]] = ucfirst($matches[1]); + } + } + foreach(self::$options['--account-auth'] as &$param) + { + if ($param['name'] == 'auth_type') + { + $param['allowed'] = array_keys($auth_types); + break; + } + } + } + return $auth_types; + } + + /** + * Return the defaults from the $options array + * + * @return array with name => $value pairs + */ + static function defaults() + { + $defaults = array(); + // fetch the default from the cli options + foreach(self::$options as $option) + { + if (is_array($option)) + { + foreach($option as $n => $data) + { + if (is_array($data) && isset($data['default'])) + { + $defaults[$data['name']] = $data['default']; + } + } + } + } + // some extra defaults for non-cli operation + $defaults['files_dir'] = '/var/lib/egroupware/$domain/files'; + $defaults['backup_dir'] = '/var/lib/egroupware/$domain/backup'; + $defaults['backup_mincount'] = 0; + $defaults['backup_files'] = false; + $defaults['temp_dir'] = '/tmp'; + $defaults['webserver_url'] = '/egroupware'; + $defaults['smtp_server'] = $defaults['mail_server'] = 'localhost'; + $defaults['mail_suffix'] = '$domain'; + $defaults['imapAdminUsername'] = 'cyrus@$domain'; + $defaults['imapAdminPW'] = self::randomstring(); + $defaults['imapType'] = 2; // standard IMAP + $defaults['smtpType'] = 1; // standard SMTP + + return $defaults; + } + + /** + * Merges the default into the current properties, if they are empty or contain placeholders + * + * Replacements like $domain, only work for values listed by self::defaults() + */ + private function _merge_defaults() + { + foreach(self::defaults() as $name => $default) + { + if (!$this->$name) + { + //echo "

setting $name='{$this->$name}' to it's default='$default'

\n"; + $this->set_defaults[$name] = $this->$name = $default; + } + if (strpos($this->$name,'$') !== false) + { + $this->$name = str_replace(array( + '$domain', + ),array( + $this->domain, + ),$this->$name); + } + } + } +} diff --git a/setup/inc/hook_config.inc.php b/setup/inc/hook_config.inc.php new file mode 100644 index 0000000000..a8a214d189 --- /dev/null +++ b/setup/inc/hook_config.inc.php @@ -0,0 +1,268 @@ + + * @author Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +/** + * Get the options for vfs_storage_mode, select the right one depending on vfs_fstab + * + * @param array $config + * @return string + */ +function vfs_storage_mode_options($config) +{ + if (!isset($config['vfs_fstab']) || $config['vfs_fstab'] == serialize(array( + '/' => 'sqlfs://$host/', + '/apps' => 'links://$host/apps', + ))) + { + $config['vfs_storage_mode'] = 'fs'; + } + elseif($config['vfs_fstab'] == serialize(array( + '/' => 'sqlfs://$host/?storage=db', + '/apps' => 'links://$host/apps?storage=db', + ))) + { + $config['vfs_storage_mode'] = 'db'; + } + else + { + $config['vfs_storage_mode'] = 'custom'; + } + //_debug_array(array_intersect_key($config,array('vfs_fstab'=>1,'vfs_storage_mode'=>1))); + foreach(array( + 'fs' => lang('Filesystem (default)'), + 'db' => lang('Database').' (problems with files > 1MB)', + 'custom' => lang('Custom set via %1','filemanager/cli.php mount'), + ) as $name => $label) + { + $options .= '' . "\n"; + $listed[] = $value; + } + } + if(!$found) + { + /* Something is wrong with their mcrypt install or php.ini */ + $out = '' . "\n";; + } + } + else + { + $out = '' . "\n";; + } + return $out; +} + +function encryptmode($config) +{ + if(@function_exists('mcrypt_list_modes')) + { + $listed = array(); + if(!isset($config['mcrypt_mode'])) + { + $config['mcrypt_mode'] = 'cbc'; /* MCRYPT_MODE_CBC */ + } + $modes = @mcrypt_list_modes(); + $found = False; + + $out = ''; + while(list($key,$value) = each($modes)) + { + $found = True; + /* Only show each once - seems this is a problem in some installs */ + if(!in_array($value,$listed)) + { + if($config['mcrypt_mode'] == $value) + { + $selected = ' selected="selected"'; + } + else + { + $selected = ''; + } + $descr = strtoupper($value); + + $out .= '' . "\n"; + $listed[] = $value; + } + } + if(!$found) + { + /* Something is wrong with their mcrypt install or php.ini */ + $out = '' . "\n"; + } + } + else + { + $out = '' . "\n"; + } + return $out; +} + +function passwdhashes($config) +{ + $hashes = array( + 'des' => 'des', + 'md5' => 'md5', + 'smd5' => 'smd5', + 'sha' => 'sha', + 'ssha' => 'ssha', + 'plain' => 'plain', + ); + /* Check for available crypt methods based on what is defined by php */ + if(@defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1) + { + $hashes['blowish_crypt'] = 'blowish_crypt'; + } + if(@defined('CRYPT_MD5') && CRYPT_MD5 == 1) + { + $hashes['md5_crypt'] = 'md5_crypt'; + } + if(@defined('CRYPT_EXT_DES') && CRYPT_EXT_DES == 1) + { + $hashes['ext_crypt'] = 'ext_crypt'; + } + + foreach($hashes as $key => $value) + { + if($config['ldap_encryption_type'] == $value) + { + $selected = ' selected="selected"'; + } + else + { + $selected = ''; + } + $descr = strtoupper($value); + + $out .= '' . "\n"; + } + return $out; +} + +function sql_passwdhashes($config) +{ + $hashes = array( + 'md5' => 'md5' + ); + + /* Check for available crypt methods based on what is defined by php */ + if(@defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1) + { + $hashes['blowish_crypt'] = 'blowish_crypt'; + } + if(@defined('CRYPT_MD5') && CRYPT_MD5 == 1) + { + $hashes['md5_crypt'] = 'md5_crypt'; + } + if(@defined('CRYPT_EXT_DES') && CRYPT_EXT_DES == 1) + { + $hashes['ext_crypt'] = 'ext_crypt'; + } + if(@defined('CRYPT_STD_DES') && CRYPT_STD_DES == 1) + { + $hashes['crypt'] = 'crypt'; + } + + $hashes += array( + 'smd5' => 'smd5', + 'sha' => 'sha', + 'ssha' => 'ssha', + 'plain' => 'plain', + ); + + foreach($hashes as $key => $value) + { + if($config['sql_encryption_type'] == $value) + { + $selected = ' selected="selected"'; + } + else + { + $selected = ''; + } + $descr = strtoupper($value); + + $out .= '' . "\n"; + } + return $out; +} + +/** + * Make auth-types from setup_cmd_config available + * + * @param array $config + * @return string + */ +function auth_type($config) +{ + return _options_from(setup_cmd_config::auth_types(),$config['auth_type']); +} +function auth_type_syncml($config) +{ + return _options_from(setup_cmd_config::auth_types(),$config['auth_type_syncml']); +} +function auth_type_groupdav($config) +{ + return _options_from(setup_cmd_config::auth_types(),$config['auth_type_groupdav']); +} + +/** + * Returns options string + * + * @param array $options value => label pairs + * @param string $selected value of selected optino + * @return string + */ +function _options_from(array $options,$selected) +{ + foreach($options as $value => $label) + { + $out .= '' . "\n"; + } + return $out; +} diff --git a/setup/templates/default/config.tpl b/setup/templates/default/config.tpl new file mode 100644 index 0000000000..e942c2374b --- /dev/null +++ b/setup/templates/default/config.tpl @@ -0,0 +1,581 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 {title}
{lang_Path_information}, {lang_Virtual_filesystem}
{lang_Where_should_eGroupware_store_file_content}: + +
{lang_Don't_change,_if_you_already_stored_files!_You_will_loose_them!} There's currently no migration avaliable.
{lang_Enter_the_full_path_for_users_and_group_files.
Examples:_/files,_E:\FILES}
+ {lang_This_has_to_be_outside_the_webservers_document-root!!!}
+ {lang_If_you_can_only_access_the_docroot_choose_Database_for_where_to_store_the_file_content_AND_use_same_path_as_for_temporary_files.} +
{lang_Usernames_(comma-separated)_which_can_get_VFS_root_access_(beside_setup_user)}
{lang_Enter_the_full_path_to_the_backup_directory.
if_empty:_files_directory}/db_backup:
{lang_This_has_to_be_outside_the_webservers_document-root!!!}
{lang_Enter_the_full_path_for_temporary_files.
Examples:_/tmp,_C:\TEMP}:
{lang_Enter_the_location_of_eGroupWare's_URL.
Example:_http://www.domain.com/egroupware_ _or_ _/egroupware
No_trailing_slash}:
{lang_Image_type_selection_order}: + +
{lang_Complete_path_to_aspell_program}: + +
 
{lang_Host_information}
{lang_Enter_the_hostname_of_the_machine_on_which_this_server_is_running}:
{lang_Enter_your_default_FTP_server}:
{lang_Attempt_to_use_correct_mimetype_for_FTP_instead_of_default_'application/octet-stream'}: + +
{lang_Enter_your_HTTP_proxy_server}:
{lang_Enter_your_HTTP_proxy_server_port}:
{lang_Enter_your_HTTP_proxy_server_username}:
{lang_Enter_your_HTTP_proxy_server_password}:
 
{lang_Standard_mailserver_settings_(used_for_Mail_authentication_too)}:
{lang_POP/IMAP_mail_server_hostname_or_IP_address}:
{lang_Mail_server_protocol}: + +
{lang_Mail_server_login_type}: + +
{lang_Mail_domain_(for_Virtual_mail_manager)}:
{lang_SMTP_server_hostname_or_IP_address}:
{lang_SMTP_server_port}:
{lang_User_for_SMTP-authentication_(leave_it_empty_if_no_auth_required)}:
{lang_Password_for_SMTP-authentication}:
 
{lang_Authentication_/_Accounts}
{lang_Select_which_type_of_authentication_you_are_using}: + +
{lang_Authentication_type_for_application}: SyncML + +
{lang_Authentication_type_for_application}: GroupDAV/CalDAV/CardDAV + +
{lang_HTTP_auth_types_(comma-separated)_to_use_without_login-page, eg. "NTLM"}: + +
{lang_Select_where_you_want_to_store/retrieve_user_accounts}: + +
{lang_sql_encryption_type}: + +
{lang_Activate_safe_password_check}: + +
{lang_Allow_authentication_via_cookie}: + +
{lang_Auto_login_anonymous_user}: + +
{lang_Allow_password_migration}: + +
{lang_Allowed_migration_types_(comma-separated)}: + +
{lang_Minimum_account_id_(e.g._500_or_100,_etc.)}:
{lang_Maximum_account_id_(e.g._65535_or_1000000)}:
{lang_User_account_prefix}:
{lang_Usernames_are_casesensitive}: + +
{lang_Auto_create_account_records_for_authenticated_users}: + +
{lang_Auto-created_user_accounts_expire}: + +
{lang_Add_auto-created_users_to_this_group_('Default'_will_be_attempted_if_this_is_empty.)}:
{lang_If_no_ACL_records_for_user_or_any_group_the_user_is_a_member_of}: + +
 
{lang_If_using_LDAP}:
{lang_LDAP_host}:
{lang_LDAP_accounts_context}:
{lang_LDAP_search_filter_for_accounts,_default:_"(uid=%user)",_%domain=eGW-domain}:
{lang_LDAP_groups_context}:
{lang_LDAP_rootdn} {lang_(searching_accounts_and_changing_passwords)}:
{lang_LDAP_root_password}:
{lang_LDAP_encryption_type}: + +
{lang_Do_you_want_to_manage_homedirectory_and_loginshell_attributes?}: + +
{lang_LDAP_Default_homedirectory_prefix_(e.g._/home_for_/home/username)}:
{lang_LDAP_Default_shell_(e.g._/bin/bash)}:
{lang_Allow_usernames_identical_to_system_users?}: + +
+ {lang_Migration_between_eGroupWare_account_repositories}: + +
  • {lang_Account_repository_need_to_be_set_to_the_one_you_migrate_to!}
  • +
  • {lang_You_need_to_save_the_settings_you_made_here_first!}
  • +
    {lang_If_using_CAS_(Central_Authentication_Service):}
    {lang_CAS_server_host_name:
    Example:_sso-cas.univ-rennes1.fr}
    {lang_CAS_server_port:
    Example:_443}
    {lang_CAS_server_uri:}
    {lang_Authentification_mode:} + +
    {lang_SSL_validation:} + +
    {lang_Certificate_(PEM_or_CA):}
     
    {lang_If_using_ADS_(Active_Directory)_authentication}:
    {lang_Host/IP_Domain_controler}:
    {lang_Domain_name}:
     
    +   +
    + + +
    +
    + + +