]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 3692] /dev/gpsN requirement prevents KPPS
authorJuergen Perlinger <perlinger@ntp.org>
Wed, 14 Oct 2020 16:40:09 +0000 (18:40 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Wed, 14 Oct 2020 16:40:09 +0000 (18:40 +0200)
 - resolve symlinks in device names for GPSD_JSON driver

bk: 5f8729e9muDcx7Vq6XoBDT_eNmfM1Q

ChangeLog
configure.ac
include/ntp_stdlib.h
libntp/Makefile.am
libntp/ntp_realpath.c [new file with mode: 0644]
ntpd/refclock_gpsdjson.c
ntpsnmpd/ntpsnmpd.c
sntp/m4/realpath.m4 [new file with mode: 0644]

index eeceaa9f10cb57b56caf561eaab50a81ec861f63..be97b2a2fe8fa2ab042af3c9e1488df023abf030 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+---
+* [Bug 3692] /dev/gpsN requirement prevents KPPS <perlinger@ntp.org>
+  - implement/wrap 'realpath()' to resolve symlinks in device names
+* Implement NTP_FUNC_REALPATH.  <stenn@ntp.org>
+
 ---
 (4.2.8p15) 2020/06/23 Released by Harlan Stenn <stenn@ntp.org>
 
index 5dc6aee02edc763c02af86a9417269f5b70d045c..4e1c1dc676d483c8b6b42d405efc837a95a25e3f 100644 (file)
@@ -900,6 +900,7 @@ case "$host" in
     ;;
 esac
 AC_CHECK_FUNCS([nice plock pututline pututxline readlink rtprio])
+NTP_FUNC_REALPATH
 case "$host" in
  *-*-aix[[4-9]]*)
     # XXX only verified thru AIX6.
index 265aafa73ebc03cc7cb57dcc798c2c1e2d803405..cf8c4f27979ec3d46bf93fdfee82c18044d9fd1e 100644 (file)
@@ -40,6 +40,8 @@ extern        void    setup_logfile   (const char *);
 extern void    errno_to_str(int, char *, size_t);
 #endif
 
+extern char *  ntp_realpath(const char * fsname);
+
 extern int     xvsbprintf(char**, char* const, char const*, va_list) NTP_PRINTF(3, 0);
 extern int     xsbprintf(char**, char* const, char const*, ...) NTP_PRINTF(3, 4);
 
index ddd1e01dd7efcda69d0d8da4abcaf3001b9c6c5d..54dbdf1e8ce344637d09bf0b70e4a7546daacd43 100644 (file)
@@ -87,6 +87,7 @@ libntp_a_SRCS =                                               \
        ntp_libopts.c                                   \
        ntp_lineedit.c                                  \
        ntp_random.c                                    \
+       ntp_realpath.c                                  \
        ntp_rfc2553.c                                   \
        ntp_worker.c                                    \
        numtoa.c                                        \
diff --git a/libntp/ntp_realpath.c b/libntp/ntp_realpath.c
new file mode 100644 (file)
index 0000000..716c7b5
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * ntp_realpath.c - get real path for a file
+ *     Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ *     Feb 11, 2014 for the NTP project.
+ * 
+ * This is a butchered version of FreeBSD's implementation of 'realpath()',
+ * and the following copyright applies:
+ *----------------------------------------------------------------------
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "ntp_stdlib.h"
+
+/* ================================================================== */
+#if !defined(SYS_WINNT) && !defined(HAVE_FUNC_POSIX_REALPATH)
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* The following definitions are to avoid system settings with excessive
+ * values for maxmimum path length and symlink chains/loops. Adjust with
+ * care, if that's ever needed: some buffers are on the stack!
+ */
+#define NTP_PATH_MAX   1024
+#define NTP_MAXSYMLINKS        16
+
+/*
+ * Find the real name of path, by removing all ".", ".." and symlink
+ * components.  Returns (resolved) on success, or (NULL) on failure,
+ * in which case the path which caused trouble is left in (resolved).
+ */
+static char *
+realpath1(const char *path, char *resolved)
+{
+       struct stat sb;
+       char *p, *q;
+       size_t left_len, resolved_len, next_token_len;
+       unsigned symlinks;
+       ssize_t slen;
+       char left[NTP_PATH_MAX], next_token[NTP_PATH_MAX], symlink[NTP_PATH_MAX];
+
+       symlinks = 0;
+       if (path[0] == '/') {
+               resolved[0] = '/';
+               resolved[1] = '\0';
+               if (path[1] == '\0')
+                       return (resolved);
+               resolved_len = 1;
+               left_len = strlcpy(left, path + 1, sizeof(left));
+       } else {
+               if (getcwd(resolved, NTP_PATH_MAX) == NULL) {
+                       resolved[0] = '.';
+                       resolved[1] = '\0';
+                       return (NULL);
+               }
+               resolved_len = strlen(resolved);
+               left_len = strlcpy(left, path, sizeof(left));
+       }
+       if (left_len >= sizeof(left) || resolved_len >= NTP_PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return (NULL);
+       }
+
+       /*
+        * Iterate over path components in `left'.
+        */
+       while (left_len != 0) {
+               /*
+                * Extract the next path component and adjust `left'
+                * and its length.
+                */
+               p = strchr(left, '/');
+
+               next_token_len = p != NULL ? (size_t)(p - left) : left_len;
+               memcpy(next_token, left, next_token_len);
+               next_token[next_token_len] = '\0';
+
+               if (p != NULL) {
+                       left_len -= next_token_len + 1;
+                       memmove(left, p + 1, left_len + 1);
+               } else {
+                       left[0] = '\0';
+                       left_len = 0;
+               }
+
+               if (resolved[resolved_len - 1] != '/') {
+                       if (resolved_len + 1 >= NTP_PATH_MAX) {
+                               errno = ENAMETOOLONG;
+                               return (NULL);
+                       }
+                       resolved[resolved_len++] = '/';
+                       resolved[resolved_len] = '\0';
+               }
+               if (next_token[0] == '\0') {
+                       /* Handle consequential slashes. */
+                       continue;
+               } else if (strcmp(next_token, ".") == 0) {
+                       continue;
+               } else if (strcmp(next_token, "..") == 0) {
+                       /*
+                        * Strip the last path component except when we have
+                        * single "/"
+                        */
+                       if (resolved_len > 1) {
+                               resolved[resolved_len - 1] = '\0';
+                               q = strrchr(resolved, '/') + 1;
+                               *q = '\0';
+                               resolved_len = q - resolved;
+                       }
+                       continue;
+               }
+
+               /*
+                * Append the next path component and lstat() it.
+                */
+               resolved_len = strlcat(resolved, next_token, NTP_PATH_MAX);
+               if (resolved_len >= NTP_PATH_MAX) {
+                       errno = ENAMETOOLONG;
+                       return (NULL);
+               }
+               if (lstat(resolved, &sb) != 0)
+                       return (NULL);
+               if (S_ISLNK(sb.st_mode)) {
+                       if (symlinks++ > NTP_MAXSYMLINKS) {
+                               errno = ELOOP;
+                               return (NULL);
+                       }
+                       slen = readlink(resolved, symlink, sizeof(symlink));
+                       if (slen <= 0 || slen >= (ssize_t)sizeof(symlink)) {
+                               if (slen < 0)
+                                       ; /* keep errno from readlink(2) call */
+                               else if (slen == 0)
+                                       errno = ENOENT;
+                               else
+                                       errno = ENAMETOOLONG;
+                               return (NULL);
+                       }
+                       symlink[slen] = '\0';
+                       if (symlink[0] == '/') {
+                               resolved[1] = 0;
+                               resolved_len = 1;
+                       } else {
+                               /* Strip the last path component. */
+                               q = strrchr(resolved, '/') + 1;
+                               *q = '\0';
+                               resolved_len = q - resolved;
+                       }
+
+                       /*
+                        * If there are any path components left, then
+                        * append them to symlink. The result is placed
+                        * in `left'.
+                        */
+                       if (p != NULL) {
+                               if (symlink[slen - 1] != '/') {
+                                       if (slen + 1 >= (ssize_t)sizeof(symlink)) {
+                                               errno = ENAMETOOLONG;
+                                               return (NULL);
+                                       }
+                                       symlink[slen] = '/';
+                                       symlink[slen + 1] = 0;
+                               }
+                               left_len = strlcat(symlink, left,
+                                   sizeof(symlink));
+                               if (left_len >= sizeof(symlink)) {
+                                       errno = ENAMETOOLONG;
+                                       return (NULL);
+                               }
+                       }
+                       left_len = strlcpy(left, symlink, sizeof(left));
+               } else if (!S_ISDIR(sb.st_mode) && p != NULL) {
+                       errno = ENOTDIR;
+                       return (NULL);
+               }
+       }
+
+       /*
+        * Remove trailing slash except when the resolved pathname
+        * is a single "/".
+        */
+       if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
+               resolved[resolved_len - 1] = '\0';
+       return (resolved);
+}
+
+#endif /* !defined(SYS_WINNT) && !defined(HAVE_POSIX_REALPATH) */
+/* ================================================================== */
+
+char *
+ntp_realpath(const char * path)
+{
+       char *res, *m;
+
+#   if defined(SYS_WINNT)
+
+       (void)m;
+       if (path == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (path[0] == '\0') {
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       return strdup(path); /* this clearly needs some work! */
+
+#   elif defined(HAVE_FUNC_POSIX_REALPATH)
+
+       (void)m;
+       return realpath(path, NULL);
+
+#   else
+
+       if (path == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (path[0] == '\0') {
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       m = malloc(NTP_PATH_MAX);
+       if (m == NULL)
+               return (NULL);
+       
+       res = realpath1(path, m);
+       if (res != NULL)
+               res = realloc(res, strlen(res) + 1);
+       if (res == NULL)
+               free(m);
+
+#   endif
+
+       return (res);
+}
index 0cb2fc408abbe9282bf57f52f3bd6d9032451bbe..fa8bc29d7974ea31b66fc25730d0614e338aa283 100644 (file)
@@ -501,9 +501,10 @@ gpsd_start(
 {
        clockprocT  * const pp = peer->procptr;
        gpsd_unitT  * up;
-       gpsd_unitT ** uscan    = &s_clock_units;
+       gpsd_unitT ** uscan    = &s_clock_units;        
 
-       struct stat sb;
+       struct stat     sb;
+       char *          devname = NULL;
 
        /* check if we can proceed at all or if init failed */
        if ( ! gpsd_init_check())
@@ -531,17 +532,30 @@ gpsd_start(
                 * practicable, we will have to read the symlink, if
                 * any, so we can get the true device file.)
                 */
-               if (-1 == myasprintf(&up->device, "%s%u",
+               if (-1 == myasprintf(&devname, "%s%u",
                                     s_dev_stem, up->unit)) {
                        msyslog(LOG_ERR, "%s: clock device name too long",
                                up->logname);
                        goto dev_fail;
                }
-               if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) {
+               up->device = ntp_realpath(devname);
+               if (NULL == up->device) {
+                       msyslog(LOG_ERR, "%s: '%s' has no absolute path",
+                               up->logname, devname);
+                       goto dev_fail;
+               }
+               if (-1 == lstat(up->device, &sb)) {
+                       msyslog(LOG_ERR, "%s: '%s' not accessible",
+                               up->logname, up->device);
+                       goto dev_fail;
+               }
+               if (!S_ISCHR(sb.st_mode)) {
                        msyslog(LOG_ERR, "%s: '%s' is not a character device",
                                up->logname, up->device);
                        goto dev_fail;
                }
+               free(devname);
+               devname = NULL;
        } else {
                /* All set up, just increment use count. */
                ++up->refcount;
@@ -585,7 +599,7 @@ gpsd_start(
 
 dev_fail:
        /* On failure, remove all UNIT ressources and declare defeat. */
-
+       free(devname);
        INSIST (up);
        if (!--up->refcount) {
                *uscan = up->next_unit;
@@ -2205,6 +2219,7 @@ log_data(
        }
 }
 
+
 #else
 NONEMPTY_TRANSLATION_UNIT
 #endif /* REFCLOCK && CLOCK_GPSDJSON */
index d96ad3af453ba88add283ec6cba96d33780332a6..f2534ba552ba3e63604695dd74679ccadb23ef75 100644 (file)
@@ -67,7 +67,7 @@ main (int argc, char **argv) {
     snmp_enable_stderrlog();
 
   /* Become Subagent */
-    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
+  netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
  
   /* go into background mode, if requested */
   if (background && netsnmp_daemonize(1, !use_syslog))
diff --git a/sntp/m4/realpath.m4 b/sntp/m4/realpath.m4
new file mode 100644 (file)
index 0000000..4deaaed
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# SYNOPSIS
+#
+#   NTP_FUNC_REALPATH
+#
+# DESCRIPTION
+#
+#   This macro defines HAVE_FUNC_REALPATH if we have a realpath()
+#   function that accepts NULL as the 2nd argument.
+#
+# LICENSE
+#
+#   Copyright (c) 2020 Network Time Foundation
+#
+#   Author: Harlan Stenn <stenn@nwtime.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 1
+
+AC_DEFUN([NTP_FUNC_REALPATH], [
+       AC_MSG_CHECKING([for POSIX-2008 compliant realpath()])
+       AC_REQUIRE([AC_PROG_CC_C99])
+
+       AC_LANG_PUSH([C])
+
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+                       #include <sys/param.h>
+                       #include <stdlib.h>
+                       int main() { return (NULL == realpath(".", NULL)); }
+                       ]])],
+               ans="yes",
+               ans="no",
+               ans="CROSS COMPILE!"
+               )
+       AC_MSG_RESULT([$ans])
+       case "$ans" in
+        yes)
+           AC_DEFINE([HAVE_FUNC_POSIX_REALPATH], [1],
+                       [Define to 1 if we have realpath() that supports NULL as the 2nd argument])
+           ;;
+       esac
+
+       AC_LANG_POP([C])
+       ]);