Commit 8de9cfe1 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Resolve FIXME items: make expand_filename handle ~ and ~username


svn:r2789
parent 987cb2b9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ dnl These headers are not essential

AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h sys/time.h sys/resource.h)

AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit setrlimit strlcat strlcpy strtoull)
AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit setrlimit strlcat strlcpy strtoull getpwnam)

AC_CHECK_MEMBERS([struct timeval.tv_sec])

+17 −0
Original line number Diff line number Diff line
@@ -390,6 +390,23 @@ int switch_id(char *user, char *group) {
  return -1;
}

#ifdef HAVE_PWD_H
/** Allocate and return a string containing the home directory for the
 * user <b>username</b>. Only works on posix-like systems */
char *
get_user_homedir(const char *username)
{
  struct passwd *pw;
  tor_assert(username);

  if (!(pw = getpwnam(username))) {
    log_fn(LOG_ERR,"User '%s' not found.", username);
    return NULL;
  }
  return tor_strdup(pw->pw_dir);
}
#endif

/** Set *addr to the IP address (in dotted-quad notation) stored in c.
 * Return 1 on success, 0 if c is badly formatted.  (Like inet_aton(c,addr),
 * but works on Windows and Solaris.)
+3 −0
Original line number Diff line number Diff line
@@ -164,6 +164,9 @@ void set_uint32(char *cp, uint32_t v);

int set_max_file_descriptors(unsigned int required_min);
int switch_id(char *user, char *group);
#ifdef HAVE_PWD_H
char *get_user_homedir(const char *username);
#endif

int spawn_func(int (*func)(void *), void *data);
void spawn_exit(void);
+40 −12
Original line number Diff line number Diff line
@@ -958,22 +958,50 @@ parse_line_from_str(char *line, char **key_out, char **value_out)
char *expand_filename(const char *filename)
{
  tor_assert(filename);
  /* XXXX Should eventually check for ~username/ */
  if (!strncmp(filename,"~/",2)) {
  if (*filename == '~') {
    size_t len;
    const char *home = getenv("HOME");
    char *result;
    char *home, *result;
    const char *rest;

    if (filename[1] == '/' || filename[1] == '\0') {
      home = getenv("HOME");
      if (!home) {
        log_fn(LOG_WARN, "Couldn't find $HOME environment variable while expanding %s", filename);
        return NULL;
      }
    /* minus two characters for ~/, plus one for /, plus one for NUL.
      home = tor_strdup(home);
      rest = strlen(filename)>=2?(filename+2):NULL;
    } else {
#ifdef HAVE_PWD_H
      char *username, *slash;
      slash = strchr(filename, '/');
      if (slash)
        username = tor_strndup(filename+1,slash-filename-1);
      else
        username = tor_strdup(filename+1);
      if (!(home = get_user_homedir(username))) {
        log_fn(LOG_WARN,"Couldn't get homedir for %s",username);
        tor_free(username);
        return NULL;
      }
      tor_free(username);
      rest = slash ? (slash+1) : NULL;
#else
      log_fn(LOG_WARN, "Couldn't expend homedir on system without pwd.h");
      return tor_strdup(filename);
#endif
    }
    tor_assert(home);
    /* Remove trailing slash. */
    if (strlen(home)>1 && !strcmpend(home,"/")) {
      home[strlen(home)-1] = '\0';
    }
    /* Plus one for /, plus one for NUL.
     * Round up to 16 in case we can't do math. */
    len = strlen(home)+strlen(filename)+16;
    len = strlen(home)+strlen(rest)+16;
    result = tor_malloc(len);
    tor_snprintf(result,len,"%s%s%s",home,
                 (!strcmpend(home, "/")) ? "" : "/",
                 filename+2);
    tor_snprintf(result,len,"%s/%s",home,rest?rest:"");
    tor_free(home);
    return result;
  } else {
    return tor_strdup(filename);