diff options
author | Havoc Pennington <hp@redhat.com> | 2003-08-18 15:27:33 +0000 |
---|---|---|
committer | Havoc Pennington <hp@redhat.com> | 2003-08-18 15:27:33 +0000 |
commit | 95717a938b237d12211935f6a7467ef610288fe5 (patch) | |
tree | 9182521c86f31e74ad642eb19b431a433859c85f /bus | |
parent | 7c3693a53b4eba0db1aebe1edab5ded21eb7757f (diff) |
2003-08-17 Havoc Pennington <hp@pobox.com>
This doesn't compile yet, but syncing up so I can hack on it from
work. What are branches for if not broken code? ;-)
* dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add
DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER,
DBUS_HEADER_FIELD_ERROR_NAME
* dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use
for the interface+member pairs
(string_hash): change to use g_str_hash algorithm
(find_direct_function, find_string_function): refactor these to
share most code.
* dbus/dbus-message.c: port all of this over to support
interface/member fields instead of name field
* dbus/dbus-object-registry.c: port over
* dbus/dbus-string.c (_dbus_string_validate_interface): rename
from _dbus_string_validate_name
* bus/dbus-daemon-1.1: change file format for the
<deny>/<allow> stuff to match new message naming scheme
* bus/policy.c: port over
* bus/config-parser.c: parse new format
Diffstat (limited to 'bus')
-rw-r--r-- | bus/bus.c | 33 | ||||
-rw-r--r-- | bus/config-parser.c | 188 | ||||
-rw-r--r-- | bus/connection.c | 26 | ||||
-rw-r--r-- | bus/dispatch.c | 47 | ||||
-rw-r--r-- | bus/policy.c | 76 | ||||
-rw-r--r-- | bus/policy.h | 12 |
6 files changed, 270 insertions, 112 deletions
@@ -870,20 +870,21 @@ bus_context_check_security_policy (BusContext *context, * the hello message to the bus driver */ if (recipient == NULL && - dbus_message_has_name (message, DBUS_MESSAGE_HELLO)) + dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) && + dbus_message_has_member (message, "Hello")) { _dbus_verbose ("security check allowing %s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); return TRUE; } else { _dbus_verbose ("security check disallowing non-%s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Client tried to send a message other than %s without being registered", - DBUS_MESSAGE_HELLO); + "Hello"); return FALSE; } @@ -934,9 +935,14 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this sender " "from sending this message to this recipient, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to sender policy\n"); return FALSE; } @@ -951,9 +957,14 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this recipient " "from receiving this message from this sender, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to recipient policy\n"); return FALSE; } @@ -966,7 +977,7 @@ bus_context_check_security_policy (BusContext *context, const char *dest = dbus_message_get_destination (message); dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The destination service \"%s\" has a full message queue", - dest ? dest : DBUS_SERVICE_DBUS); + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to full message queue\n"); return FALSE; } diff --git a/bus/config-parser.c b/bus/config-parser.c index c42278e1..471c67d8 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -816,11 +816,15 @@ append_rule_from_element (BusConfigParser *parser, dbus_bool_t allow, DBusError *error) { - const char *send; - const char *receive; + const char *send_interface; + const char *send_member; + const char *send_error; + const char *send_service; + const char *receive_interface; + const char *receive_member; + const char *receive_error; + const char *receive_service; const char *own; - const char *send_to; - const char *receive_from; const char *user; const char *group; BusPolicyRule *rule; @@ -829,57 +833,112 @@ append_rule_from_element (BusConfigParser *parser, attribute_names, attribute_values, error, - "send", &send, - "receive", &receive, + "send_interface", &send_interface, + "send_member", &send_member, + "send_error", &send_error, + "send_service", &send_service, + "receive_interface", &receive_interface, + "receive_member", &receive_member, + "receive_error", &receive_error, + "receive_service", &receive_service, "own", &own, - "send_to", &send_to, - "receive_from", &receive_from, "user", &user, "group", &group, NULL)) return FALSE; - if (!(send || receive || own || send_to || receive_from || - user || group)) + if (!(send_interface || send_member || send_error || send_service || + receive_interface || receive_member || receive_error || receive_service || + own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Element <%s> must have one or more attributes", element_name); return FALSE; } - - if (((send && own) || - (send && receive) || - (send && receive_from) || - (send && user) || - (send && group)) || - - ((receive && own) || - (receive && send_to) || - (receive && user) || - (receive && group)) || - - ((own && send_to) || - (own && receive_from) || - (own && user) || - (own && group)) || - ((send_to && receive_from) || - (send_to && user) || - (send_to && group)) || + if ((send_member && send_interface == NULL) || + (receive_member && receive_interface == NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "On element <%s>, if you specify a member you must specify an interface", + element_name); + return FALSE; + } + + /* Allowed combinations of elements are: + * + * base, must be all send or all receive: + * interface + * interface + member + * error + * + * base send_ can combine with send_service, + * base receive_ with receive_service + * + * user, group, own must occur alone + */ - ((receive_from && user) || - (receive_from && group)) || + if (((send_interface && send_error) || + (send_interface && receive_interface) || + (send_interface && receive_member) || + (send_interface && receive_error) || + (send_interface && receive_service) || + (send_interface && own) || + (send_interface && user) || + (send_interface && group)) || + + ((send_member && send_error) || + (send_member && receive_interface) || + (send_member && receive_member) || + (send_member && receive_error) || + (send_member && receive_service) || + (send_member && own) || + (send_member && user) || + (send_member && group)) || + + ((send_error && receive_interface) || + (send_error && receive_member) || + (send_error && receive_error) || + (send_error && receive_service) || + (send_error && own) || + (send_error && user) || + (send_error && group)) || + + ((send_service && receive_interface) || + (send_service && receive_member) || + (send_service && receive_error) || + (send_service && receive_service) || + (send_service && own) || + (send_service && user) || + (send_service && group)) || + + ((receive_interface && receive_error) || + (receive_interface && own) || + (receive_interface && user) || + (receive_interface && group)) || + + ((receive_member && receive_error) || + (receive_member && own) || + (receive_member && user) || + (receive_member && group)) || + + ((receive_error && own) || + (receive_error && user) || + (receive_error && group)) || + + ((own && user) || + (own && group)) || - (user && group)) + ((user && group))) { dbus_set_error (error, DBUS_ERROR_FAILED, "Invalid combination of attributes on element <%s>, " - "only send/send_to or receive/receive_from may be paired", + "only send_foo/send_service or receive_foo/receive_service may be paired", element_name); return FALSE; } - + rule = NULL; /* In BusPolicyRule, NULL represents wildcard. @@ -887,41 +946,60 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send || send_to) + if (send_interface || send_member || send_error || send_service) { rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; - - if (IS_WILDCARD (send)) - send = NULL; - if (IS_WILDCARD (send_to)) - send_to = NULL; - rule->d.send.message_name = _dbus_strdup (send); - rule->d.send.destination = _dbus_strdup (send_to); - if (send && rule->d.send.message_name == NULL) + if (IS_WILDCARD (send_interface)) + send_interface = NULL; + if (IS_WILDCARD (send_member)) + send_member = NULL; + if (IS_WILDCARD (send_error)) + send_error = NULL; + if (IS_WILDCARD (send_service)) + send_service = NULL; + + rule->d.send.interface = _dbus_strdup (send_interface); + rule->d.send.member = _dbus_strdup (send_member); + rule->d.send.error = _dbus_strdup (send_error); + rule->d.send.destination = _dbus_strdup (send_service); + if (send_interface && rule->d.send.interface == NULL) + goto nomem; + if (send_member && rule->d.send.member == NULL) goto nomem; - if (send_to && rule->d.send.destination == NULL) + if (send_error && rule->d.send.error == NULL) + goto nomem; + if (send_service && rule->d.send.destination == NULL) goto nomem; } - else if (receive || receive_from) + else if (receive_interface || receive_member || receive_error || receive_service) { rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); if (rule == NULL) goto nomem; - - if (IS_WILDCARD (receive)) - receive = NULL; - - if (IS_WILDCARD (receive_from)) - receive_from = NULL; - rule->d.receive.message_name = _dbus_strdup (receive); - rule->d.receive.origin = _dbus_strdup (receive_from); - if (receive && rule->d.receive.message_name == NULL) + if (IS_WILDCARD (receive_interface)) + receive_interface = NULL; + if (IS_WILDCARD (receive_member)) + receive_member = NULL; + if (IS_WILDCARD (receive_error)) + receive_error = NULL; + if (IS_WILDCARD (receive_service)) + receive_service = NULL; + + rule->d.receive.interface = _dbus_strdup (receive_interface); + rule->d.receive.member = _dbus_strdup (receive_member); + rule->d.receive.error = _dbus_strdup (receive_error); + rule->d.receive.origin = _dbus_strdup (receive_service); + if (receive_interface && rule->d.receive.interface == NULL) + goto nomem; + if (receive_member && rule->d.receive.member == NULL) + goto nomem; + if (receive_error && rule->d.receive.error == NULL) goto nomem; - if (receive_from && rule->d.receive.origin == NULL) + if (receive_service && rule->d.receive.origin == NULL) goto nomem; } else if (own) diff --git a/bus/connection.c b/bus/connection.c index e588039e..4df00bfd 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -972,10 +972,10 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) } /* d->name may be NULL, but that is OK */ - if (!dbus_message_set_name (message, DBUS_ERROR_NO_MEMORY) || + if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) || !dbus_message_set_destination (message, d->name) || !dbus_message_set_sender (message, - DBUS_SERVICE_DBUS)) + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { dbus_connection_free_preallocated_send (connection, preallocated); dbus_message_unref (message); @@ -1312,10 +1312,15 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * to check security policy since it was not done in * dispatch.c */ - _dbus_verbose ("Sending %s from driver\n", - dbus_message_get_name (message)); - - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + _dbus_verbose ("Sending %s %s %s from driver\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(no interface)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(no member)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(no error name)"); + + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) return FALSE; /* If security policy doesn't allow the message, we silently @@ -1337,11 +1342,16 @@ bus_transaction_send (BusTransaction *transaction, BusConnectionData *d; DBusList *link; - _dbus_verbose (" trying to add %s %s to transaction%s\n", + _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n", dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : dbus_message_get_reply_serial (message) != 0 ? "reply" : "message", - dbus_message_get_name (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", dbus_connection_get_is_connected (connection) ? "" : " (disconnected)"); diff --git a/bus/dispatch.c b/bus/dispatch.c index e8f0c9ba..934619f1 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -104,7 +104,7 @@ static DBusHandlerResult bus_dispatch (DBusConnection *connection, DBusMessage *message) { - const char *sender, *service_name, *message_name; + const char *sender, *service_name; DBusError error; BusTransaction *transaction; BusContext *context; @@ -126,14 +126,24 @@ bus_dispatch (DBusConnection *connection, /* Ref connection in case we disconnect it at some point in here */ dbus_connection_ref (connection); - + service_name = dbus_message_get_destination (message); - message_name = dbus_message_get_name (message); - - _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */ - _dbus_verbose ("DISPATCH: %s to %s\n", - message_name, service_name ? service_name : "peer"); +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + const char *interface_name, *member_name, *error_name; + + interface_name = dbus_message_get_interface (message); + member_name = dbus_message_get_member (message); + error_name = dbus_message_get_error_name (message); + + _dbus_verbose ("DISPATCH: %s %s %s to %s\n", + interface_name ? interface_name : "(no interface)", + member_name ? member_name : "(no member)", + error_name ? error_name : "(no error name)", + service_name ? service_name : "peer"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ /* If service_name is NULL, this is a message to the bus daemon, not * intended to actually go "on the bus"; e.g. a peer-to-peer @@ -142,7 +152,8 @@ bus_dispatch (DBusConnection *connection, */ if (service_name == NULL) { - if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0) + if (dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL) && + dbus_message_has_member (message, "Disconnect")) bus_connection_disconnected (connection); /* DBusConnection also handles some of these automatically, we leave @@ -182,7 +193,7 @@ bus_dispatch (DBusConnection *connection, service_name = dbus_message_get_destination (message); } - if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ + if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ { if (!bus_context_check_security_policy (context, connection, NULL, message, &error)) @@ -191,7 +202,7 @@ bus_dispatch (DBusConnection *connection, goto out; } - _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); + _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (!bus_driver_handle_message (connection, transaction, message, &error)) goto out; } @@ -679,7 +690,7 @@ check_hello_message (BusContext *context, message = NULL; message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -721,7 +732,7 @@ check_hello_message (BusContext *context, _dbus_verbose ("Received %s on %p\n", dbus_message_get_name (message), connection); - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -911,7 +922,7 @@ check_nonexistent_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -959,7 +970,7 @@ check_nonexistent_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1465,7 +1476,7 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -1519,7 +1530,7 @@ check_existent_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1673,7 +1684,7 @@ check_segfault_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -1722,7 +1733,7 @@ check_segfault_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? diff --git a/bus/policy.c b/bus/policy.c index 2f8e2ca3..3b3ceb4e 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -80,11 +80,15 @@ bus_policy_rule_unref (BusPolicyRule *rule) switch (rule->type) { case BUS_POLICY_RULE_SEND: - dbus_free (rule->d.send.message_name); + dbus_free (rule->d.send.interface); + dbus_free (rule->d.send.member); + dbus_free (rule->d.send.error); dbus_free (rule->d.send.destination); break; case BUS_POLICY_RULE_RECEIVE: - dbus_free (rule->d.receive.message_name); + dbus_free (rule->d.receive.interface); + dbus_free (rule->d.receive.member); + dbus_free (rule->d.receive.error); dbus_free (rule->d.receive.origin); break; case BUS_POLICY_RULE_OWN: @@ -680,8 +684,8 @@ bus_client_policy_optimize (BusClientPolicy *policy) /* The idea here is that if we have: * - * <allow send="foo"/> - * <deny send="*"/> + * <allow send_interface="foo.bar"/> + * <deny send_interface="*"/> * * (for example) the deny will always override the allow. So we * delete the allow. Ditto for deny followed by allow, etc. This is @@ -713,12 +717,16 @@ bus_client_policy_optimize (BusClientPolicy *policy) { case BUS_POLICY_RULE_SEND: remove_preceding = - rule->d.send.message_name == NULL && + rule->d.send.interface == NULL && + rule->d.send.member == NULL && + rule->d.send.error == NULL && rule->d.send.destination == NULL; break; case BUS_POLICY_RULE_RECEIVE: remove_preceding = - rule->d.receive.message_name == NULL && + rule->d.receive.interface == NULL && + rule->d.receive.member == NULL && + rule->d.receive.error == NULL && rule->d.receive.origin == NULL; break; case BUS_POLICY_RULE_OWN: @@ -791,16 +799,34 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } - if (rule->d.send.message_name != NULL) + if (rule->d.send.interface != NULL) { - if (!dbus_message_has_name (message, - rule->d.send.message_name)) + if (!dbus_message_has_interface (message, + rule->d.send.interface)) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } } - + else if (rule->d.send.member != NULL) + { + if (!dbus_message_has_member (message, + rule->d.send.member)) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + else if (rule->d.send.error != NULL) + { + if (!dbus_message_has_error_name (message, + rule->d.send.error)) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.send.destination != NULL) { /* receiver can be NULL for messages that are sent to the @@ -886,16 +912,34 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } - if (rule->d.receive.message_name != NULL) + if (rule->d.receive.interface != NULL) { - if (!dbus_message_has_name (message, - rule->d.receive.message_name)) + if (!dbus_message_has_interface (message, + rule->d.receive.interface)) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } } - + else if (rule->d.receive.member != NULL) + { + if (!dbus_message_has_member (message, + rule->d.receive.member)) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + else if (rule->d.receive.error != NULL) + { + if (!dbus_message_has_error_name (message, + rule->d.receive.error)) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.receive.origin != NULL) { /* sender can be NULL for messages that originate from the diff --git a/bus/policy.h b/bus/policy.h index 940085ee..2aa69aaf 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -54,15 +54,19 @@ struct BusPolicyRule { struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* any of these can be NULL meaning "any" */ + char *interface; + char *member; + char *error; char *destination; } send; struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* any of these can be NULL meaning "any" */ + char *interface; + char *member; + char *error; char *origin; } receive; |