server: Pass the security descriptor into create_file, if one is specified, and set the initial mode for the file appropriately.
diff --git a/server/file.c b/server/file.c
index b5f6a87..7f34c02 100644
--- a/server/file.c
+++ b/server/file.c
@@ -75,6 +75,7 @@
 static int file_get_poll_events( struct fd *fd );
 static void file_flush( struct fd *fd, struct event **event );
 static enum server_fd_type file_get_fd_type( struct fd *fd );
+static mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
 
 static const struct object_ops file_ops =
 {
@@ -154,7 +155,7 @@
 
 static struct object *create_file( const char *nameptr, data_size_t len, unsigned int access,
                                    unsigned int sharing, int create, unsigned int options,
-                                   unsigned int attrs )
+                                   unsigned int attrs, const struct security_descriptor *sd )
 {
     struct object *obj = NULL;
     struct fd *fd;
@@ -177,11 +178,26 @@
     default:                set_error( STATUS_INVALID_PARAMETER ); goto done;
     }
 
-    mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
+    if (sd)
+    {
+        const SID *owner = sd_get_owner( sd );
+        if (!owner)
+            owner = token_get_user( current->process->token );
+        mode = sd_to_mode( sd, owner );
+    }
+    else
+        mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
 
     if (len >= 4 &&
         (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" )))
-        mode |= 0111;
+    {
+        if (mode & S_IRUSR)
+            mode |= S_IXUSR;
+        if (mode & S_IRGRP)
+            mode |= S_IXGRP;
+        if (mode & S_IROTH)
+            mode |= S_IXOTH;
+    }
 
     access = generic_file_map_access( access );
 
@@ -395,59 +411,26 @@
     return sd;
 }
 
-static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
-                        unsigned int set_info )
+static mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
 {
-    struct file *file = (struct file *)obj;
-    mode_t new_mode;
+    mode_t new_mode = 0;
     mode_t denied_mode = 0;
-    const SID *owner;
-    int unix_fd;
-
-    assert( obj->ops == &file_ops );
-
-    unix_fd = get_file_unix_fd( file );
-
-    if (unix_fd == -1) return 1;
-
-    if (set_info & OWNER_SECURITY_INFORMATION)
+    int present;
+    const ACL *dacl = sd_get_dacl( sd, &present );
+    if (present && dacl)
     {
-        owner = sd_get_owner( sd );
-        if (!owner)
+        const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1);
+        ULONG i;
+        for (i = 0; i < dacl->AceCount; i++, ace_next( ace ))
         {
-            set_error( STATUS_INVALID_SECURITY_DESCR );
-            return 0;
-        }
-        if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) ))
-        {
-            /* FIXME: get Unix uid and call fchown */
-        }
-    }
-    else if (obj->sd)
-        owner = sd_get_owner( obj->sd );
-    else
-        owner = token_get_user( current->process->token );
+            const ACCESS_ALLOWED_ACE *aa_ace;
+            const ACCESS_DENIED_ACE *ad_ace;
+            const SID *sid;
 
-    /* group and sacl not supported */
+            if (ace->AceFlags & INHERIT_ONLY_ACE) continue;
 
-    /* keep the bits that we don't map to access rights in the ACL */
-    new_mode = file->mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXG);
-
-    if (set_info & DACL_SECURITY_INFORMATION)
-    {
-        int present;
-        const ACL *dacl = sd_get_dacl( sd, &present );
-        if (present && dacl)
-        {
-            const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1);
-            ULONG i;
-            for (i = 0; i < dacl->AceCount; i++)
+            switch (ace->AceType)
             {
-                const ACCESS_ALLOWED_ACE *aa_ace;
-                const ACCESS_DENIED_ACE *ad_ace;
-                const SID *sid;
-                switch (ace->AceType)
-                {
                 case ACCESS_DENIED_ACE_TYPE:
                     ad_ace = (const ACCESS_DENIED_ACE *)ace;
                     sid = (const SID *)&ad_ace->SidStart;
@@ -496,23 +479,65 @@
                             new_mode |= S_IXUSR;
                     }
                     break;
-                }
-                ace = ace_next( ace );
             }
         }
-        else
-            /* no ACL means full access rights to anyone */
-            new_mode |= S_IRWXU | S_IRWXO;
+    }
+    else
+        /* no ACL means full access rights to anyone */
+        new_mode = S_IRWXU | S_IRWXO;
 
-        if (file->mode != (new_mode & ~denied_mode))
+    return new_mode & ~denied_mode;
+}
+
+static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
+                        unsigned int set_info )
+{
+    struct file *file = (struct file *)obj;
+    const SID *owner;
+    mode_t mode;
+    int unix_fd;
+
+    assert( obj->ops == &file_ops );
+
+    unix_fd = get_file_unix_fd( file );
+
+    if (unix_fd == -1) return 1;
+
+    if (set_info & OWNER_SECURITY_INFORMATION)
+    {
+        owner = sd_get_owner( sd );
+        if (!owner)
         {
-            if (fchmod( unix_fd, new_mode & ~denied_mode ) == -1)
+            set_error( STATUS_INVALID_SECURITY_DESCR );
+            return 0;
+        }
+        if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) ))
+        {
+            /* FIXME: get Unix uid and call fchown */
+        }
+    }
+    else if (obj->sd)
+        owner = sd_get_owner( obj->sd );
+    else
+        owner = token_get_user( current->process->token );
+
+    /* group and sacl not supported */
+
+    if (set_info & DACL_SECURITY_INFORMATION)
+    {
+        /* keep the bits that we don't map to access rights in the ACL */
+        mode = file->mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXG);
+        mode |= sd_to_mode( sd, owner );
+
+        if (file->mode != mode)
+        {
+            if (fchmod( unix_fd, mode ) == -1)
             {
                 file_set_error();
                 return 0;
             }
 
-            file->mode = new_mode & ~denied_mode;
+            file->mode = mode;
         }
     }
     return 1;
@@ -625,10 +650,31 @@
 DECL_HANDLER(create_file)
 {
     struct object *file;
+    const struct object_attributes *objattr = get_req_data();
+    const struct security_descriptor *sd;
+    const char *name;
+    data_size_t name_len;
 
     reply->handle = 0;
-    if ((file = create_file( get_req_data(), get_req_data_size(), req->access,
-                             req->sharing, req->create, req->options, req->attrs )))
+
+    if (!objattr_is_valid( objattr, get_req_data_size() ))
+        return;
+    /* name is transferred in the unix codepage outside of the objattr structure */
+    if (objattr->name_len)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+
+    sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL;
+
+    name = (const char *)get_req_data() + sizeof(*objattr) + objattr->sd_len;
+    name_len = get_req_data_size() - sizeof(*objattr) - objattr->sd_len;
+
+    reply->handle = 0;
+    if ((file = create_file( name, name_len, req->access,
+                             req->sharing, req->create, req->options,
+                             req->attrs, sd )))
     {
         reply->handle = alloc_handle( current->process, file, req->access, req->attributes );
         release_object( file );
diff --git a/server/protocol.def b/server/protocol.def
index 1ecc886..5d8acde 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -848,6 +848,7 @@
     int          create;        /* file create action */
     unsigned int options;       /* file options */
     unsigned int attrs;         /* file attributes for creation */
+    VARARG(objattr,object_attributes); /* object attributes */
     VARARG(filename,string);    /* file name */
 @REPLY
     obj_handle_t handle;        /* handle to the file */