[Git][NTPsec/ntpsec][master] 2 commits: Genericize lex_open - first step towards config directory.

Eric S. Raymond gitlab at mg.gitlab.com
Fri Mar 24 11:30:46 UTC 2017


Eric S. Raymond pushed to branch master at NTPsec / ntpsec


Commits:
aa6ada8a by Eric S. Raymond at 2017-03-24T07:30:15-04:00
Genericize lex_open - first step towards config directory.

- - - - -
edc696bd by Eric S. Raymond at 2017-03-24T07:30:15-04:00
Address GitLab issue #204: Support /etc/ntp.d

Implementation ad documentation.

- - - - -


9 changed files:

- devel/TODO
- devel/hacking.txt
- docs/includes/ntpd-body.txt
- docs/ntpsec.txt
- include/ntp_config.h
- ntpd/ntp_config.c
- ntpd/ntp_parser.y
- ntpd/ntp_scanner.c
- ntpd/ntp_scanner.h


Changes:

=====================================
devel/TODO
=====================================
--- a/devel/TODO
+++ b/devel/TODO
@@ -4,8 +4,6 @@
 
 * Units as an option in ntpq/ntpmon.
 
-* Easier assembly of config file snippets - ntpconf.d.
-
 * Package metadata for Debian, Ubuntu, Raspbian, Red Hat, Gentoo, and SuSe.
 
 * Add .tar.xz tarball.


=====================================
devel/hacking.txt
=====================================
--- a/devel/hacking.txt
+++ b/devel/hacking.txt
@@ -84,7 +84,10 @@ cause buffer overruns and (all too often) exploitable security holes:
 * gets: Use fgets instead.
 * gmtime(), localtime(), asctime(), ctime(): use the reentrant *_r variants.
 * tmpnam() - use mkstemp() or tmpfile() instead.
-* dirname() - the Linux version is re-entrant but this property is not portable.
+
+Do not rely on dirname() being re-entrant, and assume it will modify
+(truncate) its argument. The Linux version is re-entrant, but this
+property is not portable.
 
 In general, avoid functions that are non-reentrant.  When in doubt, see
 http://www.unix.org/whitepapers/reentrant.html[Thread-safety and POSIX.1]
@@ -120,8 +123,8 @@ continuity; you should, too.
 A discussion about using uncrustify to mass convert all the C sources
 to a more modern indentation and format style is ongoing.  As it will
 result in a coordinated flag day in ongoing development, it will be
-carefully announced in the mailto:devel at ntpsec.org mailing list before being merged and
-pushed.
+carefully announced in the mailto:devel at ntpsec.org mailing list before
+being merged and pushed.
 
 === Conventions for #ifdef guard names ===
 


=====================================
docs/includes/ntpd-body.txt
=====================================
--- a/docs/includes/ntpd-body.txt
+++ b/docs/includes/ntpd-body.txt
@@ -502,17 +502,38 @@ as described in {ntpdconfman}.
 
 [options="header"]
 |===================================================================
-|File               |Default           |Option      |Option
-|configuration file |+/etc/{ntpconf}+  |+-c+        |+conffile+
-|frequency file     |none              |+-f+        |+driftfile+
-|leapseconds file   |none              |            |+leapfile+
-|process ID file    |none              |+-p+        |+pidfile+
-|log file           |system log        |+-l+        |+logfile+
-|include file       |none              |none        |+includefile+
-|statistics path    |+/var/NTP+        |+-s+        |+statsdir+
-|keys file          |none              |+-k+        |+keys+
+|File                    |Default           |Option      |Option
+|configuration file      |+/etc/{ntpconf}+  |+-c+        |+conffile+
+|configuration directory |+/etc/ntp.d+      |+-c+        |+conffile+
+|frequency file          |none              |+-f+        |+driftfile+
+|leapseconds file        |none              |            |+leapfile+
+|process ID file         |none              |+-p+        |+pidfile+
+|log file                |system log        |+-l+        |+logfile+
+|include file            |none              |none        |+includefile+
+|statistics path         |+/var/NTP+        |+-s+        |+statsdir+
+|keys file               |none              |+-k+        |+keys+
 |===================================================================
 
+Configuration files are parsed according to the following rules:
+
+. The plain config file (normally +/etc/{ntpconf}+ but the path can be
+  overridden by the -c option) is read first if it exists.
+
+. Then the configuration directory, if it exists, is scanned. Normally
+  this directory is /etc/ntp.d, but if the -c option is specified the
+  /etc will be specified by the directory name of the -c argument.
+
+. Each file beneath the configuration directory with either the
+  extension ".ntpd" or ".refclockd" is interpreted.  Files are
+  interpreted in ASCII sort order of their pathnames.  Files with
+  other extensions or no extensions are ignored.
+
+It is best practice to put refclock and clockstats declarations in a
+".refclockd" file and all other declarations in an ".ntpd" file.  This
+anticipates a future direction of the architecture - it is intended
+that someday the refclock handling will be broken out of the main
+daemon into a separate executable with its own configuration parser.
+
 [[signals]]
 == SIGNALS ==
 


=====================================
docs/ntpsec.txt
=====================================
--- a/docs/ntpsec.txt
+++ b/docs/ntpsec.txt
@@ -214,6 +214,13 @@ codebase has been outright removed, with less than 5% new code added.
   in /etc/ntp.conf finding /etc/foo rather than looking for foo in
   your current directory.
 
+* If there is an /etc/ntp.d directory, its subfiles are scanned
+  for more configuration declarations. Only files with the extensions
+  ".ntpd" and ".refclockd" are interpreted; others are ignored.  This
+  feature is intended to make assembling configuration easier for
+  administration and package-configuration scripts.  See {ntpdman}
+  for details.
+
 * It is now possible to set the peer maximum dispersion with "tos
   maxdisp". See RFC 5905 for discussion of this synchronization
   parameter.


=====================================
include/ntp_config.h
=====================================
--- a/include/ntp_config.h
+++ b/include/ntp_config.h
@@ -20,6 +20,7 @@
 #ifndef CONFIG_FILE
 #  define	CONFIG_FILE "/etc/ntp.conf"
 #endif /* not CONFIG_FILE */
+#define CONFIG_DIR	"ntp.d"
 
 /* Limits */
 #define MAXLINE 1024


=====================================
ntpd/ntp_config.c
=====================================
--- a/ntpd/ntp_config.c
+++ b/ntpd/ntp_config.c
@@ -3265,6 +3265,7 @@ getconfig(const char *explicit_config)
 void readconfig(const char *config_file)
 {
 	char	line[256];
+	char	dirpath[PATH_MAX];
 	/*
 	 * install a non default variable with this daemon version
 	 */
@@ -3279,7 +3280,7 @@ void readconfig(const char *config_file)
 		&& check_netinfo && !(config_netinfo = get_netinfo_config())
 #endif /* HAVE_NETINFO_NI_H */
 		) {
-		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", config_file);
+		msyslog(LOG_INFO, "readconfig: Couldn't open <%s>: %m", config_file);
 		io_open_sockets();
 
 		return;
@@ -3292,7 +3293,15 @@ void readconfig(const char *config_file)
 #ifdef DEBUG
 	yydebug = !!(debug >= 5);
 #endif
+
+	/* parse the plain config file if it exists */
 	yyparse();
+
+	/* parse configs in parallel subdirectory if that exists */
+	reparent(dirpath, sizeof(dirpath), config_file, CONFIG_DIR);
+	if (is_directory(dirpath) && lex_push_file(dirpath))
+	    yyparse();
+
 	lex_drop_stack();
 
 	DPRINTF(1, ("Finished Parsing!!\n"));


=====================================
ntpd/ntp_parser.y
=====================================
--- a/ntpd/ntp_parser.y
+++ b/ntpd/ntp_parser.y
@@ -1135,7 +1135,7 @@ miscellaneous_command
 				msyslog(LOG_ERR, "getconfig: Maximum include file level exceeded.");
 			} else {
 				const char * path = $2;
-				if (!lex_push_file(path, "r")) {
+				if (!lex_push_file(path)) {
 					fprintf(stderr, "getconfig: Couldn't open <%s>\n", path);
 					msyslog(LOG_ERR, "getconfig: Couldn't open <%s>", path);
 				}


=====================================
ntpd/ntp_scanner.c
=====================================
--- a/ntpd/ntp_scanner.c
+++ b/ntpd/ntp_scanner.c
@@ -20,6 +20,9 @@
 #include <string.h>
 #include <limits.h>
 #include <libgen.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "ntpd.h"
 #include "ntp_config.h"
@@ -43,9 +46,10 @@ static struct FILE_INFO * lex_stack = NULL;
 
 
 
-/* CONSTANTS 
- * ---------
+/* CONSTANTS AND MACROS
+ * --------------------
  */
+#define CONF_ENABLE(s)	strcmp(s + strlen(s) - 5, ".ntpd") == 0
 
 
 /* SCANNER GLOBAL VARIABLES 
@@ -299,6 +303,7 @@ lex_init_stack(
 	if (NULL != lex_stack || NULL == path)
 		return false;
 
+	//fprintf(stderr, "lex_init_stack(%s)\n", path);
 	lex_stack = lex_open(path, mode);
 	return (NULL != lex_stack);
 }
@@ -338,11 +343,45 @@ lex_flush_stack()
 	return retv;
 }
 
+/* Reversed string comparison - we want to LIFO directory subfiles so they
+ * actually get evaluated in sort order. 
+ */
+static int rcmpstring(const void *p1, const void *p2)
+{
+    return strcmp(*(const char **)p1, *(const char **)p2);
+}
+
+bool is_directory(const char *path)
+{
+	struct stat sb;
+	return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode);
+}
+
+void reparent(char *fullpath, size_t fullpathsize,
+	      const char *dir, const char *base)
+{
+	fullpath[0] = '\0';
+	if (base[0] != DIR_SEP) {
+		char *dirpart = strdup(dir);
+		char *end;
+		strlcpy(fullpath, dirname(dirpart), fullpathsize-2);
+		end = fullpath + strlen(fullpath);
+		*end++ = DIR_SEP;
+		*end++ = '\0';
+		free(dirpart);
+	}
+	strlcat(fullpath, base, fullpathsize);
+}
+
 /* Push another file on the parsing stack. If the mode is NULL, create a
  * FILE_INFO suitable for in-memory parsing; otherwise, create a
  * FILE_INFO that is bound to a local/disc file. Note that 'path' must
  * not be NULL, or the function will fail.
  *
+ * If the pathname is a directory, push all subfiles and
+ * subdirectories with paths satisying the predicate CONF_ENABLE(),
+ * recursively depth first to be interpreted in ASCII sort order.
+ *
  * Relative pathnames are interpreted relative to the directory
  * of the previous entry on the stack, not the current directory.
  * This is so "include foo" from within /etc/conf will reliably
@@ -351,29 +390,59 @@ lex_flush_stack()
  * Returns true if a new info record was pushed onto the stack.
  */
 bool lex_push_file(
-	const char * path,
-	const char * mode
+	const char * path
 	)
 {
 	struct FILE_INFO * next = NULL;
 
 	if (NULL != path) {
 		char fullpath[PATH_MAX];
-		fullpath[0] = '\0';
-		if (path[0] != DIR_SEP && lex_stack != NULL) {
-			char *end;
-			strlcpy(fullpath,
-				dirname(lex_stack->fname),sizeof(fullpath)-2);
-			end = fullpath + strlen(fullpath);
-			*end++ = DIR_SEP;
-			*end++ = '\0';
-		}
-		strlcat(fullpath, path, sizeof(fullpath));
-		fprintf(stderr, "Opening %s\n", fullpath);
-		next = lex_open(fullpath, mode);
-		if (NULL != next) {
-			next->st_next = lex_stack;
-			lex_stack = next;
+		if (lex_stack != NULL)
+		    reparent(fullpath, sizeof(fullpath), lex_stack->fname, path);
+		else
+		    strlcpy(fullpath, path, sizeof(fullpath));
+		//fprintf(stderr, "lex_push_file(%s)\n", fullpath);
+		if (is_directory(fullpath)) {
+			/* directory scanning */
+			DIR *dfd;
+			struct dirent *dp;
+			char **baselist = (char **)malloc(sizeof(char *));
+			int basecount = 0;
+			if ((dfd = opendir(fullpath)) == NULL)
+				return false;
+			while ((dp = readdir(dfd)) != NULL)
+			{
+			    if (!CONF_ENABLE(dp->d_name))
+			    	continue;
+			    baselist[basecount++] = strdup(dp->d_name);
+			    baselist = realloc(baselist,
+					       (basecount+1) * sizeof(char *));
+			}
+			qsort(baselist, basecount, sizeof(char *), rcmpstring);
+			for (int i = 0; i < basecount; i++) {
+				char subpath[PATH_MAX];
+				strlcpy(subpath, fullpath, PATH_MAX);
+				if (strlen(subpath) < PATH_MAX - 1) {
+				    char *ep = subpath + strlen(subpath);
+				    *ep++ = DIR_SEP;
+				    *ep = '\0';
+				}
+				strlcat(subpath, baselist[i], PATH_MAX);
+				/* This should barf safely if the complete
+				 * filename was too long to fit in the buffer.
+				 */ 
+				lex_push_file(subpath);
+			}
+			for (int i = 0; i < basecount; i++)
+				free(baselist[basecount]);
+			free(baselist);
+			return basecount > 0;
+		} else {
+			next = lex_open(fullpath, "r");
+			if (NULL != next) {
+				next->st_next = lex_stack;
+				lex_stack = next;
+			}
 		}
 	}
 	return (NULL != next);


=====================================
ntpd/ntp_scanner.h
=====================================
--- a/ntpd/ntp_scanner.h
+++ b/ntpd/ntp_scanner.h
@@ -132,8 +132,12 @@ extern bool lex_init_stack(const char * path, const char * mode);
 extern void        lex_drop_stack(void);
 extern bool lex_flush_stack(void);
 
+/* path management for config directories */
+extern void reparent(char *, size_t, const char *, const char *);
+extern bool is_directory(const char *);
+
 /* add/remove a nested input source */
-extern bool lex_push_file(const char * path, const char * mode);
+extern bool lex_push_file(const char * path);
 extern bool lex_pop_file(void);
 
 /* input stack state query functions */



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/e2132683825779f4ec7cfe393a3b790894e3e544...edc696bd5f8adda8ea2a7d3599e6967c4ff399bb
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20170324/4df45919/attachment.html>


More information about the vc mailing list