From: Alan T. DeKok Date: Fri, 17 Jan 2025 15:57:10 +0000 (-0500) Subject: Use / require '@' in subrequest, when changing namespaces X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=74bb8b15e225d17050ed3bcff07413bfbe698d28;p=thirdparty%2Ffreeradius-server.git Use / require '@' in subrequest, when changing namespaces --- diff --git a/doc/antora/modules/reference/pages/unlang/subrequest.adoc b/doc/antora/modules/reference/pages/unlang/subrequest.adoc index fd75bd1c829..f06a0ce8ef0 100644 --- a/doc/antora/modules/reference/pages/unlang/subrequest.adoc +++ b/doc/antora/modules/reference/pages/unlang/subrequest.adoc @@ -11,26 +11,39 @@ subrequest { The `subrequest` keyword creates a child request. The child request is empty, and contains no attributes. Attributes in the child can be copied from the parent via xref:unlang/edit.adoc[editing] statements. -Please see the xref:unlang/list.adoc[list] syntax for a description of how to -refer to parent requests. +Please see the xref:unlang/list.adoc[list] syntax for a description of +how to refer to parent requests. The `subrequest` keyword allows the server to receive one type of -packet, and then to create a different type of packet. `subrequest` -is most commonly used in conjunction with the +packet, and then to create a different type of packet. For example, +receive a RADIUS `Accounting-Request`, and then create a child +`Disconnect-Request` to kick the user offline. The `subrequest` +keyword can also be used to change protocols. For example, receive a +DHCP `Discover` packet, and then send a RADIUS `Access-Request` packet +to see if the MAC address is authorized. + +`subrequest` is most commonly used in conjunction with the xref:unlang/call.adoc[call] keyword to change packet types or -protocols, and then run a different virtual server. See the -"Operation" section below for more information. +protocols, and then xref:unlang/call.adoc[call] a different virtual +server. See the "Operation" section below for more information. -:: The type of the child request being created. +:: The packet type of the child request being created. + -The __ field is a either an enumerated packet name such as `::Access-Request`, -or a protocol name followed by a packet name, such as -`dhcpv4::Discover`. Please see the protocol dictionaries for a -complete list of packet types for each protocol. +If the __ field is omitted, then a child request is created +using the same packet type as the current request. ++ +If the __ field contains a protocol reference such as `@dhcpv4`, +then this creates a new child request of a different protocol. The +rest of the __ field is then parsed to see what kind of packet +is created. ++ +The _ field is then parsed as an enumerated packet name such as +`::Access-Request`, Please see the protocol dictionaries for a +complete list of allowed packet types for each protocol. + The __ field cannot be a dynamic expansion. + -The _ field can, however, be an attribute reference. When an +As an exception, the __ field can be an attribute reference. When an attribute reference is used, the attribute must be of an integer type (8, 16, 32, or 64-bit), or of type `string`. Integer types are resolved to known / allowed values of the `Packet-Type` attribute. @@ -39,6 +52,10 @@ attribute. + When the __ field is an attribute reference, it is not possible to change the dictionary. ++ +We do not suggest using attribute references. The functionality will +be removed in a future release, and will be replaced with full support +for dynamic expansions. [ statements ]:: The `unlang` commands which will be executed. @@ -71,7 +88,7 @@ parsed in the context of the new protocol. .Example [source,unlang] ---- -subrequest dhcpv4::Discover { +subrequest @dhcpv4::Discover { &Your-IP-Address := &parent.request.Framed-IP-Address ... @@ -162,5 +179,5 @@ subrequest ::Disconnect-Request { } ---- -// Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0. +// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0. // This documentation was developed by Network RADIUS SAS. diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index d65889d5a62..a2a5402d956 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -3995,22 +3995,74 @@ static unlang_t *compile_subrequest(unlang_t *parent, unlang_compile_t *unlang_c return NULL; } + dict = unlang_ctx->rules->attr.dict_def; + + /* + * @foo is "dictionary foo", as with references in the dictionaries. + * + * @foo::bar is "dictionary foo, Packet-Type = ::bar" + * + * foo::bar is "dictionary foo, Packet-Type = ::bar" + * + * ::bar is "this dictionary, Packet-Type = ::bar", BUT + * we don't try to parse the new dictionary name, as it + * doesn't exist. + */ + if ((name2[0] == '@') || + ((name2[0] != ':') && (name2[0] != '&') && (strchr(name2 + 1, ':') != NULL))) { + char *q; + + if (name2[0] == '@') name2++; + + MEM(namespace = talloc_strdup(parent, name2)); + q = namespace; + + while (fr_dict_attr_allowed_chars[(unsigned int) *q]) { + q++; + } + *q = '\0'; + + dict = fr_dict_by_protocol_name(namespace); + if (!dict) { + dict_ref = fr_dict_autoload_talloc(NULL, &dict, namespace); + if (!dict_ref) { + cf_log_err(cs, "Unknown namespace in '%s'", name2); + talloc_free(namespace); + return NULL; + } + } + + /* + * Skip the dictionary name, and go to the thing + * right after it. + */ + name2 += (q - namespace); + TALLOC_FREE(namespace); + } + /* + * @dict::enum is "other dictionary, Packet-Type = ::enum" * ::enum is this dictionary, "Packet-Type = ::enum" */ if ((name2[0] == ':') && (name2[1] == ':')) { - dict = unlang_ctx->rules->attr.dict_def; packet_name = name2; goto get_packet_type; } /* - * If !tmpl_require_enum_prefix, '&' means "attribute reference". + * Can't do foo.bar.baz::foo, the enums are only used for Packet-Type. + */ + if (strchr(name2, ':') != NULL) { + cf_log_err(cs, "Reference cannot contain enum value in '%s'", name2); + return NULL; + } + + /* + * '&' means "attribute reference" * - * Or, bare word means "attribute reference". + * Or, bare word an require_enum_prefix means "attribute reference". */ - if ((name2[0] == '&') || - (tmpl_require_enum_prefix && ((p = strchr(name2, ':')) == NULL))) { + if ((name2[0] == '&') || tmpl_require_enum_prefix) { ssize_t slen; slen = tmpl_afrom_attr_substr(parent, NULL, &vpt, @@ -4045,47 +4097,19 @@ static unlang_t *compile_subrequest(unlang_t *parent, unlang_compile_t *unlang_c } /* - * subrequest foo::bar { ... } - * - * Change to dictionary "foo", packet type "bar". - */ - if (p) { - if (p[1] != ':') { - cf_log_err(cs, "Invalid syntax in namespace::enum"); - return NULL; - } - - MEM(namespace = talloc_strdup(parent, name2)); /* get a modifiable copy */ - - p = namespace + (p - name2); - *p = '\0'; - p += 2; - packet_name = p; - - dict = fr_dict_by_protocol_name(namespace); - if (!dict) { - dict_ref = fr_dict_autoload_talloc(NULL, &dict, namespace); - if (!dict_ref) { - cf_log_err(cs, "Unknown namespace '%s'", namespace); - talloc_free(namespace); - return NULL; - } - } - - goto get_packet_type; - } - - /* - * subrequest foo { ... } - * - * Change packet types without changing dictionaries. + * foo.bar without '&' and NOT require_enum_prefix is fugly, we should disallow it. */ p = strchr(name2, '.'); if (!p) { + cf_log_warn(cs, "Please upgrade configuration to use '::%s' when changing packet types", + name2); + dict = unlang_ctx->rules->attr.dict_def; packet_name = name2; - } else if (!tmpl_require_enum_prefix) { + } else { + cf_log_warn(cs, "Please upgrade configuration to use '@' when changing dictionaries"); + /* * subrequest foo.bar { ... } * @@ -4109,14 +4133,6 @@ static unlang_t *compile_subrequest(unlang_t *parent, unlang_compile_t *unlang_c WARN("Deprecated syntax 'subrequest %s ...'", name2); WARN(" please switch to 'subrequest %s::%s ...", namespace, packet_name); - - } else { - /* - * We have tmpl_require_enum prefix, so bare word foo.bar is "attribute foo, - * sub-attribute bar" - */ - dict = unlang_ctx->rules->attr.dict_def; - packet_name = name2; } /* diff --git a/src/tests/modules/cache_rbtree/cache-not-radius.unlang b/src/tests/modules/cache_rbtree/cache-not-radius.unlang index 11ae7260b0c..89cb2d257f7 100644 --- a/src/tests/modules/cache_rbtree/cache-not-radius.unlang +++ b/src/tests/modules/cache_rbtree/cache-not-radius.unlang @@ -1,7 +1,7 @@ # Verify that the cache update and key sections work with foreign attributes -subrequest dhcpv4.Discover { - subrequest radius.Access-Request { +subrequest @dhcpv4::Discover { + subrequest @radius::Access-Request { caller dhcpv4 { &parent.Gateway-IP-Address = 127.0.0.1 &parent.control.Your-IP-Address = 127.0.0.2