Browse Source

Resolve FIXME items: make expand_filename handle ~ and ~username

svn:r2789
Nick Mathewson 20 years ago
parent
commit
8de9cfe184
4 changed files with 61 additions and 13 deletions
  1. 1 1
      configure.in
  2. 17 0
      src/common/compat.c
  3. 3 0
      src/common/compat.h
  4. 40 12
      src/common/util.c

+ 1 - 1
configure.in

@@ -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
src/common/compat.c

@@ -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
src/common/compat.h

@@ -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
src/common/util.c

@@ -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;
-    if (!home) {
-      log_fn(LOG_WARN, "Couldn't find $HOME environment variable while expanding %s", filename);
-      return NULL;
+    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;
+      }
+      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';
     }
-    /* minus two characters for ~/, plus one for /, plus one for NUL.
+    /* 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);