--- embedaddon/sudo/common/fileops.c 2012/05/29 12:26:49 1.1.1.2 +++ embedaddon/sudo/common/fileops.c 2013/07/22 10:46:11 1.1.1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005, 2007, 2009-2011 + * Copyright (c) 1999-2005, 2007, 2009-2013 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -22,29 +22,40 @@ #include #include -#include #include #ifdef HAVE_FLOCK # include #endif /* HAVE_FLOCK */ -#include -#ifdef HAVE_STDBOOL_H -# include +#ifdef STDC_HEADERS +# include +# include #else -# include "compat/stdbool.h" -#endif +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ #ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif # include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H # include -#endif /* HAVE_STRINGS_H */ +#endif /* HAVE_STRING_H */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ #include -#include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif #if TIME_WITH_SYS_TIME # include #endif @@ -56,10 +67,6 @@ #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. */ @@ -152,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; + size_t size = total + len + 1; + + if (size < 64) { + size = 64; + } else if (size <= 0x80000000) { + /* 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); }