]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add and document ENUM
authorAlan T. DeKok <aland@freeradius.org>
Sat, 18 Sep 2021 13:56:44 +0000 (09:56 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 18 Sep 2021 14:05:49 +0000 (10:05 -0400)
we'll add more complex tests later

man/man5/dictionary.5
src/lib/util/dict_tokenize.c

index 74a6387fa0ecc7b90dcef128a1923e49a9d3aa37..ac4d7822bd1ea065747ba5214f21d5cb5f7c6909 100644 (file)
 .RE
 .sp
 ..
-.TH dictionary 5 "09 Oct 2020"
+.TH dictionary 5 "18 Sep 2021"
 .SH NAME
-dictionary \- RADIUS dictionary file
+dictionary \- FreeRADIUS dictionary file
 .SH DESCRIPTION
-The master RADIUS dictionary file resides in
-\fI/etc/raddb/dictionary\fP.  It references other \fIdictionary\fP
-files located in \fI/usr/local/share/freeradius/\fP.  Each dictionary
-file contains a list of RADIUS attributes and values, which the server
-uses to map between descriptive names and on-the-wire data.  The names
-have no meaning outside of the RADIUS server itself, and are never
-exchanged between server and clients.
+The local dictionary file resides in \fI/etc/raddb/dictionary\fP.  It
+references other \fIdictionary\fP files located in
+\fI/usr/local/share/freeradius/\fP.  Each dictionary file contains a
+list of protocol-specific attributes and values, which the server uses
+to map between descriptive names and on-the-wire data.  The names have
+no meaning outside of the server, and are never sent "on the wire"
+between server and clients.
 .PP
 That is, editing the dictionaries will have NO EFFECT on anything
 other than the server that is reading those files.  Adding new
-attributes to the dictionaries will have NO EFFECT on RADIUS clients,
-and will not make RADIUS clients magically understand those
-attributes.  The dictionaries are solely for local administrator
-convenience, and are specific to each version of FreeRADIUS.
+attributes to the dictionaries will have NO EFFECT on clients, and
+will not make clients magically understand those attributes.  The
+dictionaries are solely for local administrator convenience, and are
+specific to each version of FreeRADIUS.
 .PP
 The dictionaries in \fI/usr/local/share\fP SHOULD NOT be edited unless
 you know exactly what you are doing.  Changing them will most likely
-break your RADIUS deployment.
+break the FreeRADIUS system.
 .PP
 If you need to add new attributes, please edit the
 \fI/etc/raddb/dictionary\fP file.  It's sole purpose is to contain
@@ -127,11 +127,6 @@ definition is, however, accepted:
      long-extended use "long-extended" as a flag instead
      time         use "date" instead
 
-FreeRADIUS will accept a VALUE definition for any "base" data type.
-For example, you can define VALUEs for IP addresses, Ethernet
-addresses, etc.  VALUEs cannot be defined for "structural" data types
-such as struct, tlv, vsa, group, etc.
-
 The "struct" type is a compound type.  An attribute of data type
 "struct" can have multiple sub-attributes defined, just as with TLVs.
 Each sub-attribute has to be numbered sequentially, starting at 1.
@@ -148,8 +143,9 @@ This usage is no longer allowed.
 
 The options are:
 
-     encrypt=...    set encryption type 1, 2, or 3.
+     encrypt=...  set encryption type 1, 2, or 3.
      has_tag      The attribute can have an RFC 2868 style tag
+     clone=...    copy another attribute subtree
 
 The "encrypt" flag marks the attribute as being encrypted with one of
 three possible methods.  "1" means that the attribute is encrypted
@@ -164,12 +160,26 @@ tag, as defined in \fIRFC2868\fP.  The purpose of the tag is to allow
 grouping of attributes for tunneled users.  See \fIRFC2868\fP for
 more details.
 
-When the server receives an encoded attribute in a RADIUS packet, it
-looks up that attribute by number in the dictionary, and uses the
-definition found there for printing diagnostic and log messages.  When
-the server sees an attribute name in a configuration file, it looks up
-that attribute by name in the dictionary, and uses the definition
-found there.
+When the server receives an encoded attribute in a packet, it looks up
+that attribute by number in the dictionary, and uses the definition
+found there for printing diagnostic and log messages.  When the server
+sees an attribute name in a configuration file, it looks up that
+attribute by name in the dictionary, and uses the definition found
+there.
+
+.TP 0.5i
+.B ENUM name  type
+Define an enumerated type, which can contain VALUEs.
+
+The \fIname\fP field has the same definition as for an ATTRIBUTE.
+
+
+The \fItype\fP field has the same definition as for an attribute.
+
+The purpose of ENUM is to define a common set of VALUEs, which can be
+re-used across multiple ATTRIBUTEs.  Each ATTRIBUTE which needs to
+refer to an ENUM should set the "clone" flag, which refers to the ENUM
+name.  For example. "ATTRIBUTE foo 1 uint16 enum=name_of_enum".
 
 .TP 0.5i
 .B MEMBER name  type [flags]
@@ -201,9 +211,15 @@ be any non-space text, but is usually taken from \fIRFC2865\fP, or
 other documents..  The \fInumber\fP field is also taken from the
 relevant documents, for that name.
 
-When the server receives an encoded value in a RADIUS packet, it looks
-up the value of that attribute by number in the dictionary, and uses
-the name found there for printing diagnostic and log messages.
+When the server receives an encoded value in a packet, it looks up the
+value of that attribute by number in the dictionary, and uses the name
+found there for printing diagnostic and log messages.
+
+FreeRADIUS will accept a VALUE definition for any "base" data type.
+For example, you can define VALUEs for IP addresses, Ethernet
+addresses, etc.  VALUEs cannot be defined for "structural" data types
+such as struct, tlv, vsa, group, etc.
+
 .TP 0.5i
 .B VENDOR vendor-name number [format=...]
 Define a Vendor Specific Attribute encapsulation for \fIvendor-name\fP
index 914b74a191ecc6f16eb793833f8131237e6ec14d..e52a2643b05dea1abb0976e9f4d850a37be3606d 100644 (file)
@@ -485,6 +485,31 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type
                         */
                        *ref = talloc_strdup(ctx->fixup.pool, value);
 
+               } else if (strcmp(key, "enum") == 0) {
+                       /*
+                        *      Allow enum=... as a synonym for
+                        *      "clone".  We check the sources and not
+                        *      the targets, because that's easier.
+                        *
+                        *      Plus, ENUMs are really just normal attributes
+                        *      in disguise.
+                        */
+                       if (!value) {
+                               fr_strerror_const("Missing ENUM name for 'enum=...'");
+                               return -1;
+                       }
+
+                       switch (type) {
+                       case FR_TYPE_LEAF:
+                               break;
+
+                       default:
+                               fr_strerror_const("ENUM references be used for structural types");
+                               return -1;
+                       }
+
+                       *ref = talloc_strdup(ctx->fixup.pool, value);
+
                } else if (ctx->dict->subtype_table) {
                        int subtype;
 
@@ -909,6 +934,100 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
 }
 
 
+/*
+ *     Process the ENUM command
+ */
+static int dict_read_process_enum(dict_tokenize_ctx_t *ctx, char **argv, int argc,
+                                 fr_dict_attr_flags_t *base_flags)
+{
+       int                     attr = -1;
+       fr_type_t               type;
+       fr_dict_attr_flags_t    flags;
+       fr_dict_attr_t const    *parent, *da;
+
+       if (argc != 2) {
+               fr_strerror_const("Invalid ENUM syntax");
+               return -1;
+       }
+
+       /*
+        *      Dictionaries need to have real names, not shitty ones.
+        */
+       if (strncmp(argv[0], "Attr-", 5) == 0) {
+               fr_strerror_const("Invalid ENUM name");
+               return -1;
+       }
+
+       flags = *base_flags;
+
+       if (dict_process_type_field(ctx, argv[1], &type, &flags) < 0) return -1;
+
+       if (flags.extra && (flags.subtype == FLAG_BIT_FIELD)) {
+               fr_strerror_const("Bit fields can only be defined as a MEMBER of a STRUCT");
+               return -1;
+       }
+
+       switch (type) {
+       case FR_TYPE_LEAF:
+               break;
+
+       default:
+               fr_strerror_printf("ENUMs can only be a leaf type, not %s",
+                                  fr_table_str_by_value(fr_value_box_type_table, type, "?Unknown?"));
+               break;
+       }
+
+       parent = ctx->stack[ctx->stack_depth].da;
+       if (!parent) {
+               fr_strerror_const("Invalid location for ENUM");
+               return -1;
+       }
+
+       /*
+        *      ENUMs cannot have a flag field, so we don't parse that.
+        *
+        *      Maybe we do want a flag field for named time deltas?
+        */
+
+#ifdef __clang_analyzer__
+       if (!ctx->dict) return -1;
+#endif
+
+       /*
+        *      We have to call this first in order to allocate a
+        *      number for the attribute.
+        */
+       if (!dict_attr_fields_valid(ctx->dict, parent, argv[0], &attr, type, &flags)) return -1;
+
+       /*
+        *      Add in an attribute
+        */
+       if (fr_dict_attr_add(ctx->dict, parent, argv[0], attr, type, &flags) < 0) return -1;
+
+       /*
+        *      If we need to set the previous attribute, we have to
+        *      look it up by number.  This lets us set the
+        *      *canonical* previous attribute, and not any potential
+        *      duplicate which was just added.
+        */
+       da = dict_attr_child_by_num(parent, attr);
+       if (!da) {
+               fr_strerror_printf("Failed to find attribute '%s' we just added.", argv[0]);
+               return -1;
+       }
+
+#ifndef NDEBUG
+       if (!dict_attr_by_name(NULL, parent, argv[0])) {
+               fr_strerror_printf("Failed to find attribute '%s' we just added.", argv[0]);
+               return -1;
+       }
+#endif
+
+       memcpy(&ctx->value_attr, &da, sizeof(da));
+
+       return 0;
+}
+
 /*
  *     Process the MEMBER command
  */
@@ -1823,6 +1942,16 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                        continue;
                }
 
+               /*
+                *      Perhaps this is an enum.
+                */
+               if (strcasecmp(argv[0], "ENUM") == 0) {
+                       if (dict_read_process_enum(ctx,
+                                                       argv + 1, argc - 1,
+                                                       &base_flags) == -1) goto error;
+                       continue;
+               }
+
                /*
                 *      Process FLAGS lines.
                 */