Add sudo_strsplit(), similar to strtok_r() but non-destructive and
operates on non-C strings (requires a length parameter).
This commit is contained in:
1
MANIFEST
1
MANIFEST
@@ -162,6 +162,7 @@ lib/util/strlcpy.c
|
||||
lib/util/strndup.c
|
||||
lib/util/strnlen.c
|
||||
lib/util/strsignal.c
|
||||
lib/util/strsplit.c
|
||||
lib/util/strtobool.c
|
||||
lib/util/strtoid.c
|
||||
lib/util/strtomode.c
|
||||
|
@@ -201,6 +201,10 @@ __dso_public int sudo_secure_file_v1(const char *path, uid_t uid, gid_t gid, str
|
||||
__dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids);
|
||||
#define sudo_setgroups(_a, _b) sudo_setgroups_v1((_a), (_b))
|
||||
|
||||
/* strsplit.c */
|
||||
__dso_public const char *sudo_strsplit_v1(const char *str, const char *endstr, const char *sep, const char **last);
|
||||
#define sudo_strsplit(_a, _b, _c, _d) sudo_strsplit_v1(_a, _b, _c, _d)
|
||||
|
||||
/* strtobool.c */
|
||||
__dso_public int sudo_strtobool_v1(const char *str);
|
||||
#define sudo_strtobool(_a) sudo_strtobool_v1((_a))
|
||||
|
@@ -101,8 +101,9 @@ SHELL = @SHELL@
|
||||
|
||||
LTOBJS = alloc.lo event.lo fatal.lo key_val.lo gethostname.lo gettime.lo \
|
||||
gidlist.lo lbuf.lo locking.lo parseln.lo progname.lo secure_path.lo \
|
||||
setgroups.lo strtobool.lo strtoid.lo strtomode.lo sudo_conf.lo \
|
||||
sudo_debug.lo sudo_dso.lo term.lo ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@
|
||||
setgroups.lo strsplit.lo strtobool.lo strtoid.lo strtomode.lo \
|
||||
sudo_conf.lo sudo_debug.lo sudo_dso.lo term.lo ttysize.lo \
|
||||
@COMMON_OBJS@ @LTLIBOBJS@
|
||||
|
||||
ATOFOO_TEST_OBJS = atofoo_test.lo
|
||||
|
||||
@@ -333,10 +334,9 @@ conf_test.lo: $(srcdir)/regress/sudo_conf/conf_test.c \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/sudo_conf/conf_test.c
|
||||
event.lo: $(srcdir)/event.c $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_event.h $(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
event.lo: $(srcdir)/event.c $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/event.c
|
||||
event_poll.lo: $(srcdir)/event_poll.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h \
|
||||
@@ -345,15 +345,15 @@ event_poll.lo: $(srcdir)/event_poll.c $(incdir)/compat/stdbool.h \
|
||||
$(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/event_poll.c
|
||||
event_select.lo: $(srcdir)/event_select.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_event.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/event_select.c
|
||||
fatal.lo: $(srcdir)/fatal.c $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
fatal.lo: $(srcdir)/fatal.c $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/fatal.c
|
||||
fnm_test.lo: $(srcdir)/regress/fnmatch/fnm_test.c $(incdir)/compat/fnmatch.h \
|
||||
$(incdir)/sudo_compat.h $(top_builddir)/config.h
|
||||
@@ -492,6 +492,11 @@ strnlen.lo: $(srcdir)/strnlen.c $(incdir)/sudo_compat.h $(top_builddir)/config.h
|
||||
strsignal.lo: $(srcdir)/strsignal.c $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_gettext.h $(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/strsignal.c
|
||||
strsplit.lo: $(srcdir)/strsplit.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/strsplit.c
|
||||
strtobool.lo: $(srcdir)/strtobool.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
|
80
lib/util/strsplit.c
Normal file
80
lib/util/strsplit.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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 */
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
|
||||
/*
|
||||
* Like strtok_r but non-destructive and works w/o a NUL terminator.
|
||||
* TODO: Optimize by storing current char in a variable ch
|
||||
*/
|
||||
const char *
|
||||
sudo_strsplit_v1(const char *str, const char *endstr, const char *sep, const char **last)
|
||||
{
|
||||
const char *cp, *s;
|
||||
debug_decl(sudo_strsplit, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* If no str specified, use last ptr (if any). */
|
||||
if (str == NULL)
|
||||
str = *last;
|
||||
|
||||
/* Skip leading separator characters. */
|
||||
while (str < endstr) {
|
||||
for (s = sep; *s != '\0'; s++) {
|
||||
if (*str == *s) {
|
||||
str++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*s == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
/* Empty string? */
|
||||
if (str >= endstr) {
|
||||
*last = endstr;
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/* Scan str until we hit a char from sep. */
|
||||
for (cp = str; cp < endstr; cp++) {
|
||||
for (s = sep; *s != '\0'; s++) {
|
||||
if (*cp == *s)
|
||||
break;
|
||||
}
|
||||
if (*s != '\0')
|
||||
break;
|
||||
}
|
||||
*last = cp;
|
||||
debug_return_const_ptr(str);
|
||||
}
|
@@ -80,6 +80,7 @@ sudo_parseln_v1
|
||||
sudo_secure_dir_v1
|
||||
sudo_secure_file_v1
|
||||
sudo_setgroups_v1
|
||||
sudo_strsplit_v1
|
||||
sudo_strtobool_v1
|
||||
sudo_strtoid_v1
|
||||
sudo_strtomode_v1
|
||||
|
@@ -1046,48 +1046,60 @@ sudoers_cleanup(void)
|
||||
}
|
||||
|
||||
static char *
|
||||
resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, int *argc_out, char ***argv_out)
|
||||
resolve_editor(const char *ed, size_t edlen, int nfiles, char **files,
|
||||
int *argc_out, char ***argv_out)
|
||||
{
|
||||
char *cp, **nargv, *editor, *editor_path = NULL;
|
||||
int ac, i, nargc;
|
||||
bool wasblank;
|
||||
char **nargv, *editor, *editor_path = NULL;
|
||||
const char *cp, *ep, *tmp;
|
||||
const char *edend = ed + edlen;
|
||||
int nargc;
|
||||
debug_decl(resolve_editor, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
/* Note: editor becomes part of argv_out and is not freed. */
|
||||
editor = sudo_emalloc(edlen + 1);
|
||||
memcpy(editor, ed, edlen);
|
||||
editor[edlen] = '\0';
|
||||
|
||||
/*
|
||||
* Split editor into an argument vector; editor is reused (do not free).
|
||||
* Split editor into an argument vector, including files to edit.
|
||||
* The EDITOR and VISUAL environment variables may contain command
|
||||
* line args so look for those and alloc space for them too.
|
||||
*/
|
||||
nargc = 1;
|
||||
for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
|
||||
if (isblank((unsigned char) *cp))
|
||||
wasblank = true;
|
||||
else if (wasblank) {
|
||||
wasblank = false;
|
||||
nargc++;
|
||||
}
|
||||
}
|
||||
/* If we can't find the editor in the user's PATH, give up. */
|
||||
cp = strtok(editor, " \t");
|
||||
if (cp == NULL ||
|
||||
find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
|
||||
sudo_efree(editor);
|
||||
cp = sudo_strsplit(ed, edend, " \t", &ep);
|
||||
if (cp == NULL)
|
||||
debug_return_str(NULL);
|
||||
editor = strndup(cp, (size_t)(ep - cp));
|
||||
if (editor == NULL) {
|
||||
sudo_warnx(U_("unable to allocate memory"));
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
nargv = (char **) sudo_emallocarray(nargc + 1 + nfiles + 1, sizeof(char *));
|
||||
for (ac = 0; cp != NULL && ac < nargc; ac++) {
|
||||
nargv[ac] = cp;
|
||||
cp = strtok(NULL, " \t");
|
||||
|
||||
/* If we can't find the editor in the user's PATH, give up. */
|
||||
if (find_path(editor, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
|
||||
free(editor);
|
||||
errno = ENOENT;
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
nargv[ac++] = "--";
|
||||
for (i = 0; i < nfiles; )
|
||||
nargv[ac++] = files[i++];
|
||||
nargv[ac] = NULL;
|
||||
|
||||
/* Count rest of arguments and allocate editor argv. */
|
||||
for (nargc = 1, tmp = ep; sudo_strsplit(NULL, edend, " \t", &tmp) != NULL; )
|
||||
nargc++;
|
||||
nargv = reallocarray(NULL, nargc + 1 + nfiles + 1, sizeof(char *));
|
||||
if (nargv == NULL) {
|
||||
sudo_warnx(U_("unable to allocate memory"));
|
||||
free(editor);
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
|
||||
/* Fill in editor argv (assumes files[] is NULL-terminated). */
|
||||
nargv[0] = editor;
|
||||
for (nargc = 1; (cp = sudo_strsplit(NULL, edend, " \t", &ep)) != NULL; nargc++) {
|
||||
nargv[nargc] = strndup(cp, (size_t)(ep - cp));
|
||||
if (nargv[nargc] == NULL) {
|
||||
sudo_warnx(U_("unable to allocate memory"));
|
||||
while (nargc--)
|
||||
free(nargv[nargc]);
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
}
|
||||
nargv[nargc++] = "--";
|
||||
while ((nargv[nargc++] = *files++) != NULL)
|
||||
continue;
|
||||
|
||||
*argc_out = nargc;
|
||||
*argv_out = nargv;
|
||||
@@ -1118,6 +1130,8 @@ find_editor(int nfiles, char **files, int *argc_out, char ***argv_out)
|
||||
if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
|
||||
editor_path = resolve_editor(editor, strlen(editor), nfiles,
|
||||
files, argc_out, argv_out);
|
||||
if (editor_path == NULL && errno != ENOENT)
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
}
|
||||
if (editor_path == NULL) {
|
||||
@@ -1129,6 +1143,8 @@ find_editor(int nfiles, char **files, int *argc_out, char ***argv_out)
|
||||
else
|
||||
len = strlen(cp);
|
||||
editor_path = resolve_editor(cp, len, nfiles, files, argc_out, argv_out);
|
||||
if (editor_path == NULL && errno != ENOENT)
|
||||
debug_return_str(NULL);
|
||||
cp = ep + 1;
|
||||
} while (ep != NULL && editor_path == NULL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user