From 161160f05ae2340ab5bb35307ca02056cbca68e9 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 17 Apr 2008 12:41:34 +0200 Subject: [PATCH] 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 50848924601..d2c0b23dcf8 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, ¤t_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 9a2c7b1eda4..8726e1c6671 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 283ad97aea7..496c5ff5707 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 );