]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
allow dictionary to use $INCLUDE directory.d/
authorAlan T. DeKok <aland@freeradius.org>
Wed, 24 Sep 2025 14:38:26 +0000 (10:38 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 24 Sep 2025 15:07:56 +0000 (11:07 -0400)
doc/antora/modules/reference/pages/raddb/dictionary.adoc
raddb/dictionary
src/lib/util/dict_tokenize.c

index bd500e9d4adbc3bc03bfbf2977f9520f50758ab8..ea85f6210c23019b218b7017560fec6468adf86c 100644 (file)
@@ -156,6 +156,13 @@ This dictionary includes v3-compatible names like "Cleartext-Password",
 or "NT-Password".
 
 
+
+Any local dictionaries can be added in the `dictionary.d` subdirectory.
+
+The server will load all files in that directory, but will skip
+editor backup files, and others which are known to not be real files.
+
+
 == Default Configuration
 
 ```
@@ -167,6 +174,7 @@ or "NT-Password".
 #$INCLUDE ${dictdir}/radius/v3/dictionary.aruba
 #END-PROTOCOL RADIUS
 #$INCLUDE ${dictdir}/freeradius/v3/dictionary.freeradius.internal
+$INCLUDE- dictionary.d/
 ```
 
 // Copyright (C) 2025 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
index d5e88c3c57c767f642207faa055082a481cd4e90..93e86c628628b51de894d9e9885afb56f2191c42 100644 (file)
 #  or "NT-Password".
 #
 #$INCLUDE ${dictdir}/freeradius/v3/dictionary.freeradius.internal
+
+#
+#  Any local dictionaries can be added in the `dictionary.d` subdirectory.
+#
+#  The server will load all files in that directory, but will skip
+#  editor backup files, and others which are known to not be real files.
+#
+$INCLUDE- dictionary.d/
index 28c7b6d0292e44dc2be0c4f7d547d35397f9da91..0a093f48c59057315a3489b0653a95866fe4e6c4 100644 (file)
@@ -1163,10 +1163,13 @@ static int dict_read_process_common(dict_tokenize_ctx_t *dctx, fr_dict_attr_t **
 static int dict_read_process_include(dict_tokenize_ctx_t *dctx, char **argv, int argc, char const *dir)
 {
        int rcode;
+       bool required = true;
        int stack_depth = dctx->stack_depth;
        char *src_file = dctx->filename;
        int src_line = dctx->line;
-       char *filename;
+       char *pattern;
+       char const *filename;
+       fr_globdir_iter_t iter;
 
        /*
         *      Allow "$INCLUDE" or "$INCLUDE-", but
@@ -1182,41 +1185,68 @@ static int dict_read_process_include(dict_tokenize_ctx_t *dctx, char **argv, int
                return -1;
        }
 
-       filename = argv[1];
+       pattern = argv[1];
+       required = (argv[0][8] != '-');
 
        /*
         *      Allow limited macro capability, so people don't have
         *      to remember where the root dictionaries are located.
         */
-       if (strncmp(filename, "${dictdir}/", 11) == 0) {
+       if (strncmp(pattern, "${dictdir}/", 11) == 0) {
                dir = fr_dict_global_ctx_dir();
-               filename += 11;
-       }
-
-       rcode = _dict_from_file(dctx, dir, filename, src_file, src_line);
-       if ((rcode == -2) && (argv[0][8] == '-')) {
-               fr_strerror_clear(); /* delete all errors */
-               return 0;
+               pattern += 11;
        }
 
+       /*
+        *      Figure out what we need to open, and put the result into "filename".
+        */
+       rcode = fr_globdir_iter_init(&filename, dir, pattern, &iter);
        if (rcode < 0) {
-               fr_strerror_printf_push("from $INCLUDE at %s[%d]", fr_cwd_strip(src_file), src_line);
+       failed:
+               fr_strerror_printf("Failed opening $INCLUDE of %s/%s at %s[%d] - %s",
+                                  dir, pattern, fr_cwd_strip(src_file), src_line, fr_syserror(errno));
                return -1;
        }
 
-       if (dctx->stack_depth < stack_depth) {
-               fr_strerror_printf("unexpected END-??? in $INCLUDE at %s[%d]",
-                                  fr_cwd_strip(src_file), src_line);
-               return -1;
+       /*
+        *      No files may or may not be an error, depending on if the $INCLUDE was required.
+        */
+       if (rcode == 0) {
+               if (required) {
+                       errno = ENOENT;
+                       goto failed;
+               }
+
+               fr_strerror_clear(); /* delete all errors */
+               return 0;
        }
 
+       /*
+        *      "filename" is already the file, so we use do{}while() instead of while{}
+        */
+       do {
+               rcode = _dict_from_file(dctx, dir, filename, src_file, src_line);
+               if (rcode < 0) {
+                       fr_strerror_printf_push("from $INCLUDE at %s[%d]", fr_cwd_strip(src_file), src_line);
+                       break;
+               }
+
+               if (dctx->stack_depth < stack_depth) {
+                       fr_strerror_printf("unexpected END-??? in $INCLUDE at %s[%d]",
+                                          fr_cwd_strip(src_file), src_line);
+                       rcode = -1;
+                       break;
+               }
+
+       } while ((rcode = fr_globdir_iter_next(&filename, &iter)) == 1);
+       (void) fr_globdir_iter_free(&iter);
+
        /*
         *      Reset the filename and line number.
         */
        dctx->filename = src_file;
        dctx->line = src_line;
-
-       return 0;
+       return rcode;           /* could be an error! */
 }
 
 static int dict_read_parse_format(char const *format, int *ptype, int *plength, bool *pcontinuation)