diff options
Diffstat (limited to 'src/common/util.c')
-rw-r--r-- | src/common/util.c | 200 |
1 files changed, 79 insertions, 121 deletions
diff --git a/src/common/util.c b/src/common/util.c index b5a3ade2b..16e737023 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -934,7 +934,7 @@ esc_for_log(const char *s) char *result, *outp; size_t len = 3; if (!s) { - return tor_strdup(""); + return tor_strdup("(null)"); } for (cp = s; *cp; ++cp) { @@ -1503,83 +1503,6 @@ update_approx_time(time_t now) #endif /* ===== - * Fuzzy time - * XXXX022 Use this consistently or rip most of it out. - * ===== */ - -/* In a perfect world, everybody would run NTP, and NTP would be perfect, so - * if we wanted to know "Is the current time before time X?" we could just say - * "time(NULL) < X". - * - * But unfortunately, many users are running Tor in an imperfect world, on - * even more imperfect computers. Hence, we need to track time oddly. We - * model the user's computer as being "skewed" from accurate time by - * -<b>ftime_skew</b> seconds, such that our best guess of the current time is - * time(NULL)+ftime_skew. We also assume that our measurements of time may - * have up to <b>ftime_slop</b> seconds of inaccuracy; IOW, our window of - * estimate for the current time is now + ftime_skew +/- ftime_slop. - */ -/** Our current estimate of our skew, such that we think the current time is - * closest to time(NULL)+ftime_skew. */ -static int ftime_skew = 0; -/** Tolerance during time comparisons, in seconds. */ -static int ftime_slop = 60; -/** Set the largest amount of sloppiness we'll allow in fuzzy time - * comparisons. */ -void -ftime_set_maximum_sloppiness(int seconds) -{ - tor_assert(seconds >= 0); - ftime_slop = seconds; -} -/** Set the amount by which we believe our system clock to differ from - * real time. */ -void -ftime_set_estimated_skew(int seconds) -{ - ftime_skew = seconds; -} -#if 0 -void -ftime_get_window(time_t now, ftime_t *ft_out) -{ - ft_out->earliest = now + ftime_skew - ftime_slop; - ft_out->latest = now + ftime_skew + ftime_slop; -} -#endif -/** Return true iff we think that <b>now</b> might be after <b>when</b>. */ -int -ftime_maybe_after(time_t now, time_t when) -{ - /* It may be after when iff the latest possible current time is after when */ - return (now + ftime_skew + ftime_slop) >= when; -} -/** Return true iff we think that <b>now</b> might be before <b>when</b>. */ -int -ftime_maybe_before(time_t now, time_t when) -{ - /* It may be before when iff the earliest possible current time is before */ - return (now + ftime_skew - ftime_slop) < when; -} -/** Return true if we think that <b>now</b> is definitely after <b>when</b>. */ -int -ftime_definitely_after(time_t now, time_t when) -{ - /* It is definitely after when if the earliest time it could be is still - * after when. */ - return (now + ftime_skew - ftime_slop) >= when; -} -/** Return true if we think that <b>now</b> is definitely before <b>when</b>. - */ -int -ftime_definitely_before(time_t now, time_t when) -{ - /* It is definitely before when if the latest time it could be is still - * before when. */ - return (now + ftime_skew + ftime_slop) < when; -} - -/* ===== * Rate limiting * ===== */ @@ -2498,18 +2421,21 @@ digit_to_num(char d) * success, store the result in <b>out</b>, advance bufp to the next * character, and return 0. On failure, return -1. */ static int -scan_unsigned(const char **bufp, unsigned *out, int width) +scan_unsigned(const char **bufp, unsigned *out, int width, int base) { unsigned result = 0; int scanned_so_far = 0; + const int hex = base==16; + tor_assert(base == 10 || base == 16); if (!bufp || !*bufp || !out) return -1; if (width<0) width=MAX_SCANF_WIDTH; - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - int digit = digit_to_num(*(*bufp)++); - unsigned new_result = result * 10 + digit; + while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) + && scanned_so_far < width) { + int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); + unsigned new_result = result * base + digit; if (new_result > UINT32_MAX || new_result < result) return -1; /* over/underflow. */ result = new_result; @@ -2571,11 +2497,12 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap) if (!width) /* No zero-width things. */ return -1; } - if (*pattern == 'u') { + if (*pattern == 'u' || *pattern == 'x') { unsigned *u = va_arg(ap, unsigned *); + const int base = (*pattern == 'u') ? 10 : 16; if (!*buf) return n_matched; - if (scan_unsigned(&buf, u, width)<0) + if (scan_unsigned(&buf, u, width, base)<0) return n_matched; ++pattern; ++n_matched; @@ -2612,9 +2539,9 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap) /** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> * and store the results in the corresponding argument fields. Differs from - * sscanf in that it: Only handles %u and %Ns. Does not handle arbitrarily - * long widths. %u does not consume any space. Is locale-independent. - * Returns -1 on malformed patterns. + * sscanf in that it: Only handles %u and %x and %Ns. Does not handle + * arbitrarily long widths. %u and %x do not consume any space. Is + * locale-independent. Returns -1 on malformed patterns. * * (As with other locale-independent functions, we need this to parse data that * is in ASCII without worrying that the C library's locale-handling will make @@ -2879,17 +2806,34 @@ load_windows_system_library(const TCHAR *library_name) } #endif -/** Format child_state and saved_errno as a hex string placed in hex_errno. - * Called between fork and _exit, so must be signal-handler safe */ +/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in + * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler + * safe. + * + * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE bytes available. + * + * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded + * with spaces. Note that there is no trailing \0. CHILD_STATE indicates where + * in the processs of starting the child process did the failure occur (see + * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of + * errno when the failure occurred. + */ + void format_helper_exit_status(unsigned char child_state, int saved_errno, char *hex_errno) { - /* Convert errno to be unsigned for hex conversion */ unsigned int unsigned_errno; char *cur; + size_t i; + + /* Fill hex_errno with spaces, and a trailing newline (memset may + not be signal handler safe, so we can't use it) */ + for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) + hex_errno[i] = ' '; + hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; - /* If errno is negative, negate it */ + /* Convert errno to be unsigned for hex conversion */ if (saved_errno < 0) { unsigned_errno = (unsigned int) -saved_errno; } else { @@ -2899,17 +2843,26 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, /* Convert errno to hex (start before \n) */ cur = hex_errno + HEX_ERRNO_SIZE - 2; + /* Check for overflow on first iteration of the loop */ + if (cur < hex_errno) + return; + do { *cur-- = "0123456789ABCDEF"[unsigned_errno % 16]; unsigned_errno /= 16; } while (unsigned_errno != 0 && cur >= hex_errno); - /* Add on the minus side if errno was negative */ - if (saved_errno < 0) + /* Prepend the minus sign if errno was negative */ + if (saved_errno < 0 && cur >= hex_errno) *cur-- = '-'; /* Leave a gap */ - *cur-- = '/'; + if (cur >= hex_errno) + *cur-- = '/'; + + /* Check for overflow on first iteration of the loop */ + if (cur < hex_errno) + return; /* Convert child_state to hex */ do { @@ -2934,13 +2887,20 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, #define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " -/** Start a program in the background. If <b>filename</b> contains a '/', then - * it will be treated as an absolute or relative path. Otherwise the system - * path will be searched for <b>filename</b>. Returns pid on success, otherwise - * returns -1. - * Some parts of this code are based on the POSIX subprocess module from Python +/** Start a program in the background. If <b>filename</b> contains a '/', + * then it will be treated as an absolute or relative path. Otherwise the + * system path will be searched for <b>filename</b>. The strings in + * <b>argv</b> will be passed as the command line arguments of the child + * program (following convention, argv[0] should normally be the filename of + * the executable). The last element of argv must be NULL. If the child + * program is launched, the PID will be returned and <b>stdout_read</b> and + * <b>stdout_err</b> will be set to file descriptors from which the stdout + * and stderr, respectively, output of the child program can be read, and the + * stdin of the child process shall be set to /dev/null. Otherwise returns + * -1. Some parts of this code are based on the POSIX subprocess module from + * Python. */ -static int +int tor_spawn_background(const char *const filename, int *stdout_read, int *stderr_read, const char **argv) { @@ -2970,16 +2930,12 @@ tor_spawn_background(const char *const filename, int *stdout_read, and we are not allowed to use unsafe functions between fork and exec */ error_message_length = strlen(error_message); - /* Fill hex_errno with spaces, and a trailing newline */ - memset(hex_errno, ' ', sizeof(hex_errno) - 1); - hex_errno[sizeof(hex_errno) - 1] = '\n'; - child_state = CHILD_STATE_PIPE; /* Set up pipe for redirecting stdout and stderr of child */ retval = pipe(stdout_pipe); if (-1 == retval) { - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Failed to set up pipe for stdout communication with child process: %s", strerror(errno)); return -1; @@ -2987,7 +2943,7 @@ tor_spawn_background(const char *const filename, int *stdout_read, retval = pipe(stderr_pipe); if (-1 == retval) { - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Failed to set up pipe for stderr communication with child process: %s", strerror(errno)); return -1; @@ -3039,7 +2995,8 @@ tor_spawn_background(const char *const filename, int *stdout_read, child_state = CHILD_STATE_CLOSEFD; /* Close all other fds, including the read end of the pipe */ - /* TODO: use closefrom if available */ + /* XXX: use closefrom if available, or better still set FD_CLOEXEC + on all of Tor's open files */ for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) close(fd); @@ -3055,7 +3012,7 @@ tor_spawn_background(const char *const filename, int *stdout_read, child_state = CHILD_STATE_FAILEXEC; error: - /* TODO: are we leaking fds from the pipe? */ + /* XXX: are we leaking fds from the pipe? */ format_helper_exit_status(child_state, errno, hex_errno); @@ -3071,7 +3028,7 @@ tor_spawn_background(const char *const filename, int *stdout_read, /* In parent */ if (-1 == pid) { - log_err(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); + log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); close(stdout_pipe[0]); close(stdout_pipe[1]); close(stderr_pipe[0]); @@ -3084,7 +3041,7 @@ tor_spawn_background(const char *const filename, int *stdout_read, retval = close(stdout_pipe[1]); if (-1 == retval) { - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Failed to close write end of stdout pipe in parent process: %s", strerror(errno)); /* Do not return -1, because the child is running, so the parent @@ -3095,7 +3052,7 @@ tor_spawn_background(const char *const filename, int *stdout_read, retval = close(stderr_pipe[1]); if (-1 == retval) { - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Failed to close write end of stderr pipe in parent process: %s", strerror(errno)); /* Do not return -1, because the child is running, so the parent @@ -3148,26 +3105,27 @@ log_from_pipe(FILE *stream, int severity, const char *executable, } else { /* No newline; check whether we overflowed the buffer */ if (!feof(stream)) - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Line from port forwarding helper was truncated: %s", buf); /* TODO: What to do with this error? */ } /* Check if buf starts with SPAWN_ERROR_MESSAGE */ - if (strstr(buf, SPAWN_ERROR_MESSAGE) == buf) { + if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) { /* Parse error message */ int retval, child_state, saved_errno; - retval = sscanf(buf, SPAWN_ERROR_MESSAGE "%d/%d", - &child_state, &saved_errno); + retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x", + &child_state, &saved_errno); if (retval == 2) { - log_err(LD_GENERAL, + log_warn(LD_GENERAL, "Failed to start child process \"%s\" in state %d: %s", executable, child_state, strerror(saved_errno)); if (child_status) *child_status = 1; } else { - /* Failed to parse message from child process, log it as error */ - log_err(LD_GENERAL, + /* Failed to parse message from child process, log it as a + warning */ + log_warn(LD_GENERAL, "Unexpected message from port forwarding helper \"%s\": %s", executable, buf); } @@ -3233,7 +3191,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port, child_pid = tor_spawn_background(filename, &fd_out, &fd_err, argv); if (child_pid < 0) { - log_err(LD_GENERAL, "Failed to start port forwarding helper %s", + log_warn(LD_GENERAL, "Failed to start port forwarding helper %s", filename); child_pid = -1; return; @@ -3254,7 +3212,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port, /* Read from stdout/stderr and log result */ retval = 0; stdout_status = log_from_pipe(stdout_read, LOG_INFO, filename, &retval); - stderr_status = log_from_pipe(stderr_read, LOG_ERR, filename, &retval); + stderr_status = log_from_pipe(stderr_read, LOG_WARN, filename, &retval); if (retval) { /* There was a problem in the child process */ time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL; @@ -3276,7 +3234,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port, if (1 == retval) { log_info(LD_GENERAL, "Port forwarding helper terminated"); } else { - log_err(LD_GENERAL, "Failed to read from port forwarding helper"); + log_warn(LD_GENERAL, "Failed to read from port forwarding helper"); } /* TODO: The child might not actually be finished (maybe it failed or |