fa855555b2af3a9fc286984bf679384e63af09fa
[jra/samba/.git] / source4 / ntvfs / posix / pvfs_acl_nfs4.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - NT ACLs mapped to NFS4 ACLs, as per
5    http://www.suse.de/~agruen/nfs4acl/
6
7    Copyright (C) Andrew Tridgell 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25 #include "lib/util/unix_privs.h"
26 #include "librpc/gen_ndr/ndr_nfs4acl.h"
27 #include "libcli/security/security.h"
28
29 #define ACE4_IDENTIFIER_GROUP 0x40
30
31 /*
32   load the current ACL from system.nfs4acl
33 */
34 static NTSTATUS pvfs_acl_load_nfs4(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
35                                    TALLOC_CTX *mem_ctx,
36                                    struct security_descriptor **psd)
37 {
38         NTSTATUS status;
39         struct nfs4acl *acl;
40         struct security_descriptor *sd;
41         int i, num_ids;
42         struct id_mapping *ids;
43         struct composite_context *ctx;
44
45         acl = talloc_zero(mem_ctx, struct nfs4acl);
46         NT_STATUS_HAVE_NO_MEMORY(acl);
47
48         status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, fd, 
49                                      NFS4ACL_XATTR_NAME,
50                                      acl, ndr_pull_nfs4acl);
51         if (!NT_STATUS_IS_OK(status)) {
52                 talloc_free(acl);
53                 return status;
54         }
55
56         *psd = security_descriptor_initialise(mem_ctx);
57         NT_STATUS_HAVE_NO_MEMORY(*psd);
58
59         sd = *psd;
60
61         sd->type |= acl->a_flags;
62
63         /* the number of ids to map is the acl count plus uid and gid */
64         num_ids = acl->a_count +2;
65         ids = talloc_array(sd, struct id_mapping, num_ids);
66         NT_STATUS_HAVE_NO_MEMORY(ids);
67
68         ids[0].unixid = talloc(ids, struct unixid);
69         NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid);
70         ids[0].unixid->id = name->st.st_uid;
71         ids[0].unixid->type = ID_TYPE_UID;
72         ids[0].sid = NULL;
73         ids[0].status = NT_STATUS_NONE_MAPPED;
74
75         ids[1].unixid = talloc(ids, struct unixid);
76         NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid);
77         ids[1].unixid->id = name->st.st_gid;
78         ids[1].unixid->type = ID_TYPE_GID;
79         ids[1].sid = NULL;
80         ids[1].status = NT_STATUS_NONE_MAPPED;
81
82         for (i=0;i<acl->a_count;i++) {
83                 struct nfs4ace *a = &acl->ace[i];
84                 ids[i+2].unixid = talloc(ids, struct unixid);
85                 NT_STATUS_HAVE_NO_MEMORY(ids[i+2].unixid);
86                 ids[i+2].unixid->id = a->e_id;
87                 if (a->e_flags & ACE4_IDENTIFIER_GROUP) {
88                         ids[i+2].unixid->type = ID_TYPE_GID;
89                 } else {
90                         ids[i+2].unixid->type = ID_TYPE_UID;
91                 }
92                 ids[i+2].sid = NULL;
93                 ids[i+2].status = NT_STATUS_NONE_MAPPED;
94         }
95
96         /* Allocate memory for the sids from the security descriptor to be on
97          * the safe side. */
98         ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, sd, num_ids, ids);
99         NT_STATUS_HAVE_NO_MEMORY(ctx);
100         status = wbc_xids_to_sids_recv(ctx, &ids);
101         NT_STATUS_NOT_OK_RETURN(status);
102
103         sd->owner_sid = talloc_steal(sd, ids[0].sid);
104         sd->group_sid = talloc_steal(sd, ids[1].sid);
105
106         for (i=0;i<acl->a_count;i++) {
107                 struct nfs4ace *a = &acl->ace[i];
108                 struct security_ace ace;
109                 ace.type = a->e_type;
110                 ace.flags = a->e_flags;
111                 ace.access_mask = a->e_mask;
112                 ace.trustee = *ids[i+2].sid;
113                 security_descriptor_dacl_add(sd, &ace);
114         }
115
116         return NT_STATUS_OK;
117 }
118
119 /*
120   save the acl for a file into system.nfs4acl
121 */
122 static NTSTATUS pvfs_acl_save_nfs4(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
123                                    struct security_descriptor *sd)
124 {
125         NTSTATUS status;
126         void *privs;
127         struct nfs4acl acl;
128         int i;
129         TALLOC_CTX *tmp_ctx;
130         struct id_mapping *ids;
131         struct composite_context *ctx;
132
133         tmp_ctx = talloc_new(pvfs);
134         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
135
136         acl.a_version = 0;
137         acl.a_flags   = sd->type;
138         acl.a_count   = sd->dacl?sd->dacl->num_aces:0;
139         acl.a_owner_mask = 0;
140         acl.a_group_mask = 0;
141         acl.a_other_mask = 0;
142
143         acl.ace = talloc_array(tmp_ctx, struct nfs4ace, acl.a_count);
144         if (!acl.ace) {
145                 talloc_free(tmp_ctx);
146                 return NT_STATUS_NO_MEMORY;
147         }
148
149         ids = talloc_array(tmp_ctx, struct id_mapping, acl.a_count);
150         if (ids == NULL) {
151                 talloc_free(tmp_ctx);
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         for (i=0;i<acl.a_count;i++) {
156                 struct security_ace *ace = &sd->dacl->aces[i];
157                 ids[i].unixid = NULL;
158                 ids[i].sid = dom_sid_dup(ids, &ace->trustee);
159                 if (ids[i].sid == NULL) {
160                         talloc_free(tmp_ctx);
161                         return NT_STATUS_NO_MEMORY;
162                 }
163                 ids[i].status = NT_STATUS_NONE_MAPPED;
164         }
165
166         ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx,ids, acl.a_count, ids);
167         if (ctx == NULL) {
168                 talloc_free(tmp_ctx);
169                 return NT_STATUS_NO_MEMORY;
170         }
171         status = wbc_sids_to_xids_recv(ctx, &ids);
172         if (!NT_STATUS_IS_OK(status)) {
173                 talloc_free(tmp_ctx);
174                 return status;
175         }
176
177         for (i=0;i<acl.a_count;i++) {
178                 struct nfs4ace *a = &acl.ace[i];
179                 struct security_ace *ace = &sd->dacl->aces[i];
180                 a->e_type  = ace->type;
181                 a->e_flags = ace->flags;
182                 a->e_mask  = ace->access_mask;
183                 if (ids[i].unixid->type != ID_TYPE_UID) {
184                         a->e_flags |= ACE4_IDENTIFIER_GROUP;
185                 }
186                 a->e_id = ids[i].unixid->id;
187                 a->e_who   = "";
188         }
189
190         privs = root_privileges();
191         status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
192                                      NFS4ACL_XATTR_NAME, 
193                                      &acl, ndr_push_nfs4acl);
194         talloc_free(privs);
195
196         talloc_free(tmp_ctx);
197         return status;
198 }
199
200
201 /*
202   initialise pvfs acl NFS4 backend
203 */
204 NTSTATUS pvfs_acl_nfs4_init(void)
205 {
206         struct pvfs_acl_ops ops = {
207                 .name = "nfs4acl",
208                 .acl_load = pvfs_acl_load_nfs4,
209                 .acl_save = pvfs_acl_save_nfs4
210         };
211         return pvfs_acl_register(&ops);
212 }