diff options
Diffstat (limited to 'src/misc')
-rw-r--r-- | src/misc/getopt.c | 3 | ||||
-rw-r--r-- | src/misc/initgroups.c | 26 | ||||
-rw-r--r-- | src/misc/mntent.c | 46 | ||||
-rw-r--r-- | src/misc/nftw.c | 4 | ||||
-rw-r--r-- | src/misc/syslog.c | 3 |
5 files changed, 70 insertions, 12 deletions
diff --git a/src/misc/getopt.c b/src/misc/getopt.c index c3f66995..b02b81c3 100644 --- a/src/misc/getopt.c +++ b/src/misc/getopt.c @@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring) if (optstring[i] == ':') { optarg = 0; if (optstring[i+1] != ':' || optpos) { - optarg = argv[optind++] + optpos; + optarg = argv[optind++]; + if (optpos) optarg += optpos; optpos = 0; } if (optind > argc) { diff --git a/src/misc/initgroups.c b/src/misc/initgroups.c index 922a9581..101f5c7b 100644 --- a/src/misc/initgroups.c +++ b/src/misc/initgroups.c @@ -1,11 +1,29 @@ #define _GNU_SOURCE #include <grp.h> #include <limits.h> +#include <stdlib.h> int initgroups(const char *user, gid_t gid) { - gid_t groups[NGROUPS_MAX]; - int count = NGROUPS_MAX; - if (getgrouplist(user, gid, groups, &count) < 0) return -1; - return setgroups(count, groups); + gid_t buf[32], *groups = buf; + int count = sizeof buf / sizeof *buf, prev_count = count; + while (getgrouplist(user, gid, groups, &count) < 0) { + if (groups != buf) free(groups); + + /* Return if failure isn't buffer size */ + if (count <= prev_count) + return -1; + + /* Always increase by at least 50% to limit to + * logarithmically many retries on TOCTOU races. */ + if (count < prev_count + (prev_count>>1)) + count = prev_count + (prev_count>>1); + + groups = calloc(count, sizeof *groups); + if (!groups) return -1; + prev_count = count; + } + int ret = setgroups(count, groups); + if (groups != buf) free(groups); + return ret; } diff --git a/src/misc/mntent.c b/src/misc/mntent.c index d404fbe3..78bf0cd0 100644 --- a/src/misc/mntent.c +++ b/src/misc/mntent.c @@ -20,6 +20,42 @@ int endmntent(FILE *f) return 1; } +static char *unescape_ent(char *beg) +{ + char *dest = beg; + const char *src = beg; + while (*src) { + const char *val; + unsigned char cval = 0; + if (*src != '\\') { + *dest++ = *src++; + continue; + } + if (src[1] == '\\') { + ++src; + *dest++ = *src++; + continue; + } + val = src + 1; + for (int i = 0; i < 3; ++i) { + if (*val >= '0' && *val <= '7') { + cval <<= 3; + cval += *val++ - '0'; + } else { + break; + } + } + if (cval) { + *dest++ = cval; + src = val; + } else { + *dest++ = *src++; + } + } + *dest = 0; + return beg; +} + struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { int n[8], use_internal = (linebuf == SENTINEL); @@ -45,7 +81,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle len = strlen(linebuf); if (len > INT_MAX) continue; for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len; - sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + sscanf(linebuf, " %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %d %d", n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, &mnt->mnt_freq, &mnt->mnt_passno); } while (linebuf[n[0]] == '#' || n[1]==len); @@ -55,10 +91,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle linebuf[n[5]] = 0; linebuf[n[7]] = 0; - mnt->mnt_fsname = linebuf+n[0]; - mnt->mnt_dir = linebuf+n[2]; - mnt->mnt_type = linebuf+n[4]; - mnt->mnt_opts = linebuf+n[6]; + mnt->mnt_fsname = unescape_ent(linebuf+n[0]); + mnt->mnt_dir = unescape_ent(linebuf+n[2]); + mnt->mnt_type = unescape_ent(linebuf+n[4]); + mnt->mnt_opts = unescape_ent(linebuf+n[6]); return mnt; } diff --git a/src/misc/nftw.c b/src/misc/nftw.c index fcd25a73..71bc62ee 100644 --- a/src/misc/nftw.c +++ b/src/misc/nftw.c @@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, int err; struct FTW lev; + st.st_dev = st.st_ino = 0; + if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st)) type = FTW_SLN; @@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, type = FTW_F; } - if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) + if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev) return 0; new.chain = h; diff --git a/src/misc/syslog.c b/src/misc/syslog.c index 7dc0c1be..710202f9 100644 --- a/src/misc/syslog.c +++ b/src/misc/syslog.c @@ -11,6 +11,7 @@ #include <fcntl.h> #include "lock.h" #include "fork_impl.h" +#include "locale_impl.h" static volatile int lock[1]; static char log_ident[32]; @@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap) now = time(NULL); gmtime_r(&now, &tm); - strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE); pid = (log_opt & LOG_PID) ? getpid() : 0; l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", |