diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c index cc3b4d69e20..4fbb973a2f3 100644 --- a/dlls/ntdll/om.c +++ b/dlls/ntdll/om.c @@ -636,35 +636,31 @@ NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK * Failure: An NTSTATUS error code. */ NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PUNICODE_STRING TargetName) + POBJECT_ATTRIBUTES attr, PUNICODE_STRING TargetName) { NTSTATUS ret; + data_size_t len; + struct object_attributes *objattr; if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION; if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER; TRACE("(%p,0x%08x,%s -> %s)\n", SymbolicLinkHandle, DesiredAccess, - debugstr_ObjectAttributes(ObjectAttributes), debugstr_us(TargetName)); + debugstr_ObjectAttributes(attr), debugstr_us(TargetName)); + + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; SERVER_START_REQ(create_symlink) { req->access = DesiredAccess; - req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0; - req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 ); - if (ObjectAttributes && ObjectAttributes->ObjectName) - { - req->name_len = ObjectAttributes->ObjectName->Length; - wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer, - ObjectAttributes->ObjectName->Length); - } - else - req->name_len = 0; + wine_server_add_data( req, objattr, len ); wine_server_add_data(req, TargetName->Buffer, TargetName->Length); ret = wine_server_call( req ); *SymbolicLinkHandle = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; + + RtlFreeHeap( GetProcessHeap(), 0, objattr ); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 85666174078..4614c983257 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4760,12 +4760,8 @@ struct create_symlink_request { struct request_header __header; unsigned int access; - unsigned int attributes; - obj_handle_t rootdir; - data_size_t name_len; - /* VARARG(name,unicode_str,name_len); */ + /* VARARG(objattr,object_attributes); */ /* VARARG(target_name,unicode_str); */ - char __pad_28[4]; }; struct create_symlink_reply { diff --git a/server/directory.c b/server/directory.c index d05b60fe7bb..05dddeceaec 100644 --- a/server/directory.c +++ b/server/directory.c @@ -463,15 +463,15 @@ void init_directories(void) create_unix_device( dir_device, &null_str, "/dev/null" ); /* symlinks */ - link_dosdev = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str ); - link_global1 = create_symlink( dir_global, &link_global_str, 0, &dir_global_str ); - link_global2 = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str ); - link_local = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str ); - link_nul = create_symlink( dir_global, &link_nul_str, 0, &dir_null_str ); - link_pipe = create_symlink( dir_global, &link_pipe_str, 0, &dir_named_pipe_str ); - link_mailslot = create_symlink( dir_global, &link_mailslot_str, 0, &dir_mailslot_str ); - link_0 = create_symlink( dir_sessions, &link_0_str, 0, &dir_basenamed_str ); - link_session = create_symlink( dir_basenamed, &link_session_str, 0, &link_sessions_str ); + link_dosdev = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str, NULL ); + link_global1 = create_symlink( dir_global, &link_global_str, 0, &dir_global_str, NULL ); + link_global2 = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str, NULL ); + link_local = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str, NULL ); + link_nul = create_symlink( dir_global, &link_nul_str, 0, &dir_null_str, NULL ); + link_pipe = create_symlink( dir_global, &link_pipe_str, 0, &dir_named_pipe_str, NULL ); + link_mailslot = create_symlink( dir_global, &link_mailslot_str, 0, &dir_mailslot_str, NULL ); + link_0 = create_symlink( dir_sessions, &link_0_str, 0, &dir_basenamed_str, NULL ); + link_session = create_symlink( dir_basenamed, &link_session_str, 0, &link_sessions_str, NULL ); make_object_static( (struct object *)link_dosdev ); make_object_static( (struct object *)link_global1 ); make_object_static( (struct object *)link_global2 ); diff --git a/server/object.h b/server/object.h index b59811f44b0..8e010a3fb18 100644 --- a/server/object.h +++ b/server/object.h @@ -222,7 +222,8 @@ extern void init_directories(void); /* symbolic link functions */ extern struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, - unsigned int attr, const struct unicode_str *target ); + unsigned int attr, const struct unicode_str *target, + const struct security_descriptor *sd ); /* global variables */ diff --git a/server/protocol.def b/server/protocol.def index 28c70223151..cbf5ea74a2f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3331,10 +3331,7 @@ struct handle_info /* Create a symbolic link object */ @REQ(create_symlink) unsigned int access; /* access flags */ - unsigned int attributes; /* object attributes */ - obj_handle_t rootdir; /* root directory */ - data_size_t name_len; /* length of the symlink name in bytes */ - VARARG(name,unicode_str,name_len); /* symlink name */ + VARARG(objattr,object_attributes); /* object attributes */ VARARG(target_name,unicode_str); /* target name */ @REPLY obj_handle_t handle; /* handle to the symlink */ diff --git a/server/request.h b/server/request.h index 2acf9cdf89a..e1d2487007e 100644 --- a/server/request.h +++ b/server/request.h @@ -2110,10 +2110,7 @@ C_ASSERT( sizeof(struct get_directory_entry_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct get_directory_entry_reply, name_len) == 8 ); C_ASSERT( sizeof(struct get_directory_entry_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_symlink_request, access) == 12 ); -C_ASSERT( FIELD_OFFSET(struct create_symlink_request, attributes) == 16 ); -C_ASSERT( FIELD_OFFSET(struct create_symlink_request, rootdir) == 20 ); -C_ASSERT( FIELD_OFFSET(struct create_symlink_request, name_len) == 24 ); -C_ASSERT( sizeof(struct create_symlink_request) == 32 ); +C_ASSERT( sizeof(struct create_symlink_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_symlink_reply, handle) == 8 ); C_ASSERT( sizeof(struct create_symlink_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct open_symlink_request, access) == 12 ); diff --git a/server/symlink.c b/server/symlink.c index 2330fde1cea..28d51abbed4 100644 --- a/server/symlink.c +++ b/server/symlink.c @@ -132,7 +132,8 @@ static void symlink_destroy( struct object *obj ) } struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, - unsigned int attr, const struct unicode_str *target ) + unsigned int attr, const struct unicode_str *target, + const struct security_descriptor *sd ) { struct symlink *symlink; @@ -145,7 +146,13 @@ struct symlink *create_symlink( struct directory *root, const struct unicode_str (get_error() != STATUS_OBJECT_NAME_EXISTS)) { if ((symlink->target = memdup( target->str, target->len ))) + { symlink->len = target->len; + if (sd) + default_set_sd( &symlink->obj, sd, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION ); + } else { release_object( symlink ); @@ -162,23 +169,20 @@ DECL_HANDLER(create_symlink) struct symlink *symlink; struct unicode_str name, target; struct directory *root = NULL; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name ); - if (req->name_len > get_req_data_size()) + if (!objattr) return; + + target.str = (const WCHAR *)get_req_data() + sizeof(*objattr) / sizeof(WCHAR) + + objattr->sd_len / sizeof(WCHAR) + name.len / sizeof(WCHAR); + target.len = get_req_data_size() - ((const char *)target.str - (const char *)get_req_data()); + + if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return; + + if ((symlink = create_symlink( root, &name, objattr->attributes, &target, sd ))) { - set_error( STATUS_INVALID_PARAMETER ); - return; - } - name.str = get_req_data(); - target.str = name.str + req->name_len / sizeof(WCHAR); - name.len = (target.str - name.str) * sizeof(WCHAR); - target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR); - - if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) - return; - - if ((symlink = create_symlink( root, &name, req->attributes, &target ))) - { - reply->handle = alloc_handle( current->process, symlink, req->access, req->attributes ); + reply->handle = alloc_handle( current->process, symlink, req->access, objattr->attributes ); release_object( symlink ); }