]> granicus.if.org Git - sudo/commitdiff
Add line continuation support to sudo_parseln() and make it use
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 7 Feb 2013 15:56:01 +0000 (10:56 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 7 Feb 2013 15:56:01 +0000 (10:56 -0500)
getline() instead of fgets() internally.

21 files changed:
MANIFEST
common/Makefile.in
common/fileops.c
common/regress/sudo_parseln/parseln_test.c [new file with mode: 0644]
common/regress/sudo_parseln/test1.in [new file with mode: 0644]
common/regress/sudo_parseln/test1.out.ok [new file with mode: 0644]
common/regress/sudo_parseln/test2.in [new file with mode: 0644]
common/regress/sudo_parseln/test2.out.ok [new file with mode: 0644]
common/regress/sudo_parseln/test3.in [new file with mode: 0644]
common/regress/sudo_parseln/test3.out.ok [new file with mode: 0644]
common/regress/sudo_parseln/test4.in [new file with mode: 0644]
common/regress/sudo_parseln/test4.out.ok [new file with mode: 0644]
common/regress/sudo_parseln/test5.in [new file with mode: 0644]
common/regress/sudo_parseln/test5.out.ok [new file with mode: 0644]
common/regress/sudo_parseln/test6.in [new file with mode: 0644]
common/regress/sudo_parseln/test6.out.ok [new file with mode: 0644]
common/sudo_conf.c
include/fileops.h
plugins/sudoers/env.c
plugins/sudoers/ldap.c
plugins/sudoers/sudo_nss.c

index e643121c7623b2fe8e2878fe7135174845c208b1..0d6962293e6636298cd29e27e4b7c87b7894c57d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -16,6 +16,19 @@ common/fileops.c
 common/fmt_string.c
 common/lbuf.c
 common/list.c
+common/regress/sudo_parseln/parseln_test.c
+common/regress/sudo_parseln/test1.in
+common/regress/sudo_parseln/test1.out.ok
+common/regress/sudo_parseln/test2.in
+common/regress/sudo_parseln/test2.out.ok
+common/regress/sudo_parseln/test3.in
+common/regress/sudo_parseln/test3.out.ok
+common/regress/sudo_parseln/test4.in
+common/regress/sudo_parseln/test4.out.ok
+common/regress/sudo_parseln/test5.in
+common/regress/sudo_parseln/test5.out.ok
+common/regress/sudo_parseln/test6.in
+common/regress/sudo_parseln/test6.out.ok
 common/secure_path.c
 common/setgroups.c
 common/sudo_conf.c
index 7fc4cfcfe32533fb4d270216279e803c106cb10c..7a0eaa043f793aafd04a06d6311d62adc3e5af7f 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
+# Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@courtesan.com>
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -54,6 +54,11 @@ PIE_LDFLAGS = @PIE_LDFLAGS@
 SSP_CFLAGS = @SSP_CFLAGS@
 SSP_LDFLAGS = @SSP_LDFLAGS@
 
+# Regression tests
+TEST_PROGS = parseln_test
+TEST_LIBS = @LIBS@ @LIBINTL@
+TEST_LDFLAGS = @LDFLAGS@
+
 # OS dependent defines
 DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\"
 
@@ -65,6 +70,8 @@ LTOBJS = alloc.lo atobool.lo error.lo fileops.lo fmt_string.lo lbuf.lo list.lo \
         secure_path.lo setgroups.lo sudo_conf.lo sudo_debug.lo sudo_printf.lo \
         term.lo ttysize.lo zero_bytes.lo @COMMON_OBJS@
 
+PARSELN_TEST_OBJS = parseln_test.lo
+
 all: libcommon.la
 
 Makefile: $(srcdir)/Makefile.in
@@ -78,6 +85,9 @@ Makefile: $(srcdir)/Makefile.in
 libcommon.la: $(LTOBJS)
        $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install
 
+parseln_test: $(PARSELN_TEST_OBJS) libcommon.la
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(PARSELN_TEST_OBJS) libcommon.la $(TEST_LDFLAGS) $(TEST_LIBS)
+
 pre-install:
 
 install:
@@ -94,7 +104,28 @@ install-plugin:
 
 uninstall:
 
-check:
+check: $(TEST_PROGS)
+       @if test X"$(cross_compiling)" != X"yes"; then \
+           passed=0; failed=0; total=0; \
+           dir=sudo_parseln; \
+           mkdir -p regress/$$dir; \
+           for t in $(srcdir)/regress/$$dir/*.in; do \
+               base=`basename $$t .in`; \
+               out="regress/$$dir/$$base.out"; \
+               ./parseln_test <$$t >$$out; \
+               if cmp $$out $(srcdir)/$$out.ok >/dev/null; then \
+                   passed=`expr $$passed + 1`; \
+                   echo "$$dir/$$base: OK"; \
+               else \
+                   failed=`expr $$failed + 1`; \
+                   echo "$$dir/$$base: FAIL"; \
+                   diff $$out $(srcdir)/$$out.ok; \
+               fi; \
+               total=`expr $$total + 1`; \
+           done; \
+           echo "$$dir: $$passed/$$total tests passed; $$failed/$$total tests failed"; \
+           exit $$failed; \
+       fi
 
 clean:
        -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
@@ -140,6 +171,10 @@ lbuf.lo: $(srcdir)/lbuf.c $(top_builddir)/config.h $(incdir)/missing.h \
 list.lo: $(srcdir)/list.c $(top_builddir)/config.h $(incdir)/missing.h \
          $(incdir)/list.h $(incdir)/error.h
        $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/list.c
+parseln_test.lo: $(srcdir)/regress/sudo_parseln/parseln_test.c \
+                 $(top_builddir)/config.h $(top_srcdir)/compat/stdbool.h \
+                 $(incdir)/missing.h $(incdir)/fileops.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/sudo_parseln/parseln_test.c
 secure_path.lo: $(srcdir)/secure_path.c $(top_builddir)/config.h \
                 $(incdir)/missing.h $(incdir)/sudo_debug.h \
                 $(incdir)/secure_path.h
index a23a42a078fb208e1d1c038d9e08b1bba763f570..e06b82cddd4946e9a1beb4c0483e23b5bb43773e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005, 2007, 2009-2011
+ * Copyright (c) 1999-2005, 2007, 2009-2013
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
 #ifdef HAVE_FLOCK
 # include <sys/file.h>
 #endif /* HAVE_FLOCK */
-#include <stdio.h>
-#ifdef HAVE_STDBOOL_H
-# include <stdbool.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
 #else
-# include "compat/stdbool.h"
-#endif
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
 #ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
 # include <string.h>
 #endif /* HAVE_STRING_H */
 #ifdef HAVE_STRINGS_H
 # include <strings.h>
-#endif /* HAVE_STRINGS_H */
+#endif /* HAVE_STRING_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
 #include <ctype.h>
-#include <limits.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <fcntl.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include "compat/stdbool.h"
+#endif
 #if TIME_WITH_SYS_TIME
 # include <time.h>
 #endif
 #include "fileops.h"
 #include "sudo_debug.h"
 
-#ifndef LINE_MAX
-# define LINE_MAX 2048
-#endif
-
 /*
  * Update the access and modify times on an fd or file.
  */
@@ -151,28 +159,75 @@ lock_file(int fd, int lockit)
 #endif
 
 /*
- * Read a line of input, remove comments and strip off leading
- * and trailing spaces.  Returns static storage that is reused.
+ * Read a line of input, honoring line continuation chars.
+ * Remove comments and strips off leading and trailing spaces.
+ * Returns the line length and updates the buf and bufsize pointers.
+ * XXX - just use a struct w/ state, including getline buffer?
+ *       could also make comment char and line continuation configurable
  */
-char *
-sudo_parseln(FILE *fp)
+ssize_t
+sudo_parseln(char **bufp, size_t *bufsizep, unsigned int *lineno, FILE *fp)
 {
-    size_t len;
-    char *cp = NULL;
-    static char buf[LINE_MAX];
+    size_t len, linesize = 0, total = 0;
+    char *cp, *line = NULL;
+    bool continued;
     debug_decl(sudo_parseln, SUDO_DEBUG_UTIL)
 
-    if (fgets(buf, sizeof(buf), fp) != NULL) {
-       /* Remove comments */
-       if ((cp = strchr(buf, '#')) != NULL)
+    do {
+       continued = false;
+       len = getline(&line, &linesize, fp);
+       if (len == -1)
+           break;
+       if (lineno != NULL)
+           (*lineno)++;
+
+       /* Remove trailing newline(s) if present. */
+       while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
+           line[--len] = '\0';
+
+       /* Remove comments or check for line continuation (but not both) */
+       if ((cp = strchr(line, '#')) != NULL) {
            *cp = '\0';
+           len = (size_t)(cp - line);
+       } else if (len > 0 && line[len - 1] == '\\' && (len == 1 || line[len - 2] != '\\')) {
+           line[--len] = '\0';
+           continued = true;
+       }
 
-       /* Trim leading and trailing whitespace/newline */
-       len = strlen(buf);
-       while (len > 0 && isspace((unsigned char)buf[len - 1]))
-           buf[--len] = '\0';
-       for (cp = buf; isblank((unsigned char)*cp); cp++)
-           continue;
-    }
-    debug_return_str(cp);
+       /* Trim leading and trailing whitespace */
+       if (!continued) {
+           while (len > 0 && isblank((unsigned char)line[len - 1]))
+               line[--len] = '\0';
+       }
+       for (cp = line; isblank((unsigned char)*cp); cp++)
+           len--;
+
+       if (*bufp == NULL || total + len >= *bufsizep) {
+           void *tmp;
+           unsigned int size = total + len + 1;
+
+           if (size < 64) {
+               size = 64;
+           } else {
+               /* Round up to next highest power of two. */
+               size--;
+               size |= size >> 1;
+               size |= size >> 2;
+               size |= size >> 4;
+               size |= size >> 8;
+               size |= size >> 16;
+               size++;
+           }
+           if ((tmp = realloc(*bufp, size)) == NULL)
+               break;
+           *bufp = tmp;
+           *bufsizep = size;
+       }
+       memcpy(*bufp + total, cp, len + 1);
+       total += len;
+    } while (continued);
+    free(line);
+    if (len == -1 && total == 0)
+       debug_return_size_t((size_t)-1);
+    debug_return_size_t(total);
 }
diff --git a/common/regress/sudo_parseln/parseln_test.c b/common/regress/sudo_parseln/parseln_test.c
new file mode 100644 (file)
index 0000000..0f3cb44
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include "compat/stdbool.h"
+#endif
+
+#include "missing.h"
+#include "fileops.h"
+
+/*
+ * Simple test driver for sudo_parseln().
+ * Behaves similarly to "cat -n" but with comment removal
+ * and line continuation.
+ */
+
+int
+main(int argc, char *argv[])
+{
+    unsigned int lineno = 0;
+    size_t linesize = 0;
+    char *line = NULL;
+
+    while (sudo_parseln(&line, &linesize, &lineno, stdin) != -1)
+       printf("%6u\t%s\n", lineno, line);
+    free(line);
+    exit(0);
+}
+
+/* STUB */
+void
+warning_set_locale(void)
+{
+    return;
+}
+
+/* STUB */
+void
+warning_restore_locale(void)
+{
+    return;
+}
diff --git a/common/regress/sudo_parseln/test1.in b/common/regress/sudo_parseln/test1.in
new file mode 100644 (file)
index 0000000..c605bb5
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Sample /etc/sudo.conf file
+#
+# Format:
+#   Plugin plugin_name plugin_path plugin_options ...
+#   Path askpass /path/to/askpass
+#   Path noexec /path/to/sudo_noexec.so
+#   Debug sudo /var/log/sudo_debug all@warn
+#   Set disable_coredump true
+#
+# Sudo plugins:
+#
+# The plugin_path is relative to ${prefix}/libexec unless fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+#   that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+
+#
+# Sudo askpass:
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support.  Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo noexec:
+#
+# Path to a shared library containing dummy versions of the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support C<LD_PRELOAD> or its equivalent.
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec /usr/libexec/sudo_noexec.so
+
+#
+# Core dumps:
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+#Set disable_coredump false
+
+#
+# User groups:
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+#   static   - use the user's list of groups returned by the kernel.
+#   dynamic  - query the group database to find the list of groups.
+#   adaptive - if user is in less than the maximum number of groups.
+#             use the kernel list, else query the group database.
+#
+#Set group_source static
diff --git a/common/regress/sudo_parseln/test1.out.ok b/common/regress/sudo_parseln/test1.out.ok
new file mode 100644 (file)
index 0000000..c98ca77
--- /dev/null
@@ -0,0 +1,72 @@
+     1 
+     2 
+     3 
+     4 
+     5 
+     6 
+     7 
+     8 
+     9 
+    10 
+    11 
+    12 
+    13 
+    14 
+    15 
+    16 
+    17 
+    18 
+    19 Plugin sudoers_policy sudoers.so
+    20 Plugin sudoers_io sudoers.so
+    21 
+    22 
+    23 
+    24 
+    25 
+    26 
+    27 
+    28 
+    29 
+    30 
+    31 
+    32 
+    33 
+    34 
+    35 
+    36 
+    37 
+    38 
+    39 
+    40 
+    41 
+    42 
+    43 
+    44 
+    45 
+    46 
+    47 
+    48 
+    49 
+    50 
+    51 
+    52 
+    53 
+    54 
+    55 
+    56 
+    57 
+    58 
+    59 
+    60 
+    61 
+    62 
+    63 
+    64 
+    65 
+    66 
+    67 
+    68 
+    69 
+    70 
+    71 
+    72 
diff --git a/common/regress/sudo_parseln/test2.in b/common/regress/sudo_parseln/test2.in
new file mode 100644 (file)
index 0000000..49166ee
--- /dev/null
@@ -0,0 +1,8 @@
+this \
+is all \
+one line
+# this is a comment, and does not get continued\
+trim the \
+       leading \
+    white \
+space
diff --git a/common/regress/sudo_parseln/test2.out.ok b/common/regress/sudo_parseln/test2.out.ok
new file mode 100644 (file)
index 0000000..d921968
--- /dev/null
@@ -0,0 +1,3 @@
+     3 this is all one line
+     4 
+     8 trim the leading white space
diff --git a/common/regress/sudo_parseln/test3.in b/common/regress/sudo_parseln/test3.in
new file mode 100644 (file)
index 0000000..e372c07
--- /dev/null
@@ -0,0 +1 @@
+line continuation at EOF \
diff --git a/common/regress/sudo_parseln/test3.out.ok b/common/regress/sudo_parseln/test3.out.ok
new file mode 100644 (file)
index 0000000..2e8d16d
--- /dev/null
@@ -0,0 +1 @@
+     1 line continuation at EOF 
diff --git a/common/regress/sudo_parseln/test4.in b/common/regress/sudo_parseln/test4.in
new file mode 100644 (file)
index 0000000..3583f3b
--- /dev/null
@@ -0,0 +1,4 @@
+line contin\
+uation raw
+line contin\
+       uation indented
diff --git a/common/regress/sudo_parseln/test4.out.ok b/common/regress/sudo_parseln/test4.out.ok
new file mode 100644 (file)
index 0000000..38afbeb
--- /dev/null
@@ -0,0 +1,2 @@
+     2 line continuation raw
+     4 line continuation indented
diff --git a/common/regress/sudo_parseln/test5.in b/common/regress/sudo_parseln/test5.in
new file mode 100644 (file)
index 0000000..57ddad2
--- /dev/null
@@ -0,0 +1 @@
+\
diff --git a/common/regress/sudo_parseln/test5.out.ok b/common/regress/sudo_parseln/test5.out.ok
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/common/regress/sudo_parseln/test6.in b/common/regress/sudo_parseln/test6.in
new file mode 100644 (file)
index 0000000..95cac84
--- /dev/null
@@ -0,0 +1,3 @@
+       leading and trailing white space        
+ # a comment
+\
diff --git a/common/regress/sudo_parseln/test6.out.ok b/common/regress/sudo_parseln/test6.out.ok
new file mode 100644 (file)
index 0000000..340765e
--- /dev/null
@@ -0,0 +1,2 @@
+     1 leading and trailing white space
+     2 
index 92628cb603bafedf1600b1170dfe215e2ae845f9..4f4e9cdd1cc0531dac3c76065ee9a935adb32761 100644 (file)
@@ -323,7 +323,9 @@ sudo_conf_read(void)
     struct sudo_conf_table *cur;
     struct stat sb;
     FILE *fp;
-    char *cp, *prev_locale = estrdup(setlocale(LC_ALL, NULL));
+    char *cp, *line = NULL;
+    char *prev_locale = estrdup(setlocale(LC_ALL, NULL));
+    size_t linesize = 0;
 
     /* Parse sudo.conf in the "C" locale. */
     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
@@ -362,9 +364,8 @@ sudo_conf_read(void)
     }
 
     lineno = 0;
-    while ((cp = sudo_parseln(fp)) != NULL) {
-       lineno++;
-       if (*cp == '\0')
+    while (sudo_parseln(&line, &linesize, &lineno, fp) != -1) {
+       if (*(cp = line) == '\0')
            continue;           /* empty line or comment */
 
        for (cur = sudo_conf_table; cur->name != NULL; cur++) {
@@ -379,6 +380,7 @@ sudo_conf_read(void)
        }
     }
     fclose(fp);
+    free(line);
 done:
     /* Restore locale if needed. */
     if (prev_locale[0] != 'C' || prev_locale[1] != '\0')
index cd0a0dfe82813ef14c5b79f5539390c49b8229ea..c3fc146802d91f84b3423e5636bbd495d7780b7c 100644 (file)
@@ -28,6 +28,6 @@ struct timeval;
 
 bool lock_file(int, int);
 int touch(int, char *, struct timeval *);
-char *sudo_parseln(FILE *);
+ssize_t  sudo_parseln(char **buf, size_t *bufsize, unsigned int *lineno, FILE *fp);
 
 #endif /* _SUDO_FILEOPS_H */
index caae19adb94e634c27be5ee4cab20a60dcbaeca4..4e2eb12b9623aa30f786e61f85ed3aac17ca1e78 100644 (file)
@@ -1029,15 +1029,15 @@ void
 read_env_file(const char *path, int overwrite)
 {
     FILE *fp;
-    char *cp, *var, *val;
-    size_t var_len, val_len;
+    char *cp, *var, *val, *line = NULL;
+    size_t var_len, val_len, linesize = 0;
 
     if ((fp = fopen(path, "r")) == NULL)
        return;
 
-    while ((var = sudo_parseln(fp)) != NULL) {
+    while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
        /* Skip blank or comment lines */
-       if (*var == '\0')
+       if (*(var = line) == '\0')
            continue;
 
        /* Skip optional "export " */
@@ -1069,6 +1069,7 @@ read_env_file(const char *path, int overwrite)
 
        sudo_putenv(cp, true, overwrite);
     }
+    free(line);
     fclose(fp);
 }
 
index a4935c7b0de73247c27b330209bfc0d588834eae..7b3e1c100454574b84bb93bb4442c76fab83d79c 100644 (file)
@@ -1360,7 +1360,8 @@ static bool
 sudo_ldap_read_config(void)
 {
     FILE *fp;
-    char *cp, *keyword, *value;
+    char *cp, *keyword, *value, *line = NULL;
+    size_t linesize = 0;
     debug_decl(sudo_ldap_read_config, SUDO_DEBUG_LDAP)
 
     /* defaults */
@@ -1377,12 +1378,12 @@ sudo_ldap_read_config(void)
     if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
        debug_return_bool(false);
 
-    while ((cp = sudo_parseln(fp)) != NULL) {
-       if (*cp == '\0')
+    while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
+       if (*line == '\0')
            continue;           /* skip empty line */
 
        /* split into keyword and value */
-       keyword = cp;
+       keyword = cp = line;
        while (*cp && !isblank((unsigned char) *cp))
            cp++;
        if (*cp)
@@ -1397,6 +1398,7 @@ sudo_ldap_read_config(void)
        if (!sudo_ldap_parse_keyword(keyword, value, ldap_conf_global))
            sudo_ldap_parse_keyword(keyword, value, ldap_conf_conn);
     }
+    free(line);
     fclose(fp);
 
     if (!ldap_conf.host)
index e2be3ac43a0a984a8b101555e22a417a1c4cf7f8..9b26fb0054351aea1a44e077966f7381432929c8 100644 (file)
@@ -61,7 +61,8 @@ struct sudo_nss_list *
 sudo_read_nss(void)
 {
     FILE *fp;
-    char *cp;
+    char *cp, *line = NULL;
+    size_t linesize = 0;
 #ifdef HAVE_SSSD
     bool saw_sss = false;
 #endif
@@ -74,17 +75,17 @@ sudo_read_nss(void)
     if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
        goto nomatch;
 
-    while ((cp = sudo_parseln(fp)) != NULL) {
+    while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
        /* Skip blank or comment lines */
-       if (*cp == '\0')
+       if (*line == '\0')
            continue;
 
        /* Look for a line starting with "sudoers:" */
-       if (strncasecmp(cp, "sudoers:", 8) != 0)
+       if (strncasecmp(line, "sudoers:", 8) != 0)
            continue;
 
        /* Parse line */
-       for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
+       for ((cp = strtok(line + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
            if (strcasecmp(cp, "files") == 0 && !saw_files) {
                tq_append(&snl, &sudo_nss_file);
                got_match = true;
@@ -112,6 +113,7 @@ sudo_read_nss(void)
        /* Only parse the first "sudoers:" line */
        break;
     }
+    free(line);
     fclose(fp);
 
 nomatch:
@@ -134,7 +136,8 @@ struct sudo_nss_list *
 sudo_read_nss(void)
 {
     FILE *fp;
-    char *cp, *ep;
+    char *cp, *ep, *line = NULL;
+    ssize_t linesize = 0;
 #ifdef HAVE_SSSD
     bool saw_sss = false;
 #endif
@@ -147,9 +150,9 @@ sudo_read_nss(void)
     if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
        goto nomatch;
 
-    while ((cp = sudo_parseln(fp)) != NULL) {
+    while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
        /* Skip blank or comment lines */
-       if (*cp == '\0')
+       if (*(cp = line) == '\0')
            continue;
 
        /* Look for a line starting with "sudoers = " */