* Create path and any parent directories as needed.
* If is_temp is set, use mkdtemp() for the final directory.
*/
-static void
+static bool
io_mkdirs(char *path, mode_t mode, bool is_temp)
{
struct stat sb;
gid_t parent_gid = 0;
char *slash = path;
+ bool ok = true;
debug_decl(io_mkdirs, SUDO_DEBUG_UTIL)
/* Fast path: not a temporary and already exists. */
if (!is_temp && stat(path, &sb) == 0) {
if (!S_ISDIR(sb.st_mode)) {
- log_fatal(0, N_("%s exists but is not a directory (0%o)"),
+ log_warning(0, N_("%s exists but is not a directory (0%o)"),
path, (unsigned int) sb.st_mode);
+ ok = false;
}
- debug_return;
+ debug_return_bool(ok);
}
while ((slash = strchr(slash + 1, '/')) != NULL) {
*slash = '\0';
if (stat(path, &sb) != 0) {
- if (mkdir(path, mode) != 0)
- log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path);
+ if (mkdir(path, mode) != 0) {
+ log_warning(USE_ERRNO, N_("unable to mkdir %s"), path);
+ ok = false;
+ break;
+ }
ignore_result(chown(path, (uid_t)-1, parent_gid));
} else if (!S_ISDIR(sb.st_mode)) {
- log_fatal(0, N_("%s exists but is not a directory (0%o)"),
+ log_warning(0, N_("%s exists but is not a directory (0%o)"),
path, (unsigned int) sb.st_mode);
+ ok = false;
+ break;
} else {
/* Inherit gid of parent dir for ownership. */
parent_gid = sb.st_gid;
}
*slash = '/';
}
- /* Create final path component. */
- if (is_temp) {
- if (mkdtemp(path) == NULL)
- log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path);
- ignore_result(chown(path, (uid_t)-1, parent_gid));
- } else {
- if (mkdir(path, mode) != 0 && errno != EEXIST)
- log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path);
- ignore_result(chown(path, (uid_t)-1, parent_gid));
+ if (ok) {
+ /* Create final path component. */
+ if (is_temp) {
+ if (mkdtemp(path) == NULL) {
+ log_warning(USE_ERRNO, N_("unable to mkdir %s"), path);
+ ok = false;
+ } else {
+ ignore_result(chown(path, (uid_t)-1, parent_gid));
+ }
+ } else {
+ if (mkdir(path, mode) != 0 && errno != EEXIST) {
+ log_warning(USE_ERRNO, N_("unable to mkdir %s"), path);
+ ok = false;
+ } else {
+ ignore_result(chown(path, (uid_t)-1, parent_gid));
+ }
+ }
}
- debug_return;
+ debug_return_bool(ok);
}
/*
* Set max session ID (aka sequence number)
*/
-int
+bool
io_set_max_sessid(const char *maxval)
{
const char *errstr;
* number, and update the on-disk copy.
* Uses file locking to avoid sequence number collisions.
*/
-void
+bool
io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
{
struct stat sb;
/*
* Create I/O log directory if it doesn't already exist.
*/
- io_mkdirs(iolog_dir, S_IRWXU, false);
+ if (!io_mkdirs(iolog_dir, S_IRWXU, false))
+ debug_return_bool(false);
/*
* Open sequence file
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
if (len <= 0 || (size_t)len >= sizeof(pathbuf)) {
errno = ENAMETOOLONG;
- log_fatal(USE_ERRNO, "%s/seq", pathbuf);
+ log_warning(USE_ERRNO, "%s/seq", pathbuf);
+ debug_return_bool(false);
}
fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
- if (fd == -1)
- log_fatal(USE_ERRNO, N_("unable to open %s"), pathbuf);
+ if (fd == -1) {
+ log_warning(USE_ERRNO, N_("unable to open %s"), pathbuf);
+ debug_return_bool(false);
+ }
lock_file(fd, SUDO_LOCK);
/*
if (id == 0) {
nread = read(fd, buf, sizeof(buf) - 1);
if (nread != 0) {
- if (nread == -1)
- log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf);
+ if (nread == -1) {
+ log_warning(USE_ERRNO, N_("unable to read %s"), pathbuf);
+ debug_return_bool(false);
+ }
if (buf[nread - 1] == '\n')
nread--;
buf[nread] = '\0';
sessid[6] = '\0';
/* Rewind and overwrite old seq file, including the NUL byte. */
- if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
- log_fatal(USE_ERRNO, N_("unable to write to %s"), pathbuf);
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) {
+ log_warning(USE_ERRNO, N_("unable to write to %s"), pathbuf);
+ debug_return_bool(false);
+ }
close(fd);
- debug_return;
+ debug_return_bool(true);
}
/*
* Copy iolog_path to pathbuf and create the directory and any intermediate
* directories. If iolog_path ends in 'XXXXXX', use mkdtemp().
+ * Returns SIZE_MAX on error.
*/
static size_t
mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
len = strlcpy(pathbuf, iolog_path, pathsize);
if (len >= pathsize) {
errno = ENAMETOOLONG;
- log_fatal(USE_ERRNO, "%s", iolog_path);
+ log_warning(USE_ERRNO, "%s", iolog_path);
+ debug_return_size_t((size_t)-1);
}
/*
*/
if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0)
is_temp = true;
- io_mkdirs(pathbuf, S_IRWXU, is_temp);
+ if (!io_mkdirs(pathbuf, S_IRWXU, is_temp))
+ len = (size_t)-1;
debug_return_size_t(len);
}
* Uses zlib if docompress is true.
* Stores the open file handle which has the close-on-exec flag set.
*/
-static void
+static bool
open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress)
{
int fd;
#endif
iol->fd.f = fdopen(fd, "w");
}
- if (fd == -1 || iol->fd.v == NULL)
- log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf);
+ if (fd == -1 || iol->fd.v == NULL) {
+ log_warning(USE_ERRNO, N_("unable to create %s"), pathbuf);
+ debug_return_bool(false);
+ }
} else {
/* Remove old log file if we recycled sequence numbers. */
unlink(pathbuf);
}
- debug_return;
+ debug_return_bool(true);
}
/*
}
break;
case 'm':
- if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0)
+ if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0) {
io_set_max_sessid(*cur + sizeof("maxseq=") - 1);
+ continue;
+ }
break;
case 'r':
if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
/*
* Write the "/log" file that contains the user and command info.
*/
-void
+static bool
write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
char * const argv[], struct timeval *now)
{
char * const *av;
FILE *fp;
int fd;
+ debug_decl(write_info_log, SUDO_DEBUG_UTIL)
pathbuf[len] = '\0';
strlcat(pathbuf, "/log", PATH_MAX);
fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
- if (fd == -1 || (fp = fdopen(fd, "w")) == NULL)
- log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf);
+ if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
+ log_warning(USE_ERRNO, N_("unable to create %s"), pathbuf);
+ debug_return_bool(false);
+ }
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s", (long long)now->tv_sec,
details->user ? details->user : "unknown", details->runas_pw->pw_name,
}
fputc('\n', fp);
fclose(fp);
+ debug_return_bool(ferror(fp) == 0);
}
static int
/* Get next session ID and convert it into a path. */
tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2);
memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR));
- io_nextid(tofree, NULL, sessid);
+ if (!io_nextid(tofree, NULL, sessid)) {
+ rval = false;
+ goto done;
+ }
snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2,
"%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3],
sessid[4], sessid[5]);
write_info_log(pathbuf, len, &details, argv, &last_time);
/* Create the timing and I/O log files. */
- for (i = 0; i < IOFD_MAX; i++)
- open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress);
+ for (i = 0; i < IOFD_MAX; i++) {
+ if (!open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress))
+ goto done;
+ }
/*
* Clear I/O log function pointers for disabled log functions.