Class: Yast::SuSEFirewallServicesClass

Inherits:
Module
  • Object
show all
Includes:
Logger
Defined in:
../../src/modules/SuSEFirewallServices.rb

Constant Summary

DEFINED_BY_PKG_PREFIX =

this is how services defined by package are distinguished

"service:"
SERVICES_DIR =
"/etc/sysconfig/SuSEfirewall2.d/services/"
SERVICES_TEXTDOMAIN =

please, check it with configuration in refresh-srv-def-by-pkgs-trans.sh script

"firewall-services"
DEFAULT_SERVICE =
{
  "tcp_ports"       => [],
  "udp_ports"       => [],
  "rpc_ports"       => [],
  "ip_protocols"    => [],
  "broadcast_ports" => [],
  "name"            => "",
  "description"     => ""
}
READ_ONLY_SERVICE_FEATURES =
["name", "description"]
IGNORED_SERVICES =
["TEMPLATE", "..", "."]
TEMPLATE_SERVICE_NAME =
"template service"
TEMPLATE_SERVICE_DESCRIPTION =
"opens ports for foo in order to allow bar"

Instance Method Summary (collapse)

Instance Method Details

- (Object) all_services

Returns all known services loaded from disk on-the-fly



362
363
364
365
# File '../../src/modules/SuSEFirewallServices.rb', line 362

def all_services
  ReadServicesDefinedByRPMPackages() if @services.nil?
  @services
end

- (String) GetDescription(service)

Function returns description of a firewall service

Parameters:

  • service (String)

Returns:

  • (String)

    service description



554
555
556
# File '../../src/modules/SuSEFirewallServices.rb', line 554

def GetDescription(service)
  service_details(service)["description"] || []
end

- (String) GetFilenameFromServiceDefinedByPackage(service)

Creates a file name from service name defined by package. Service MUST be defined by package, otherwise it returns 'nil'.

GetFilenameFromServiceDefinedByPackage (“service:abc”) -> “abc” GetFilenameFromServiceDefinedByPackage (“abc”) -> nil

Parameters:

  • service (String)

    name (e.g., 'service:abc')

Returns:

  • (String)

    file name (e.g., 'abc')



290
291
292
293
294
295
296
297
# File '../../src/modules/SuSEFirewallServices.rb', line 290

def GetFilenameFromServiceDefinedByPackage(service)
  if !ServiceDefinedByPackage(service)
    log.error "Service #{service} is not defined by package"
    return nil
  end

  service[/\A#{DEFINED_BY_PKG_PREFIX}(.*)/, 1]
end

- (Array<String>) GetListOfServicesAddedByPackage

Returns list of service-ids defined by packages.

Returns:

  • (Array<String>)

    service ids



514
515
516
# File '../../src/modules/SuSEFirewallServices.rb', line 514

def GetListOfServicesAddedByPackage
  all_services.keys
end

- (Yast::Term) GetMetadataAgent(filefullpath)

Returns SCR Agent definition.

Parameters:

  • string

    full filename path (to read by this agent)

Returns:

  • (Yast::Term)

    with agent definition



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File '../../src/modules/SuSEFirewallServices.rb', line 303

def GetMetadataAgent(filefullpath)
  term(
    :IniAgent,
    filefullpath,

    "options"  => [
      "global_values",
      "flat",
      "read_only",
      "ignore_case_regexps"
    ],
    "comments" => [
      # jail followed by anything but jail (immediately)
      "^[ \t]*#[^#].*$",
      # comments that are not commented key:value pairs (see "params")
      # they always use two jails
      "^[ \t]*##[ \t]*[^([a-zA-Z0-9_]+:.*)]$",
      # comments with three jails and more
      "^[ \t]*###.*$",
      # jail alone
      "^[ \t]*#[ \t]*$",
      # (empty space)
      "^[ \t]*$",
      # sysconfig entries
      "^[ \t]*[a-zA-Z0-9_]+.*"
    ],
    "params"   => [
      # commented key:value pairs
      # e.g.: ## Name: service name
      { "match" => ["^##[ \t]*([a-zA-Z0-9_]+):[ \t]*(.*)[ \t]*$", "%s: %s"] }
    ]

  )
end

- (Boolean) GetModified

Returns whether configuration was modified

Returns:

  • (Boolean)

    modified



575
576
577
# File '../../src/modules/SuSEFirewallServices.rb', line 575

def GetModified
  @sfws_modified
end

- (Array<String>) GetNeededBroadcastPorts(service)

Function returns needed ports allowing broadcast

Parameters:

  • service (String)

Returns:

  • (Array<String>)

    of needed broadcast ports



583
584
585
# File '../../src/modules/SuSEFirewallServices.rb', line 583

def GetNeededBroadcastPorts(service)
  service_details(service)["broadcast_ports"] || []
end

- (Array<String>) GetNeededIPProtocols(service)

Function returns needed IP protocols for service

Parameters:

  • service (String)

Returns:

  • (Array<String>)

    of needed IP protocols



546
547
548
# File '../../src/modules/SuSEFirewallServices.rb', line 546

def GetNeededIPProtocols(service)
  service_details(service)["ip_protocols"] || []
end

- (Hash{String => Array<String>}) GetNeededPortsAndProtocols(service)

Function returns needed ports and protocols for service. Service needs to be known (installed in the system). Function throws an exception SuSEFirewalServiceNotFound if service is not known (undefined).

GetNeededPortsAndProtocols (“service:aaa”) -> $[ “tcp_ports” : [ “122”, “ftp-data” ], “udp_ports” : [ “427” ], “rpc_ports” : [ “portmap”, “ypbind” ], “ip_protocols” : [], “broadcast_ports” : [ “427” ], ];

Parameters:

  • service (String)

Returns:

  • (Hash{String => Array<String>})

    of needed ports and protocols



603
604
605
# File '../../src/modules/SuSEFirewallServices.rb', line 603

def GetNeededPortsAndProtocols(service)
  DEFAULT_SERVICE.merge(service_details(service))
end

- (Array<String>) GetNeededRPCPorts(service)

Function returns needed RPC ports for service

Parameters:

  • service (String)

Returns:

  • (Array<String>)

    of needed RPC ports



538
539
540
# File '../../src/modules/SuSEFirewallServices.rb', line 538

def GetNeededRPCPorts(service)
  service_details(service)["rpc_ports"] || []
end

- (Array<String>) GetNeededTCPPorts(service)

Function returns needed TCP ports for service

Parameters:

  • service (String)

Returns:

  • (Array<String>)

    of needed TCP ports



522
523
524
# File '../../src/modules/SuSEFirewallServices.rb', line 522

def GetNeededTCPPorts(service)
  service_details(service)["tcp_ports"] || []
end

- (Array<String>) GetNeededUDPPorts(service)

Function returns needed UDP ports for service

Parameters:

  • service (String)

Returns:

  • (Array<String>)

    of needed UDP ports



530
531
532
# File '../../src/modules/SuSEFirewallServices.rb', line 530

def GetNeededUDPPorts(service)
  service_details(service)["udp_ports"] || []
end

- (Array<String>) GetPossiblyConflictServices

Function returns list of possibly conflicting services. Conflicting services are for instance nis-client and nis-server. DEPRECATED - we currently don't have such services - services are defined by packages.

Returns:

  • (Array<String>)

    of conflicting services



723
724
725
# File '../../src/modules/SuSEFirewallServices.rb', line 723

def GetPossiblyConflictServices
  []
end

- (Hash{String => String}) GetSupportedServices

Function returns the map of supported (known) services.

Structure:

	

Returns:

  • (Hash{String => String})

    supported services



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File '../../src/modules/SuSEFirewallServices.rb', line 492

def GetSupportedServices
  supported_services = {}

  all_services.each do |service_id, service_definition|
    Ops.set(
      supported_services,
      service_id,
      # TRANSLATORS: Name of unknown service. %1 is a requested service id like nis-server
      Ops.get_string(
        service_definition,
        "name",
        Builtins.sformat(_("Unknown service '%1'"), service_id)
      )
    )
  end

  deep_copy(supported_services)
end

- (Boolean) IsKnownService(service_id)

Function returns if the service_id is a known (defined) service

Parameters:

  • service_id (String)

Returns:

  • (Boolean)

    if is known (defined)



475
476
477
# File '../../src/modules/SuSEFirewallServices.rb', line 475

def IsKnownService(service_id)
  !service_details(service_id, true).nil?
end

- (Object) main



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File '../../src/modules/SuSEFirewallServices.rb', line 71

def main
  textdomain "base"

  Yast.import "FileUtils"

  #
  # IF YOU NEED TO ADD ANOTHER SERVICE, CREATE THE SERVICE DEFINITION
  # IN A FILE AND ADD IT TO THE PACKAGE TO WHICH IT BELONGS.
  # USE /etc/sysconfig/SuSEfirewall2.d/services/TEMPLATE FOR THAT.
  #
  # MORE INFORMATION IN FEATURE #300687: Ports for SuSEfirewall added via packages.
  # ANOTHER REFERENCE: Bugzilla #246911.
  #
  # See also http://kobliha-suse.blogspot.cz/2008/06/firewall-services-defined-by-packages.html
  #
  #
  # Names assigned to Port and Protocol numbers can be found
  # here:
  #
  # http://www.iana.org/assignments/protocol-numbers
  # http://www.iana.org/assignments/port-numbers
  #
  # Format of SERVICES
  #
  #   "service-id" : $[
  #     "name"            : _("Service Name"),
  #     "tcp_ports"       : list <tcp_ports>,
  #     "udp_ports"       : list <udp_ports>,
  #     "rpc_ports"       : list <rpc_ports>,
  #     "ip_protocols"    : list <ip_protocols>,
  #     "broadcast_ports" : list <broadcast_ports>,
  #   ],
  #
  @services = nil

  # firewall needs restarting
  @sfws_modified = false

  @known_services_features = {
    "TCP"       => "tcp_ports",
    "UDP"       => "udp_ports",
    "RPC"       => "rpc_ports",
    "IP"        => "ip_protocols",
    "BROADCAST" => "broadcast_ports"
  }

  @known_metadata = { "Name" => "name", "Description" => "description" }

  # Services definitions for conversion to the new ones.
  @OLD_SERVICES = {
    "http"         => {
      "tcp_ports"  => ["http"],
      "convert_to" => ["service:apache2", "service:lighttpd"]
    },
    "https"        => {
      "tcp_ports"  => ["https"],
      "convert_to" => ["service:apache2-ssl", "service:lighttpd-ssl"]
    },
    "smtp"         => { "tcp_ports" => ["smtp"], "convert_to" => [] },
    "pop3"         => { "tcp_ports" => ["pop3"], "convert_to" => [] },
    "pop3s"        => { "tcp_ports" => ["pop3s"], "convert_to" => [] },
    "imap"         => {
      "tcp_ports"  => ["imap"],
      "convert_to" => ["service:courier-imapd"]
    },
    "imaps"        => {
      "tcp_ports"  => ["imaps"],
      "convert_to" => ["service:courier-imap-ssl"]
    },
    "samba-server" => {
      "tcp_ports"       => ["netbios-ssn", "microsoft-ds"],
      # TCP: 139, 445
      "udp_ports"       => ["netbios-ns", "netbios-dgm"],
      # UDP: 137, 138
      "broadcast_ports" => ["netbios-ns", "netbios-dgm"],
      # UDP: 137, 138
      "convert_to"      => []
    },
    "ssh"          => {
      "tcp_ports"  => ["ssh"],
      "convert_to" => ["service:sshd"]
    },
    "rsync"        => { "tcp_ports" => ["rsync"], "convert_to" => [] },
    "dhcp-server"  => {
      "udp_ports"       => ["bootps"],
      "broadcast_ports" => ["bootps"],
      "convert_to"      => ["service:dhcp-server"]
    },
    "dhcp-client"  => { "udp_ports" => ["bootpc"], "convert_to" => [] },
    "dns-server"   => {
      "tcp_ports"  => ["domain"],
      "udp_ports"  => ["domain"],
      "convert_to" => ["service:bind"]
    },
    "nfs-client"   => {
      "rpc_ports"  => ["portmap", "status", "nlockmgr"],
      "convert_to" => ["service:nfs-client"]
    },
    "nfs-server"   => {
      "rpc_ports"  => [
        "portmap",
        "status",
        "nlockmgr",
        "mountd",
        "nfs",
        "nfs_acl"
      ],
      "convert_to" => []
    },
    "nis-client"   => {
      "rpc_ports"  => ["portmap", "ypbind"],
      "convert_to" => ["service:ypserv"]
    },
    "nis-server"   => {
      "rpc_ports"  => [
        "portmap",
        "ypserv",
        "fypxfrd",
        "ypbind",
        "yppasswdd"
      ],
      "convert_to" => []
    },
    # Default SUSE installation
    "vnc"          => {
      "tcp_ports"  => ["5801", "5901"],
      "convert_to" => []
    },
    "tftp"         => { "udp_ports" => ["tftp"], "convert_to" => [] },
    # Internet Printing Protocol as a Server
    "ipp-tcp"      => {
      "tcp_ports"  => ["ipp"],
      "convert_to" => []
    },
    # Internet Printing Protocol as a Client
    # IPP Client needs to listen for broadcast messages
    "ipp-udp"      => {
      "udp_ports"       => ["ipp"],
      "broadcast_ports" => ["ipp"],
      "convert_to"      => []
    },
    "ntp-server"   => {
      "udp_ports"       => ["ntp"],
      "broadcast_ports" => ["ntp"],
      "convert_to"      => ["service:ntp"]
    },
    "ldap"         => {
      "tcp_ports"  => ["ldap"],
      "convert_to" => ["service:openldap"]
    },
    "ldaps"        => { "tcp_ports" => ["ldaps"], "convert_to" => [] },
    "ipsec"        => {
      "udp_ports"    => ["isakmp", "ipsec-nat-t"],
      "ip_protocols" => ["esp"],
      "convert_to"   => []
    },
    "slp-daemon"   => {
      "tcp_ports"       => ["svrloc"],
      "udp_ports"       => ["svrloc"],
      "broadcast_ports" => ["svrloc"],
      "convert_to"      => []
    },
    # See bug #118200 for more information
    "xdmcp"        => {
      "tcp_ports"       => ["xdmcp"],
      "udp_ports"       => ["xdmcp"],
      "broadcast_ports" => ["xdmcp"],
      "convert_to"      => []
    },
    # See bug #118196 for more information
    "fam"          => {
      "rpc_ports"  => ["sgi_fam"],
      "convert_to" => []
    },
    # requested by thofmann
    "open-pbs"     => {
      # /etc/services says: The following entries are invalid, but needed
      "tcp_ports"  => [
        "pbs",
        "pbs_mom",
        "pbs_resmom",
        "pbs_sched"
      ],
      "udp_ports"  => ["pbs_resmom"],
      "convert_to" => []
    },
    "mysql-server" => {
      "tcp_ports"  => ["mysql"],
      "convert_to" => ["service:mysql"]
    },
    "iscsi-server" => {
      "tcp_ports"  => ["iscsi-target"],
      "convert_to" => ["service:iscsitarget"]
    }
  }
end

- (Boolean) ReadServicesDefinedByRPMPackages

Reads definition of services that can be used in FW_CONFIGURATIONS_ in SuSEfirewall2.

Returns:

  • (Boolean)

    if successful



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File '../../src/modules/SuSEFirewallServices.rb', line 371

def ReadServicesDefinedByRPMPackages
  log.info "Reading SuSEfirewall2 services from #{SERVICES_DIR}"
  @services ||= {}

  if !FileUtils.Exists(SERVICES_DIR) ||
      !FileUtils.IsDirectory(SERVICES_DIR)
    log.error "Cannot read #{SERVICES_DIR}"
    return false
  end

  all_definitions = SCR.Read(path(".target.dir"), SERVICES_DIR)
  all_definitions.reject! do |service|
    IGNORED_SERVICES.include?(service)
  end

  service_name = nil
  filefullpath = nil

  # for all files in that directory
  Builtins.foreach(all_definitions) do |filename|
    # "service:abc_server" to distinguis between dynamic definition and the static one
    service_name = DEFINED_BY_PKG_PREFIX + filename
    # Do not read already known services
    next unless @services[service_name].nil?

    filefullpath = SERVICES_DIR + filename
    @services[service_name] = {}

    # Registering sysconfig agent for this file
    if !SCR.RegisterAgent(
      path(".firewall_service_definition"),
      term(:ag_ini, term(:SysConfigFile, filefullpath))
      )
      log.error "Cannot register agent for #{filefullpath}"
      next
    end

    definition = nil
    definition_values = nil

    Builtins.foreach(@known_services_features) do |known_feature, map_key|
      definition = Convert.to_string(
        SCR.Read(
          Builtins.add(path(".firewall_service_definition"), known_feature)
        )
      )
      definition = "" if definition.nil?
      # map of services contains list of entries
      definition_values = Builtins.splitstring(definition, " \t\n")
      definition_values = Builtins.filter(definition_values) do |one_value|
        one_value != ""
      end
      @services[service_name][map_key] = definition_values
    end

    # Unregistering sysconfig agent for this file
    SCR.UnregisterAgent(path(".firewall_service_definition"))

    # Fallback for presented service
    @services[service_name]["name"] = _("Service: %{filename}") % { filename: filename }
    @services[service_name]["description"] = ""

    # Registering sysconfig agent for this file (to get metadata)
    if SCR.RegisterAgent(
      path(".firewall_service_metadata"),
      term(:ag_ini, GetMetadataAgent(filefullpath))
      )
      Builtins.foreach(@known_metadata) do |, |
        definition = Convert.to_string(
          SCR.Read(
            Builtins.add(
              path(".firewall_service_metadata"),
              
            )
          )
        )
        next if definition.nil? || definition.empty?
        # call gettext to translate the metadata
        @services[service_name][] = Builtins.dgettext(SERVICES_TEXTDOMAIN, definition)

        # bnc#893583: Sanitize metadata, do not allow using texts from template service
        case 
        when "name"
          @services[service_name][] = filename if definition == TEMPLATE_SERVICE_NAME
        when "description"
          @services[service_name][] = "" if definition == TEMPLATE_SERVICE_DESCRIPTION
        end
      end

      SCR.UnregisterAgent(path(".firewall_service_metadata"))
    else
      log.error "Cannot register agent for #{filefullpath} (metadata)"
    end
  end

  log.info "Services found: #{@services.keys.sort}"

  true
end

- (Object) ResetModified

Sets that configuration was not modified



566
567
568
569
570
# File '../../src/modules/SuSEFirewallServices.rb', line 566

def ResetModified
  @sfws_modified = false

  nil
end

- (Object) service_details(service_name, silent = false)

Returns service definition. See @services for the format. If silent is not defined or set to true, function throws an exception SuSEFirewalServiceNotFound if service is not found on disk.

Parameters:

  • service (String)

    name

  • (optional) (String)

    whether to silently return nil when service is not found (default false)



346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File '../../src/modules/SuSEFirewallServices.rb', line 346

def service_details(service_name, silent = false)
  service = all_services[service_name]
  if service.nil? && !silent
    log.error "Uknown service '#{service_name}'"
    log.info "Known services: #{all_services.keys}"

    raise(
      SuSEFirewalServiceNotFound,
      _("Service with name '%{service_name}' does not exist") % { service_name: service_name }
    )
  end

  service
end

- (Boolean) ServiceDefinedByPackage(service)

Returns whether the service ID is defined by package. Returns 'false' if it isn't.

ServiceDefinedByPackage (“http-server”) -> false ServiceDefinedByPackage (“service:http-server”) -> true

Parameters:

  • service (String)

Returns:

  • (Boolean)

    whether service is defined by package



277
278
279
# File '../../src/modules/SuSEFirewallServices.rb', line 277

def ServiceDefinedByPackage(service)
  service.start_with? DEFINED_BY_PKG_PREFIX
end

- (Object) SetModified

Sets that configuration was modified



559
560
561
562
563
# File '../../src/modules/SuSEFirewallServices.rb', line 559

def SetModified
  @sfws_modified = true

  nil
end

- (Boolean) SetNeededPortsAndProtocols(service, store_definition)

Immediately writes the configuration of service defined by package to the service definition file. Service must be defined by package, this function doesn't work for hard-coded services (SuSEFirewallServices). Function throws an exception SuSEFirewalServiceNotFound if service is not known (undefined) or it is not a service defined by package.

SetNeededPortsAndProtocols ( “service:something”, $[ “tcp_ports” : [ “22”, “ftp-data”, “400:420” ], “udp_ports” : [ ], “rpc_ports” : [ “portmap”, “ypbind” ], “ip_protocols” : [ “esp” ], “broadcast_ports” : [ ], ] );

Parameters:

  • service (String)

    ID (e.g., “service:ssh”)

  • map (string, list <string>)

    of full service definition

Returns:

  • (Boolean)

    if successful (nil in case of developer's mistake)

See Also:

  • #IsKnownService()
  • #ServiceDefinedByPackage()


632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
# File '../../src/modules/SuSEFirewallServices.rb', line 632

def SetNeededPortsAndProtocols(service, store_definition)
  if !IsKnownService(service)
    log.error "Service #{service} is unknown"
    raise(
      SuSEFirewalServiceNotFound,
      _("Service with name '%{service_name}' does not exist") % { service_name: service }
    )
  end

  # create the filename from service name
  filename = GetFilenameFromServiceDefinedByPackage(service)
  if filename.nil? || filename == ""
    log.error "Can't operate with filename '#{filename}' created from '#{service}'"
    return false
  end

  # full path to the filename
  filefullpath = SERVICES_DIR + filename

  if !FileUtils.Exists(filefullpath)
    log.error "File '#{filefullpath}' doesn't exist"
    return false
  end

  # Registering sysconfig agent for that file
  if !SCR.RegisterAgent(
    path(".firewall_service_definition"),
    term(:ag_ini, term(:SysConfigFile, filefullpath))
    )
    log.error "Cannot register agent for #{filefullpath}"
    return false
  end

  ks_features_backward = Builtins.mapmap(@known_services_features) do |sysconfig_id, ycp_id|
    { ycp_id => sysconfig_id }
  end

  write_ok = true

  # we can have this service already in memory
  new_store_definition = deep_copy(store_definition)

  Builtins.foreach(store_definition) do |ycp_id, one_def|
    # Skipping read-only features
    next if READ_ONLY_SERVICE_FEATURES.include? ycp_id

    sysconfig_id = Ops.get(ks_features_backward, ycp_id)
    if sysconfig_id.nil?
      log.error "Unknown key '#{ycp_id}'"
      write_ok = false
      next
    end
    one_def = Builtins.filter(one_def) do |one_def_item|
      !one_def_item.nil? && one_def_item != "" &&
        !Builtins.regexpmatch(one_def_item, "^ *$")
    end
    service_entry_path = Path.new(".firewall_service_definition.#{sysconfig_id}")
    service_entry_value = one_def.join(" ")
    if !SCR.Write(service_entry_path, service_entry_value)
      log.error "Cannot write #{service_entry_value} to #{service_entry_path}",
        write_ok = false
      next
    end
    # new definition of the service
    Ops.set(new_store_definition, ycp_id, one_def)
  end

  # flush the cache to the disk
  if write_ok
    if !SCR.Write(path(".firewall_service_definition"), nil)
      log.error "Cannot write to disk!"
      write_ok = false
    else
      # not only store to disk but also to the memory
      @services[service] = new_store_definition
      SetModified()
    end
  end

  # Unregistering sysconfig agent for that file
  SCR.UnregisterAgent(path(".firewall_service_definition"))

  log.info "Call SetNeededPortsAndProtocols(#{service}, ...) result is #{write_ok}"
  write_ok
end