Alexandre Julliard : server: Keep a file descriptor open to the config directory to make sure we don' t write the registry in the wrong place.

Alexandre Julliard julliard at winehq.org
Thu Apr 17 07:38:44 CDT 2008


Module: wine
Branch: master
Commit: 161160f05ae2340ab5bb35307ca02056cbca68e9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=161160f05ae2340ab5bb35307ca02056cbca68e9

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Apr 17 12:41:34 2008 +0200

server: Keep a file descriptor open to the config directory to make sure we don't write the registry in the wrong place.

---

 server/registry.c |   57 +++++++++++++++++++---------------------------------
 server/request.c  |   11 ++++++++-
 server/request.h  |    1 +
 3 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/server/registry.c b/server/registry.c
index 5084892..d2c0b23 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -112,7 +112,7 @@ static void set_periodic_save_timer(void);
 struct save_branch_info
 {
     struct key  *key;
-    char        *path;
+    const char  *path;
 };
 
 #define MAX_SAVE_BRANCH_INFO 3
@@ -1396,11 +1396,9 @@ static void load_init_registry_from_file( const char *filename, struct key *key
 
     assert( save_branch_count < MAX_SAVE_BRANCH_INFO );
 
-    if ((save_branch_info[save_branch_count].path = strdup( filename )))
-    {
-        save_branch_info[save_branch_count++].key = (struct key *)grab_object( key );
-        make_object_static( &key->obj );
-    }
+    save_branch_info[save_branch_count].path = filename;
+    save_branch_info[save_branch_count++].key = (struct key *)grab_object( key );
+    make_object_static( &key->obj );
 }
 
 static WCHAR *format_user_registry_path( const SID *sid, struct unicode_str *path )
@@ -1438,27 +1436,24 @@ void init_registry(void)
     WCHAR *current_user_path;
     struct unicode_str current_user_str;
 
-    const char *config = wine_get_config_dir();
-    char *p, *filename;
     struct key *key;
     int dummy;
 
+    /* switch to the config dir */
+
+    if (fchdir( config_dir_fd ) == -1) fatal_perror( "chdir to config dir" );
+
     /* create the root key */
     root_key = alloc_key( &root_name, time(NULL) );
     assert( root_key );
     make_object_static( &root_key->obj );
 
-    if (!(filename = malloc( strlen(config) + 16 ))) fatal_error( "out of memory\n" );
-    strcpy( filename, config );
-    p = filename + strlen(filename);
-
     /* load system.reg into Registry\Machine */
 
     if (!(key = create_key( root_key, &HKLM_name, NULL, 0, time(NULL), &dummy )))
         fatal_error( "could not create Machine registry key\n" );
 
-    strcpy( p, "/system.reg" );
-    load_init_registry_from_file( filename, key );
+    load_init_registry_from_file( "system.reg", key );
     release_object( key );
 
     /* load userdef.reg into Registry\User\.Default */
@@ -1466,8 +1461,7 @@ void init_registry(void)
     if (!(key = create_key( root_key, &HKU_name, NULL, 0, time(NULL), &dummy )))
         fatal_error( "could not create User\\.Default registry key\n" );
 
-    strcpy( p, "/userdef.reg" );
-    load_init_registry_from_file( filename, key );
+    load_init_registry_from_file( "userdef.reg", key );
     release_object( key );
 
     /* load user.reg into HKEY_CURRENT_USER */
@@ -1478,14 +1472,14 @@ void init_registry(void)
         !(key = create_key( root_key, &current_user_str, NULL, 0, time(NULL), &dummy )))
         fatal_error( "could not create HKEY_CURRENT_USER registry key\n" );
     free( current_user_path );
-    strcpy( p, "/user.reg" );
-    load_init_registry_from_file( filename, key );
+    load_init_registry_from_file( "user.reg", key );
     release_object( key );
 
-    free( filename );
-
     /* start the periodic save timer */
     set_periodic_save_timer();
+
+    /* go back to the server dir */
+    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
 }
 
 /* save a registry branch to a file */
@@ -1532,8 +1526,8 @@ static void save_registry( struct key *key, obj_handle_t handle )
 static int save_branch( struct key *key, const char *path )
 {
     struct stat st;
-    char *p, *real, *tmp = NULL;
-    int fd, count = 0, ret = 0, by_symlink;
+    char *p, *tmp = NULL;
+    int fd, count = 0, ret = 0;
     FILE *f;
 
     if (!(key->flags & KEY_DIRTY))
@@ -1542,25 +1536,13 @@ static int save_branch( struct key *key, const char *path )
         return 1;
     }
 
-    /* get the real path */
-
-    by_symlink = (!lstat(path, &st) && S_ISLNK (st.st_mode));
-    if (!(real = malloc( PATH_MAX ))) return 0;
-    if (!realpath( path, real ))
-    {
-        free( real );
-        real = NULL;
-    }
-    else path = real;
-
     /* test the file type */
 
     if ((fd = open( path, O_WRONLY )) != -1)
     {
         /* if file is not a regular file or has multiple links or is accessed
          * via symbolic links, write directly into it; otherwise use a temp file */
-        if (by_symlink ||
-            (!fstat( fd, &st ) && (!S_ISREG(st.st_mode) || st.st_nlink > 1)))
+        if (!lstat( path, &st ) && (!S_ISREG(st.st_mode) || st.st_nlink > 1))
         {
             ftruncate( fd, 0 );
             goto save;
@@ -1610,7 +1592,6 @@ static int save_branch( struct key *key, const char *path )
 
 done:
     free( tmp );
-    free( real );
     if (ret) make_clean( key );
     return ret;
 }
@@ -1620,9 +1601,11 @@ static void periodic_save( void *arg )
 {
     int i;
 
+    if (fchdir( config_dir_fd ) == -1) return;
     save_timeout_user = NULL;
     for (i = 0; i < save_branch_count; i++)
         save_branch( save_branch_info[i].key, save_branch_info[i].path );
+    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
     set_periodic_save_timer();
 }
 
@@ -1638,6 +1621,7 @@ void flush_registry(void)
 {
     int i;
 
+    if (fchdir( config_dir_fd ) == -1) return;
     for (i = 0; i < save_branch_count; i++)
     {
         if (!save_branch( save_branch_info[i].key, save_branch_info[i].path ))
@@ -1647,6 +1631,7 @@ void flush_registry(void)
             perror( " " );
         }
     }
+    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
 }
 
 
diff --git a/server/request.c b/server/request.c
index 9a2c7b1..8726e1c 100644
--- a/server/request.c
+++ b/server/request.c
@@ -120,6 +120,8 @@ static const struct fd_ops master_socket_fd_ops =
 struct thread *current = NULL;  /* thread handling the current request */
 unsigned int global_error = 0;  /* global error code for when no thread is current */
 timeout_t server_start_time = 0;  /* server startup time */
+int server_dir_fd = -1;    /* file descriptor for the server dir */
+int config_dir_fd = -1;    /* file descriptor for the config dir */
 
 static struct master_socket *master_socket;  /* the master socket object */
 static struct timeout_user *master_timeout;
@@ -553,7 +555,8 @@ static void create_server_dir( const char *dir )
     create_dir( server_dir, &st );
 
     if (chdir( server_dir ) == -1) fatal_perror( "chdir %s", server_dir );
-    if (stat( ".", &st2 ) == -1) fatal_perror( "stat %s", server_dir );
+    if ((server_dir_fd = open( ".", O_RDONLY )) == -1) fatal_perror( "open %s", server_dir );
+    if (fstat( server_dir_fd, &st2 ) == -1) fatal_perror( "stat %s", server_dir );
     if (st.st_dev != st2.st_dev || st.st_ino != st2.st_ino)
         fatal_error( "chdir did not end up in %s\n", server_dir );
 
@@ -733,6 +736,7 @@ static void acquire_lock(void)
 void open_master_socket(void)
 {
     const char *server_dir = wine_get_server_dir();
+    const char *config_dir = wine_get_config_dir();
     int fd, pid, status, sync_pipe[2];
     char dummy;
 
@@ -740,7 +744,10 @@ void open_master_socket(void)
     assert( sizeof(union generic_request) == sizeof(struct request_max_size) );
     assert( sizeof(union generic_reply) == sizeof(struct request_max_size) );
 
-    if (!server_dir) fatal_error( "directory %s cannot be accessed\n", wine_get_config_dir() );
+    if (!server_dir) fatal_error( "directory %s cannot be accessed\n", config_dir );
+    if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s", config_dir );
+    if ((config_dir_fd = open( ".", O_RDONLY )) == -1) fatal_perror( "open %s", config_dir );
+
     create_server_dir( server_dir );
 
     if (!foreground)
diff --git a/server/request.h b/server/request.h
index 283ad97..496c5ff 100644
--- a/server/request.h
+++ b/server/request.h
@@ -61,6 +61,7 @@ extern void close_master_socket( timeout_t timeout );
 extern void shutdown_master_socket(void);
 extern int wait_for_lock(void);
 extern int kill_lock_owner( int sig );
+extern int server_dir_fd, config_dir_fd;
 
 extern void trace_request(void);
 extern void trace_reply( enum request req, const union generic_reply *reply );




More information about the wine-cvs mailing list