r3833: NTACL is a better xattr name than DosAcl (tpot suggested this)
[kai/samba.git] / source / ntvfs / posix / pvfs_acl.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - ACL support
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "system/filesys.h"
26 #include "vfs_posix.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
28
29
30 /*
31   setup a default ACL for a file
32 */
33 static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
34                                  struct smbsrv_request *req,
35                                  struct pvfs_filename *name, int fd, 
36                                  struct xattr_NTACL *acl)
37 {
38         struct security_descriptor *sd;
39         struct nt_user_token *token = req->session->session_info->nt_user_token;
40         int i;
41
42         sd = security_descriptor_initialise(req);
43         if (sd == NULL) {
44                 return NT_STATUS_NO_MEMORY;
45         }
46
47         /* nasty hack to get a reasonable sec desc - should be based on posix uid/gid
48            and perms */
49         if (token->num_sids > 0) {
50                 sd->owner_sid = token->user_sids[0];
51         }
52         if (token->num_sids > 1) {
53                 sd->group_sid = token->user_sids[1];
54         }
55
56         for (i=0;i<token->num_sids;i++) {
57                 struct security_ace ace;
58                 NTSTATUS status;
59
60                 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
61                 ace.flags = 0;
62                 ace.access_mask = SEC_RIGHTS_FULL_CTRL | STD_RIGHT_ALL_ACCESS;
63                 ace.trustee = *token->user_sids[i];
64
65                 status = security_descriptor_dacl_add(sd, &ace);
66                 if (!NT_STATUS_IS_OK(status)) {
67                         return status;
68                 }
69         }
70         
71         acl->version = 1;
72         acl->info.sd = sd;
73
74         return NT_STATUS_OK;
75 }
76                                  
77
78 /*
79   omit any security_descriptor elements not specified in the given
80   secinfo flags
81 */
82 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
83 {
84         if (!(secinfo_flags & OWNER_SECURITY_INFORMATION)) {
85                 sd->owner_sid = NULL;
86         }
87         if (!(secinfo_flags & GROUP_SECURITY_INFORMATION)) {
88                 sd->group_sid = NULL;
89         }
90         if (!(secinfo_flags & DACL_SECURITY_INFORMATION)) {
91                 sd->dacl = NULL;
92         }
93         if (!(secinfo_flags & SACL_SECURITY_INFORMATION)) {
94                 sd->sacl = NULL;
95         }
96 }
97
98 /*
99   answer a setfileinfo for an ACL
100 */
101 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, 
102                       struct smbsrv_request *req,
103                       struct pvfs_filename *name, int fd, 
104                       union smb_setfileinfo *info)
105 {
106         struct xattr_NTACL *acl;
107         uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
108         struct security_descriptor *new_sd, *sd;
109         NTSTATUS status;
110
111         acl = talloc_p(req, struct xattr_NTACL);
112         if (acl == NULL) {
113                 return NT_STATUS_NO_MEMORY;
114         }
115
116         status = pvfs_acl_load(pvfs, name, fd, acl);
117         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
118                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
119         }
120         if (!NT_STATUS_IS_OK(status)) {
121                 return status;
122         }
123
124         switch (acl->version) {
125         case 1:
126                 sd = acl->info.sd;
127                 break;
128         default:
129                 return NT_STATUS_INVALID_LEVEL;
130         }
131
132         new_sd = info->set_secdesc.in.sd;
133
134         /* only set the elements that have been specified */
135         if (secinfo_flags & OWNER_SECURITY_INFORMATION) {
136                 sd->owner_sid = new_sd->owner_sid;
137         }
138         if (secinfo_flags & GROUP_SECURITY_INFORMATION) {
139                 sd->group_sid = new_sd->group_sid;
140         }
141         if (secinfo_flags & DACL_SECURITY_INFORMATION) {
142                 sd->dacl = new_sd->dacl;
143         }
144         if (secinfo_flags & SACL_SECURITY_INFORMATION) {
145                 sd->sacl = new_sd->sacl;
146         }
147
148         status = pvfs_acl_save(pvfs, name, fd, acl);
149
150         return status;
151 }
152
153
154 /*
155   answer a fileinfo query for the ACL
156 */
157 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs, 
158                         struct smbsrv_request *req,
159                         struct pvfs_filename *name, int fd, 
160                         union smb_fileinfo *info)
161 {
162         struct xattr_NTACL *acl;
163         NTSTATUS status;
164         struct security_descriptor *sd;
165
166         acl = talloc_p(req, struct xattr_NTACL);
167         if (acl == NULL) {
168                 return NT_STATUS_NO_MEMORY;
169         }
170
171         status = pvfs_acl_load(pvfs, name, fd, acl);
172         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
173                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
174         }
175         if (!NT_STATUS_IS_OK(status)) {
176                 return status;
177         }
178
179         switch (acl->version) {
180         case 1:
181                 sd = acl->info.sd;
182                 break;
183         default:
184                 return NT_STATUS_INVALID_LEVEL;
185         }
186
187         normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
188
189         info->query_secdesc.out.sd = sd;
190
191         return NT_STATUS_OK;
192 }
193