]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1293] make configuration dumper ready for release, specifically:
authorDave Hart <hart@ntp.org>
Sat, 29 Aug 2009 21:22:45 +0000 (21:22 +0000)
committerDave Hart <hart@ntp.org>
Sat, 29 Aug 2009 21:22:45 +0000 (21:22 +0000)
rename ntpq dumpcfg command to "saveconfig".
require authentication for saveconfig.
"restrict ... nomodify" prevents saveconfig and :config.
"saveconfig ." shorthand to save to startup configuration file.
support strftime() substitution in saveconfig arg to timestamp
  the output filename, for example "saveconfig %Y%m%d-%H%M%S.conf".
display saveconfig response message from ntpd in ntpq.
save output filename in "savedconfig" variable, fetched with ntpq -c
  "rv 0 savedconfig".
document saveconfig in html/ntpq.html.
add ./configure --disable-saveconfig to build a smaller ntpd.
log saveconfig failures and successes to syslog.

bk: 4a999c25yGmWAgeJeMYlLfjAR9MezQ

12 files changed:
ChangeLog
html/ntpq.html
include/ntp_config.h
include/ntp_control.h
include/ntpd.h
ntpd/ntp_config.c
ntpd/ntp_control.c
ntpd/ntp_intres.c
ntpd/ntp_io.c
ntpq/ntpq-subs.c
ports/winnt/include/config.h
ports/winnt/ntpd/ntp_iocompletionport.c

index aebcf9be1c33331dc1396760de3cb4b6bac59b22..c216d20e39683f233e34c260efc21d495a1746ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+* [Bug 1293] make configuration dumper ready for release, specifically:
+* rename ntpq dumpcfg command to "saveconfig".
+* require authentication for saveconfig.
+* "restrict ... nomodify" prevents saveconfig and :config.
+* "saveconfig ." shorthand to save to startup configuration file.
+* support strftime() substitution in saveconfig arg to timestamp
+  the output filename, for example "saveconfig %Y%m%d-%H%M%S.conf".
+* display saveconfig response message from ntpd in ntpq.
+* save output filename in "savedconfig" variable, fetched with ntpq -c
+  "rv 0 savedconfig".
+* document saveconfig in html/ntpq.html.
+* add ./configure --disable-saveconfig to build a smaller ntpd.
+* log saveconfig failures and successes to syslog.
 (4.2.5p206) 2009/08/26 Released by Harlan Stenn <stenn@ntp.org>
 * accopt.html typo fixes from Dave Mills.
 * [Bug 1283] default to remembering KoD in sntp.
index f42c5481fc212d1b367eff90a18d521a1ed5560d..45d72cc8b4fd342f274330e09f1ab4ba98437651 100644 (file)
@@ -48,7 +48,7 @@
                <p>Interactive format commands consist of a keyword followed by zero to four arguments. Only enough characters of the full keyword to uniquely identify the command need be typed. The output of a command is normally sent to the standard output, but optionally the output of individual commands may be sent to a file by appending a <tt>&gt;</tt>, followed by a file name, to the command line. A number of interactive format commands are executed entirely within the <tt>ntpq</tt> program itself and do not result in NTP mode-6 requests being sent to a server. These are described following.</p>
                <dl>
                        <dt><tt>? [<i>command_keyword</i>]</tt><br>
-                               <tt>helpl [<i>command_keyword</i>]</tt>
+                               <tt>help [<i>command_keyword</i>]</tt>
                        <dd>A <tt>?</tt> by itself will print a list of all the command keywords known to  <tt>ntpq</tt>. A <tt>?</tt> followed by a command keyword will print function and usage information about the command.
                        <dt><tt>addvars <i>name</i> [ = <i>value</i>] [...]</tt><br>
                                <tt>rmvars <i>name</i> [...]</tt><br>
                                                <td>event count (see <a href="decode.html#peer">peer status word</a>)</td>
                                        </tr>
                                </table>
-                       <dt><tt>clockvar [<i>assocID</i>] [<i>name</i> [ = <i>value</i> [...]] [...]</tt>
-                       <dt><tt>cv [<i>assocID</i>] [<i>name</i> [ = <i>value</i> [...] ][...]</tt>
+                       <dt><tt>clockvar [<i>assocID</i>] [<i>name</i> [ = <i>value</i> [...]] [...]</tt><br>
+                               <tt>cv [<i>assocID</i>] [<i>name</i> [ = <i>value</i> [...] ][...]</tt>
                        <dd>Display a list of <a href="#clock">clock variables</a> for those assocations supporting a reference clock.
+                       <dt><tt>:config [...]</tt>
+                       <dd>Send the remainder of the command line, including whitespace, to the server as a run-time configuration command in the same format as the configuration file. This command is experimental until further notice and clarification. Authentication is of course required.
+                       <dt><tt>config-from-file <i>filename</i></tt>
+                       <dd>Send the each line of <i>filename</i> to the server as run-time configuration commands in the same format as the configuration file. This command is experimental until further notice and clarification. Authentication is of course required.
                        <dt><tt>keyid</tt>
                        <dd>Specify the key ID to use for write requests.<dt><tt>lassociations</tt>
                        <dd>Perform the same function as the associations command, execept display mobilized and unmobilized associations.<dt><tt>mreadvar <i>assocID</i> <i>assocID</i> [ <i>variable_name</i> [ = <i>value</i>[ ... ]</tt><br>
                                </table>
                        <dt id="rv"><tt>readvar <i>assocID</i> <i>name</i> [ = <i>value</i> ] [,...]</tt><br>
                                <tt>rv <i>assocID</i> [ <i>name</i> ] [,...]</tt>
-                       <dd>Display the specified variables. If the association ID is omitted or is given as zero, the variables are from the <a href="#system">system variables</a> name space, otherwise they are from the <a href="#peer">peer variables</a> name space. If no name is included, all operative variables in the name space are displayed. Multiple names are specified with comma separators and without whitespace. Note that time values are represented in milliseconds and frequency values in parts-per-million (PPM). Some NTP timestamps are represented in the format YYYYMMDDTTTT, where YYYY is the year, MM the month of year, DD the day of month and TTTT the time of day.<dt><tt>writevar <i>assocID</i> <i>name</i> = <i>value</i> [,...]</tt>
-                       <dd>Write the specified variables. If the association ID is omitted or is given as zero, the variables are from the <a href="#system">system variables</a> name space, otherwise they are from the <a href="#peer">peer variables</a> name space.
-                       <dt><tt>:config [...]</tt>
-                       <dd>Send the remainder of the command line, including whitespace, to the server as a run-time configuration command in the same format as the configuration file. This command is experimental until further notice and clarification. Authentication is of course required.</dl>
+                       <dd>Display the specified variables. If the association ID is omitted or is given as zero, the variables are from the <a href="#system">system variables</a> name space, otherwise they are from the <a href="#peer">peer variables</a> name space. If no name is included, all operative variables in the name space are displayed. Multiple names are specified with comma separators and without whitespace. Note that time values are represented in milliseconds and frequency values in parts-per-million (PPM). Some NTP timestamps are represented in the format YYYYMMDDTTTT, where YYYY is the year, MM the month of year, DD the day of month and TTTT the time of day.
+                       <dt><tt>saveconfig <i>filename</i></tt>
+                       <dd>Write the current configuration, including any runtime modifications given with <tt>:config</tt> or <tt>config-from-file</tt>, to the ntpd host's file <i>filename</i>. A single period given for <i>filename</i> is shorthand for the startup configuration file.  <i>filename</i> can use strftime() format specifiers to substitute the current date and time, for example, <tt>saveconfig ntp-%Y%m%d-%H%M%S.conf</tt>. The filename used is stored in system variable <tt>savedconfig</tt>. Authentication is required.
+                       <dt><tt>writevar <i>assocID</i> <i>name</i> = <i>value</i> [,...]</tt>
+                       <dd>Write the specified variables. If the association ID is omitted or is given as zero, the variables are from the <a href="#system">system variables</a> name space, otherwise they are from the <a href="#peer">peer variables</a> name space.</dl>
                <h4 id="status">Status Words and Kiss Codes</h4>
                <p>The current state of the operating program is shown in a set of status words maintained by the system and each association separately. These words are displayed in the <tt>rv</tt> and <tt>as</tt> commands both in hexadecimal and decoded short tip strings. The codes, tips and short explanations are on the <a href="decode.html">Event Messages and Status Words</a> page. The page also includes a list of system and peer messages, the code for the latest of which is included in the status word.</p>
                <p>Information resulting from protocol machine state transitions is displayed using an informal set of ASCII strings called <a href="decode.html#kiss">kiss codes</a>. The original purpose was for kiss-o'-death (KoD) packets sent by the server to advise the client of an unusual condition. They are now displayed, when appropriate, in the reference identifier field in various billboards.</p>
                <h4 id="system">System Variables</h4>
-               <p>The following system variables apear in the <tt>rv</tt> billboard. Not all variables are displayed in some configurations.</p>
+               <p>The following system variables appear in the <tt>rv</tt> billboard. Not all variables are displayed in some configurations.</p>
                <table width="100%" border="1" cellspacing="2" cellpadding="2">
                        <tr>
                                <td>Variable</td>
index 25f93631a5bec86422bb9fe9acdf84310f601d73..5a3d416103523e2f96906cabbd17ec20c64b2578 100644 (file)
@@ -205,8 +205,9 @@ server_info *create_sim_server(struct address_node *addr, double server_offset,
 extern struct REMOTE_CONFIG_INFO remote_config;
 void config_remotely(sockaddr_u *);
 
+#ifdef SAVECONFIG
 int dump_config_tree(struct config_tree *ptree, FILE *df);
 int dump_all_config_trees(FILE *df);
-
+#endif
 
 #endif /* !defined(NTP_CONFIG_H) */
index dd0f86557f6e995d0be67353cfbb594ff3b7e83e..59b98b940734f048c9272a89a9e2cb022db65428 100644 (file)
@@ -53,9 +53,9 @@ struct ntp_control {
 #define        CTL_OP_WRITECLOCK       5       /* write clock variables */
 #define        CTL_OP_SETTRAP          6       /* set trap address */
 #define        CTL_OP_ASYNCMSG         7       /* asynchronous message */
-#define CTL_OP_CONFIGURE        8      /* configuration message */
+#define CTL_OP_CONFIGURE       8       /* runtime configuration */
+#define CTL_OP_SAVECONFIG      9       /* save config to file */
 #define        CTL_OP_UNSETTRAP        31      /* unset trap */
-#define CTL_OP_DUMPCONFIG      9
 
 /*
  * {En,De}coding of the system status word
index ff38202379884cc4728beeea65c576a13104a0a6..261fe4b0c6116f4b7deab6a35c10b1196c4fb916 100644 (file)
@@ -260,8 +260,8 @@ extern char *sys_phone[];           /* ACTS phone numbers */
 extern int     config_priority_override;
 extern int     config_priority;
 #endif
-
 extern char *ntp_signd_socket;
+extern struct config_tree *cfg_tree_history;
 
 /* ntp_control.c */
 extern int     num_ctl_traps;
index f9fb0de717dada4c0657481b5225cd7330e8c1f4..c84f43fc44a2b6f7eed98b60ac1050734bca81dc 100644 (file)
@@ -463,6 +463,8 @@ free_config_tree(struct config_tree *ptree)
 }
 #endif /* DEBUG */
 
+
+#ifdef SAVECONFIG
 /* Dump all trees */
 int
 dump_all_config_trees (
@@ -1463,7 +1465,7 @@ dump_config_tree(
 
        return 0;
 }
-
+#endif /* SAVECONFIG */
        
 
 /* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
@@ -4392,7 +4394,9 @@ abort_resolve(void)
 static void
 do_resolve_internal(void)
 {
+#ifndef SYS_WINNT
        int i;
+#endif
 
        if (res_fp == NULL) {
                /* belch */
index 7479997d2ae02be3d23f5acbed066891abb3c23c..8aac4bc867a156d2b75723e8f44487d26c70e352 100644 (file)
@@ -75,7 +75,7 @@ static        void    write_clock_status (struct recvbuf *, int);
 static void    set_trap        (struct recvbuf *, int);
 static void    unset_trap      (struct recvbuf *, int);
 static void    configure       (struct recvbuf *, int);
-static void    dump_config     (struct recvbuf *, int);
+static void    save_config     (struct recvbuf *, int);
 static struct ctl_trap *ctlfindtrap (sockaddr_u *,
                                      struct interface *);
 
@@ -88,7 +88,7 @@ static        struct ctl_proc control_codes[] = {
        { CTL_OP_WRITECLOCK,    NOAUTH, write_clock_status },
        { CTL_OP_SETTRAP,       NOAUTH, set_trap },
        { CTL_OP_UNSETTRAP,     NOAUTH, unset_trap },
-       { CTL_OP_DUMPCONFIG,    NOAUTH, dump_config },
+       { CTL_OP_SAVECONFIG,    AUTH,   save_config },
        { CTL_OP_CONFIGURE,     AUTH,   configure },
        { NO_REQUEST,           0 }
 };
@@ -546,54 +546,107 @@ ctl_error(
 }
 
 /* 
- * Call the config dumper
+ * save_config - Implements ntpq -c "saveconfig <filename>"
+ *              Writes current configuration including any runtime
+ *              changes by ntpq's :config or config-from-file
  */
 void
-dump_config(
-               struct recvbuf *rbufp,
-               int restrict_mask
-               )
+save_config(
+       struct recvbuf *rbufp,
+       int restrict_mask
+       )
 {
-       /* Dump config to file (for now) to ntp_dumpXXXXXXXXXX.conf */
-       char fullpath[256];
-       char filename[80];
-       char reply[80];
+       char reply[128];
+#ifdef SAVECONFIG
+       char filespec[256];
+       char filename[256];
+       time_t now;
        int fd;
        FILE *fptr;
+       const char savedconfig_eq[] = "savedconfig=";
+       size_t octets;
+       char *savedconfig;
+#endif
 
-       if (reqend - reqpt) {
-               strncpy(filename, reqpt, sizeof(filename));
-               filename[sizeof(filename) - 1] = 0;
-               if (NULL != strchr(filename, '/')
-                   || NULL != strchr(filename, '\\'))
-                       snprintf(filename, sizeof(filename), 
-                                "ntp_dump%i.conf", time(NULL));
-       } else
-               snprintf(filename, sizeof(filename), "ntp_dump%i.conf",
-                        time(NULL));
+       if (restrict_mask & RES_NOMODIFY) {
+               snprintf(reply, sizeof(reply),
+                        "saveconfig prohibited by restrict ... nomodify");
+               ctl_putdata(reply, strlen(reply), 0);
+               ctl_flushpkt(0);
+               msyslog(LOG_NOTICE,
+                       "saveconfig from %s rejected due to nomodify restriction",
+                       stoa(&rbufp->recv_srcadr));
+               return;
+       }
 
-#ifndef SYS_WINNT
-       snprintf(fullpath, sizeof(fullpath), "/var/tmp/%s", filename);
-#else
-       snprintf(fullpath, sizeof(fullpath), "%s\\%s", getenv("TEMP"),
-                filename);
-#endif
+#ifdef SAVECONFIG
+       if (0 == reqend - reqpt)
+               return;
+
+       strncpy(filespec, reqpt, sizeof(filespec));
+       filespec[sizeof(filespec) - 1] = '\0';
 
-       fd = open(fullpath, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
+       time(&now);
+
+       /*
+        * "saveconfig ." is shorthand for replacing the startup
+        * configuration file.
+        */
+       if ('.' == filespec[0] && '\0' == filespec[1]
+           && NULL != cfg_tree_history)
+               strncpy(filename, cfg_tree_history->source.value.s,
+                       sizeof(filename));
+       /*
+        * allow timestamping of the saved config filename with
+        * strftime() format such as:
+        *   ntpq -c "saveconfig ntp-%Y%m%d-%H%M%S.conf"
+        */
+       else if (0 == strftime(filename, sizeof(filename), filespec,
+                              localtime(&now)))
+               strncpy(filename, filespec, sizeof(filename));
+
+       filename[sizeof(filename) - 1] = '\0';
+       
+
+       fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
        if (-1 == fd)
                fptr = NULL;
        else
                fptr = fdopen(fd, "w");
 
-       if (NULL == fptr || -1 == dump_all_config_trees(fptr))
-               snprintf(reply, sizeof(reply), "Couldn't dump to file %s",
-                        fullpath);
-       else
-               snprintf(reply, sizeof(reply), "Dumped to config file %s",
-                        fullpath);
+       if (NULL == fptr || -1 == dump_all_config_trees(fptr)) {
+               snprintf(reply, sizeof(reply),
+                        "Unable to save configuration to file %s",
+                        filename);
+               msyslog(LOG_ERR,
+                       "saveconfig %s from %s failed", filename,
+                       stoa(&rbufp->recv_srcadr));
+       } else {
+               snprintf(reply, sizeof(reply),
+                        "Configuration saved to %s",
+                        filename);
+               msyslog(LOG_NOTICE,
+                       "Configuration saved to %s (requested by %s)",
+                       filename, stoa(&rbufp->recv_srcadr));
+               /*
+                * save the output filename in system variable
+                * savedconfig, retrieved with:
+                *   ntpq -c "rv 0 savedconfig"
+                */
+               octets = sizeof(savedconfig_eq) + strlen(filename) + 1;
+               savedconfig = emalloc(sizeof(savedconfig_eq) 
+                                     + strlen(filename) + 1);
+               snprintf(savedconfig, octets, "%s%s",
+                        savedconfig_eq, filename);
+               set_sys_var(savedconfig, octets, RO);
+       }
 
        if (NULL != fptr)
                fclose(fptr);
+#else  /* !SAFECONFIG follows */
+       snprintf(reply, sizeof(reply),
+                "saveconfig unavailable, configured with --disable-saveconfig");
+#endif
 
        ctl_putdata(reply, strlen(reply), 0);
        ctl_flushpkt(0);
@@ -2406,6 +2459,19 @@ static void configure(
                return;
        }
 
+       if (restrict_mask & RES_NOMODIFY) {
+               snprintf(remote_config.err_msg,
+                        sizeof(remote_config.err_msg),
+                        "runtime configuration prohibited by restrict ... nomodify");
+               ctl_putdata(remote_config.err_msg, 
+                           strlen(remote_config.err_msg), 0);
+               ctl_flushpkt(0);
+               msyslog(LOG_NOTICE,
+                       "runtime config from %s rejected due to nomodify restriction",
+                       stoa(&rbufp->recv_srcadr));
+               return;
+       }
+
        /* Initialize the remote config buffer */
        data_count = reqend - reqpt;
        memcpy(remote_config.buffer, reqpt, data_count);
index eb88b24edb382f191c8308f4a631ce8acc09936c..9180af59b4e5b98c7b20177b6a96c52404f024bc 100644 (file)
@@ -210,12 +210,12 @@ void
 ntp_intres(void)
 {
        FILE *in;
-       struct timeval tv;
-       fd_set fdset;
 #ifdef SYS_WINNT
        DWORD rc;
 #else
        int rc;
+       struct timeval tv;
+       fd_set fdset;
 #endif
 
 #ifdef DEBUG
index af3389f090946021c22dcbb1f1a71d7f8cc42639..43e92febd871c8cfb0b3e6faa9fbd262a9e74759 100644 (file)
@@ -1704,9 +1704,8 @@ set_reuseaddr(
        int flag
        )
 {
-       struct interface *interf;
-
 #ifndef SO_EXCLUSIVEADDRUSE
+       struct interface *interf;
 
        for (interf = inter_list;
             interf != NULL;
index b39843f994524cf1e3eb0d4cf64d5b719dd49f8c..d50353616595083c0277b1935ea71b56acd45e80 100644 (file)
@@ -62,8 +62,8 @@ static        void    lpeers          (struct parse *, FILE *);
 static void    doopeers        (int, FILE *, int);
 static void    opeers          (struct parse *, FILE *);
 static void    lopeers         (struct parse *, FILE *);
-static  void    config          (struct parse *, FILE *);
-static         void    dumpcfg         (struct parse *, FILE *);
+static  void    config         (struct parse *, FILE *);
+static         void    saveconfig      (struct parse *, FILE *);
 static  void    config_from_file (struct parse *, FILE *);
 
 
@@ -71,9 +71,9 @@ static  void    config_from_file (struct parse *, FILE *);
  * Commands we understand.     Ntpdc imports this.
  */
 struct xcmd opcmds[] = {
-       { "dumpcfg", dumpcfg, { NTP_STR, NO, NO, NO },
-               { "dumpfile", "", "", ""}, 
-               "dump ntp server configuration"},
+       { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
+               { "filename", "", "", ""}, 
+               "save ntpd configuration to file, . for current config file"},
        { "associations", associations, {  NO, NO, NO, NO },
          { "", "", "", "" },
          "print list of association ID's and statuses for the server's peers" },
@@ -1148,7 +1148,7 @@ lpassociations(
  *  * dumpcfg - dump ntp server configuration
  */
 static void
-dumpcfg(
+saveconfig(
        struct parse *pcmd,
        FILE *fp
        )
@@ -1158,14 +1158,22 @@ dumpcfg(
        int dsize;
        u_short rstatus;
 
-       /* Is there a way to make an argument optional? */
-       if(pcmd->nargs > 0)
-               res = doquery(CTL_OP_DUMPCONFIG, 0, 0, strlen(pcmd->argval[0].string), 
-                       pcmd->argval[0].string, &rstatus, &dsize, &datap);
+       if (0 == pcmd->nargs)
+               return;
+       
+       res = doquery(CTL_OP_SAVECONFIG, 0, 1,
+                     strlen(pcmd->argval[0].string),
+                     pcmd->argval[0].string, &rstatus, &dsize,
+                     &datap);
+
+       if (res != 0)
+               return;
+
+       if (0 == dsize)
+               fprintf(fp, "(no response message, curiously)");
        else {
-               res = doquery(CTL_OP_DUMPCONFIG, 0, 0, 0, (char *) 0, 
-                       &rstatus, &dsize, &datap);
-               printf("No filename supplied\n");
+               datap[dsize] = '\0';
+               fprintf(fp, "%s", datap);
        }
 }
 
index 7108cfc0a1d955ac8f19ede286b1a3307c8ca804..9fd6c7eef52cbf0d943c67784c9486bbe28e4b99 100644 (file)
@@ -203,7 +203,6 @@ typedef int socklen_t;
  */
 
 #pragma warning(disable: 4100) /* unreferenced formal parameter */
-#pragma warning(disable: 4101) /* unreferenced local variable */
 #pragma warning(disable: 4127) /* conditional expression is constant */
 #pragma warning(disable: 4996) /* more secure replacement available */
 
@@ -224,6 +223,7 @@ typedef int socklen_t;
 #define HAVE_RANDOM 
 #define MAXHOSTNAMELEN                 64
 #define AUTOKEY
+#define SAVECONFIG                     1
 
 /*
  * Multimedia timer enable
index c0329bb61ce26aa68ea77cda7acd05e088d2c2be..731613eda173be159782cb58d1b8580134bc8000 100644 (file)
@@ -444,7 +444,6 @@ OnSerialWaitComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errsta
        DWORD comm_mask;
        DWORD modem_status;
        static const l_fp zero_time = { 0 };
-       DWORD dwBytesReturned;
        BOOL rc;
 
        get_systime(&arrival_time);
@@ -686,7 +685,6 @@ OnSocketRecv(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
 {
        struct recvbuf *buff = NULL;
        recvbuf_t *newbuff;
-       isc_boolean_t ignore_this;
        l_fp arrival_time;
        struct interface * inter = (struct interface *) i;