smbd: Fix CID 1035478 Negative array index read
[samba.git] / source3 / modules / nfs4_acls.c
1 /*
2  * NFS4 ACL handling
3  *
4  * Copyright (C) Jim McDonough, 2006
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
35
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
37
38 extern const struct generic_mapping file_generic_mapping;
39
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
42 {
43         uint32  magic;
44         SMB_ACE4PROP_T  prop;
45         void    *next;
46 } SMB_ACE4_INT_T;
47
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
50 {
51         uint32  magic;
52         uint32  naces;
53         SMB_ACE4_INT_T  *first;
54         SMB_ACE4_INT_T  *last;
55 } SMB_ACL4_INT_T;
56
57 enum smbacl4_mode_enum {e_simple=0, e_special=1};
58 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
59
60 typedef struct _smbacl4_vfs_params {
61         enum smbacl4_mode_enum mode;
62         bool do_chown;
63         enum smbacl4_acedup_enum acedup;
64         bool map_full_control;
65 } smbacl4_vfs_params;
66
67 /*
68  * Gather special parameters for NFS4 ACL handling
69  */
70 static int smbacl4_get_vfs_params(
71         const char *type_name,
72         struct connection_struct *conn,
73         smbacl4_vfs_params *params
74 )
75 {
76         static const struct enum_list enum_smbacl4_modes[] = {
77                 { e_simple, "simple" },
78                 { e_special, "special" },
79                 { -1 , NULL }
80         };
81         static const struct enum_list enum_smbacl4_acedups[] = {
82                 { e_dontcare, "dontcare" },
83                 { e_reject, "reject" },
84                 { e_ignore, "ignore" },
85                 { e_merge, "merge" },
86                 { -1 , NULL }
87         };
88         int enumval;
89
90         memset(params, 0, sizeof(smbacl4_vfs_params));
91
92         enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
93                                enum_smbacl4_modes, e_simple);
94         if (enumval == -1) {
95                 DEBUG(10, ("value for %s:mode unknown\n", type_name));
96                 return -1;
97         }
98         params->mode = (enum smbacl4_mode_enum)enumval;
99
100         params->do_chown = lp_parm_bool(SNUM(conn), type_name,
101                 "chown", true);
102
103         enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
104                                enum_smbacl4_acedups, e_dontcare);
105         if (enumval == -1) {
106                 DEBUG(10, ("value for %s:acedup unknown\n", type_name));
107                 return -1;
108         }
109         params->acedup = (enum smbacl4_acedup_enum)enumval;
110
111         params->map_full_control = lp_acl_map_full_control(SNUM(conn));
112
113         DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
114                 enum_smbacl4_modes[params->mode].name,
115                 params->do_chown ? "true" : "false",
116                 enum_smbacl4_acedups[params->acedup].name,
117                 params->map_full_control ? "true" : "false"));
118
119         return 0;
120 }
121
122 /************************************************
123  Split the ACE flag mapping between nfs4 and Windows
124  into two separate functions rather than trying to do
125  it inline. Allows us to carefully control what flags
126  are mapped to what in one place.
127 ************************************************/
128
129 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
130         uint32_t nfs4_ace_flags)
131 {
132         uint32_t win_ace_flags = 0;
133
134         /* The nfs4 flags <= 0xf map perfectly. */
135         win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
136                                       SEC_ACE_FLAG_CONTAINER_INHERIT|
137                                       SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
138                                       SEC_ACE_FLAG_INHERIT_ONLY);
139
140         /* flags greater than 0xf have diverged :-(. */
141         /* See the nfs4 ace flag definitions here:
142            http://www.ietf.org/rfc/rfc3530.txt.
143            And the Windows ace flag definitions here:
144            librpc/idl/security.idl. */
145         if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
146                 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
147         }
148
149         return win_ace_flags;
150 }
151
152 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
153 {
154         uint32_t nfs4_ace_flags = 0;
155
156         /* The windows flags <= 0xf map perfectly. */
157         nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
158                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
159                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
160                                       SMB_ACE4_INHERIT_ONLY_ACE);
161
162         /* flags greater than 0xf have diverged :-(. */
163         /* See the nfs4 ace flag definitions here:
164            http://www.ietf.org/rfc/rfc3530.txt.
165            And the Windows ace flag definitions here:
166            librpc/idl/security.idl. */
167         if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
168                 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
169         }
170
171         return nfs4_ace_flags;
172 }
173
174 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
175 {
176         SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
177         if (theacl==NULL)
178         {
179                 DEBUG(2, ("acl is NULL\n"));
180                 errno = EINVAL;
181                 return NULL;
182         }
183         if (aclint->magic!=SMB_ACL4_INT_MAGIC)
184         {
185                 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
186                 errno = EINVAL;
187                 return NULL;
188         }
189         return aclint;
190 }
191
192 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
193 {
194         SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
195         if (ace==NULL)
196         {
197                 DEBUG(2, ("ace is NULL\n"));
198                 errno = EINVAL;
199                 return NULL;
200         }
201         if (aceint->magic!=SMB_ACE4_INT_MAGIC)
202         {
203                 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
204                 errno = EINVAL;
205                 return NULL;
206         }
207         return aceint;
208 }
209
210 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
211 {
212         SMB_ACL4_INT_T  *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
213                 mem_ctx, sizeof(SMB_ACL4_INT_T));
214         if (theacl==NULL)
215         {
216                 DEBUG(0, ("TALLOC_SIZE failed\n"));
217                 errno = ENOMEM;
218                 return NULL;
219         }
220         theacl->magic = SMB_ACL4_INT_MAGIC;
221         /* theacl->first, last = NULL not needed */
222         return (SMB4ACL_T *)theacl;
223 }
224
225 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
226 {
227         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
228         SMB_ACE4_INT_T *ace;
229
230         ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
231                 theacl, sizeof(SMB_ACE4_INT_T));
232         if (ace==NULL)
233         {
234                 DEBUG(0, ("TALLOC_SIZE failed\n"));
235                 errno = ENOMEM;
236                 return NULL;
237         }
238         ace->magic = SMB_ACE4_INT_MAGIC;
239         /* ace->next = NULL not needed */
240         memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
241
242         if (aclint->first==NULL)
243         {
244                 aclint->first = ace;
245                 aclint->last = ace;
246         } else {
247                 aclint->last->next = (void *)ace;
248                 aclint->last = ace;
249         }
250         aclint->naces++;
251
252         return (SMB4ACE_T *)ace;
253 }
254
255 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
256 {
257         SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
258         if (aceint==NULL)
259                 return NULL;
260
261         return &aceint->prop;
262 }
263
264 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
265 {
266         SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
267         if (aceint==NULL)
268                 return NULL;
269
270         return (SMB4ACE_T *)aceint->next;
271 }
272
273 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
274 {
275         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
276         if (aclint==NULL)
277                 return NULL;
278
279         return (SMB4ACE_T *)aclint->first;
280 }
281
282 uint32 smb_get_naces(SMB4ACL_T *theacl)
283 {
284         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
285         if (aclint==NULL)
286                 return 0;
287
288         return aclint->naces;
289 }
290
291 static int smbacl4_GetFileOwner(struct connection_struct *conn,
292                                 const char *filename,
293                                 SMB_STRUCT_STAT *psbuf)
294 {
295         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
296
297         /* Get the stat struct for the owner info. */
298         if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
299         {
300                 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
301                         strerror(errno)));
302                 return -1;
303         }
304
305         return 0;
306 }
307
308 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
309 {
310         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
311
312         if (fsp->fh->fd == -1) {
313                 return smbacl4_GetFileOwner(fsp->conn,
314                                             fsp->fsp_name->base_name, psbuf);
315         }
316         if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
317         {
318                 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
319                         strerror(errno)));
320                 return -1;
321         }
322
323         return 0;
324 }
325
326 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
327         smbacl4_vfs_params *params,
328         SMB4ACL_T *theacl, /* in */
329         struct dom_sid *psid_owner, /* in */
330         struct dom_sid *psid_group, /* in */
331         bool is_directory, /* in */
332         struct security_ace **ppnt_ace_list, /* out */
333         int *pgood_aces /* out */
334 )
335 {
336         SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
337         SMB_ACE4_INT_T *aceint;
338         struct security_ace *nt_ace_list = NULL;
339         int good_aces = 0;
340
341         DEBUG(10, ("smbacl_nfs42win entered\n"));
342
343         aclint = get_validated_aclint(theacl);
344         /* We do not check for theacl being NULL here
345            because this is already checked in smb_get_nt_acl_nfs4().
346            We reserve twice the number of input aces because one nfs4
347            ace might result in 2 nt aces.*/
348         nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
349                 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
350         if (nt_ace_list==NULL)
351         {
352                 DEBUG(10, ("talloc error with %d aces", aclint->naces));
353                 errno = ENOMEM;
354                 return false;
355         }
356
357         for (aceint=aclint->first;
358              aceint!=NULL;
359              aceint=(SMB_ACE4_INT_T *)aceint->next) {
360                 uint32_t mask;
361                 struct dom_sid sid;
362                 SMB_ACE4PROP_T  *ace = &aceint->prop;
363                 uint32_t win_ace_flags;
364
365                 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
366                            "mask: %x, who: %d\n",
367                            aceint->magic, ace->aceType, ace->flags,
368                            ace->aceFlags, ace->aceMask, ace->who.id));
369
370                 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
371
372                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
373                         switch (ace->who.special_id) {
374                         case SMB_ACE4_WHO_OWNER:
375                                 sid_copy(&sid, psid_owner);
376                                 break;
377                         case SMB_ACE4_WHO_GROUP:
378                                 sid_copy(&sid, psid_group);
379                                 break;
380                         case SMB_ACE4_WHO_EVERYONE:
381                                 sid_copy(&sid, &global_sid_World);
382                                 break;
383                         default:
384                                 DEBUG(8, ("invalid special who id %d "
385                                         "ignored\n", ace->who.special_id));
386                                 continue;
387                         }
388                 } else {
389                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
390                                 gid_to_sid(&sid, ace->who.gid);
391                         } else {
392                                 uid_to_sid(&sid, ace->who.uid);
393                         }
394                 }
395                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
396                            sid_string_dbg(&sid)));
397
398                 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
399                         ace->aceMask |= SMB_ACE4_DELETE_CHILD;
400                 }
401
402                 if (!is_directory && params->map_full_control) {
403                         /*
404                          * Do we have all access except DELETE_CHILD
405                          * (not caring about the delete bit).
406                          */
407                         uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
408                                                 SMB_ACE4_ALL_MASKS);
409                         if (test_mask == SMB_ACE4_ALL_MASKS) {
410                                 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
411                         }
412                 }
413
414                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
415                         ace->aceFlags);
416                 if (!is_directory &&
417                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
418                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
419                         /*
420                          * GPFS sets inherits dir_inhert and file_inherit flags
421                          * to files, too, which confuses windows, and seems to
422                          * be wrong anyways. ==> Map these bits away for files.
423                          */
424                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
425                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
426                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
427                 }
428                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
429                       ace->aceFlags, win_ace_flags));
430
431                 mask = ace->aceMask;
432                 /* Windows clients expect SYNC on acls to
433                    correctly allow rename. See bug #7909. */
434                 /* But not on DENY ace entries. See
435                    bug #8442. */
436                 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
437                         mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
438                 }
439
440                 /* Mapping of owner@ and group@ to creator owner and
441                    creator group. Keep old behavior in mode special. */
442                 if (params->mode != e_special &&
443                     ace->flags & SMB_ACE4_ID_SPECIAL &&
444                     (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
445                      ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
446                         DEBUG(10, ("Map special entry\n"));
447                         if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
448                                 uint32_t win_ace_flags_current;
449                                 DEBUG(10, ("Map current sid\n"));
450                                 win_ace_flags_current = win_ace_flags &
451                                         ~(SEC_ACE_FLAG_OBJECT_INHERIT |
452                                           SEC_ACE_FLAG_CONTAINER_INHERIT);
453                                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
454                                              ace->aceType, mask,
455                                              win_ace_flags_current);
456                         }
457                         if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
458                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
459                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
460                                 uint32_t win_ace_flags_creator;
461                                 DEBUG(10, ("Map creator owner\n"));
462                                 win_ace_flags_creator = win_ace_flags |
463                                         SMB_ACE4_INHERIT_ONLY_ACE;
464                                 init_sec_ace(&nt_ace_list[good_aces++],
465                                              &global_sid_Creator_Owner,
466                                              ace->aceType, mask,
467                                              win_ace_flags_creator);
468                         }
469                         if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
470                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
471                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
472                                 uint32_t win_ace_flags_creator;
473                                 DEBUG(10, ("Map creator owner group\n"));
474                                 win_ace_flags_creator = win_ace_flags |
475                                         SMB_ACE4_INHERIT_ONLY_ACE;
476                                 init_sec_ace(&nt_ace_list[good_aces++],
477                                              &global_sid_Creator_Group,
478                                              ace->aceType, mask,
479                                              win_ace_flags_creator);
480                         }
481                 } else {
482                         DEBUG(10, ("Map normal sid\n"));
483                         init_sec_ace(&nt_ace_list[good_aces++], &sid,
484                                      ace->aceType, mask,
485                                      win_ace_flags);
486                 }
487         }
488
489         nt_ace_list = (struct security_ace *)
490                 TALLOC_REALLOC(mem_ctx, nt_ace_list,
491                                        good_aces * sizeof(struct security_ace));
492         /* returns a NULL ace list when good_aces is zero. */
493         if (good_aces && nt_ace_list == NULL) {
494                 DEBUG(10, ("realloc error with %d aces", good_aces));
495                 errno = ENOMEM;
496                 return false;
497         }
498
499         *ppnt_ace_list = nt_ace_list;
500         *pgood_aces = good_aces;
501
502         return true;
503 }
504
505 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
506                                            smbacl4_vfs_params *params,
507                                            uint32 security_info,
508                                            TALLOC_CTX *mem_ctx,
509                                            struct security_descriptor **ppdesc,
510                                            SMB4ACL_T *theacl)
511 {
512         int good_aces = 0;
513         struct dom_sid sid_owner, sid_group;
514         size_t sd_size = 0;
515         struct security_ace *nt_ace_list = NULL;
516         struct security_acl *psa = NULL;
517         TALLOC_CTX *frame = talloc_stackframe();
518
519         if (theacl==NULL) {
520                 TALLOC_FREE(frame);
521                 return NT_STATUS_ACCESS_DENIED; /* special because we
522                                                  * need to think through
523                                                  * the null case.*/
524         }
525
526         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
527         gid_to_sid(&sid_group, sbuf->st_ex_gid);
528
529         if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
530                              S_ISDIR(sbuf->st_ex_mode),
531                              &nt_ace_list, &good_aces)==false) {
532                 DEBUG(8,("smbacl4_nfs42win failed\n"));
533                 TALLOC_FREE(frame);
534                 return map_nt_error_from_unix(errno);
535         }
536
537         psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
538         if (psa == NULL) {
539                 DEBUG(2,("make_sec_acl failed\n"));
540                 TALLOC_FREE(frame);
541                 return NT_STATUS_NO_MEMORY;
542         }
543
544         DEBUG(10,("after make sec_acl\n"));
545         *ppdesc = make_sec_desc(
546                 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
547                 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
548                 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
549                 NULL, psa, &sd_size);
550         if (*ppdesc==NULL) {
551                 DEBUG(2,("make_sec_desc failed\n"));
552                 TALLOC_FREE(frame);
553                 return NT_STATUS_NO_MEMORY;
554         }
555
556         DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
557                    "sd_size %d\n",
558                    (int)ndr_size_security_descriptor(*ppdesc, 0)));
559
560         TALLOC_FREE(frame);
561         return NT_STATUS_OK;
562 }
563
564 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
565                               uint32 security_info,
566                               TALLOC_CTX *mem_ctx,
567                               struct security_descriptor **ppdesc,
568                               SMB4ACL_T *theacl)
569 {
570         SMB_STRUCT_STAT sbuf;
571         smbacl4_vfs_params params;
572
573         DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
574
575         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
576                 return map_nt_error_from_unix(errno);
577         }
578
579         /* Special behaviours */
580         if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
581                 return NT_STATUS_NO_MEMORY;
582         }
583
584         return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
585                                           mem_ctx, ppdesc, theacl);
586 }
587
588 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
589                              const char *name,
590                              uint32 security_info,
591                              TALLOC_CTX *mem_ctx,
592                              struct security_descriptor **ppdesc,
593                              SMB4ACL_T *theacl)
594 {
595         SMB_STRUCT_STAT sbuf;
596         smbacl4_vfs_params params;
597
598         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
599
600         if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
601                 return map_nt_error_from_unix(errno);
602         }
603
604         /* Special behaviours */
605         if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
606                 return NT_STATUS_NO_MEMORY;
607         }
608
609         return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
610                                           mem_ctx, ppdesc, theacl);
611 }
612
613 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
614 {
615         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
616         SMB_ACE4_INT_T *aceint;
617
618         DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
619
620         for (aceint = aclint->first;
621              aceint!=NULL;
622              aceint=(SMB_ACE4_INT_T *)aceint->next) {
623                 SMB_ACE4PROP_T *ace = &aceint->prop;
624
625                 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
626                               "mask=0x%x, id=%d\n",
627                               ace->aceType,
628                               ace->aceFlags, ace->flags,
629                               ace->aceMask,
630                               ace->who.id));
631         }
632 }
633
634 /*
635  * Find 2 NFS4 who-special ACE property (non-copy!!!)
636  * match nonzero if "special" and who is equal
637  * return ace if found matching; otherwise NULL
638  */
639 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
640         SMB4ACL_T *theacl,
641         SMB_ACE4PROP_T *aceNew)
642 {
643         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
644         SMB_ACE4_INT_T *aceint;
645
646         for (aceint = aclint->first; aceint != NULL;
647              aceint=(SMB_ACE4_INT_T *)aceint->next) {
648                 SMB_ACE4PROP_T *ace = &aceint->prop;
649
650                 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
651                           "new type:0x%x flags:0x%x aceFlags:0x%x\n",
652                           ace->aceType, ace->flags, ace->aceFlags,
653                           aceNew->aceType, aceNew->flags,aceNew->aceFlags));
654
655                 if (ace->flags == aceNew->flags &&
656                         ace->aceType==aceNew->aceType &&
657                         ace->aceFlags==aceNew->aceFlags)
658                 {
659                         /* keep type safety; e.g. gid is an u.short */
660                         if (ace->flags & SMB_ACE4_ID_SPECIAL)
661                         {
662                                 if (ace->who.special_id ==
663                                     aceNew->who.special_id)
664                                         return ace;
665                         } else {
666                                 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
667                                 {
668                                         if (ace->who.gid==aceNew->who.gid)
669                                                 return ace;
670                                 } else {
671                                         if (ace->who.uid==aceNew->who.uid)
672                                                 return ace;
673                                 }
674                         }
675                 }
676         }
677
678         return NULL;
679 }
680
681
682 static bool smbacl4_fill_ace4(
683         const struct smb_filename *filename,
684         smbacl4_vfs_params *params,
685         uid_t ownerUID,
686         gid_t ownerGID,
687         const struct security_ace *ace_nt, /* input */
688         SMB_ACE4PROP_T *ace_v4 /* output */
689 )
690 {
691         DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
692
693         memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
694
695         /* only ACCESS|DENY supported right now */
696         ace_v4->aceType = ace_nt->type;
697
698         ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
699                 ace_nt->flags);
700
701         /* remove inheritance flags on files */
702         if (VALID_STAT(filename->st) &&
703             !S_ISDIR(filename->st.st_ex_mode)) {
704                 DEBUG(10, ("Removing inheritance flags from a file\n"));
705                 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
706                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
707                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
708                                       SMB_ACE4_INHERIT_ONLY_ACE);
709         }
710
711         ace_v4->aceMask = ace_nt->access_mask &
712                 (SEC_STD_ALL | SEC_FILE_ALL);
713
714         se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
715
716         if (ace_v4->aceFlags!=ace_nt->flags)
717                 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
718                         ace_v4->aceFlags, ace_nt->flags));
719
720         if (ace_v4->aceMask!=ace_nt->access_mask)
721                 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
722                         ace_v4->aceMask, ace_nt->access_mask));
723
724         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
725                 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
726                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
727         } else if (params->mode!=e_special &&
728                    dom_sid_equal(&ace_nt->trustee,
729                                  &global_sid_Creator_Owner)) {
730                 DEBUG(10, ("Map creator owner\n"));
731                 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
732                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
733                 /* A non inheriting creator owner entry has no effect. */
734                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
735                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
736                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
737                         return false;
738                 }
739         } else if (params->mode!=e_special &&
740                    dom_sid_equal(&ace_nt->trustee,
741                                  &global_sid_Creator_Group)) {
742                 DEBUG(10, ("Map creator owner group\n"));
743                 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
744                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
745                 /* A non inheriting creator group entry has no effect. */
746                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
747                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
748                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
749                         return false;
750                 }
751         } else {
752                 uid_t uid;
753                 gid_t gid;
754
755                 if (sid_to_gid(&ace_nt->trustee, &gid)) {
756                         ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
757                         ace_v4->who.gid = gid;
758                 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
759                         ace_v4->who.uid = uid;
760                 } else {
761                         DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
762                                   "convert %s to uid or gid\n",
763                                   filename->base_name,
764                                   sid_string_dbg(&ace_nt->trustee)));
765                         return false;
766                 }
767         }
768
769         return true; /* OK */
770 }
771
772 static int smbacl4_MergeIgnoreReject(
773         enum smbacl4_acedup_enum acedup,
774         SMB4ACL_T *theacl, /* may modify it */
775         SMB_ACE4PROP_T *ace, /* the "new" ACE */
776         bool    *paddNewACE,
777         int     i
778 )
779 {
780         int     result = 0;
781         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
782         if (ace4found)
783         {
784                 switch(acedup)
785                 {
786                 case e_merge: /* "merge" flags */
787                         *paddNewACE = false;
788                         ace4found->aceFlags |= ace->aceFlags;
789                         ace4found->aceMask |= ace->aceMask;
790                         break;
791                 case e_ignore: /* leave out this record */
792                         *paddNewACE = false;
793                         break;
794                 case e_reject: /* do an error */
795                         DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
796                         errno = EINVAL; /* SHOULD be set on any _real_ error */
797                         result = -1;
798                         break;
799                 default:
800                         break;
801                 }
802         }
803         return result;
804 }
805
806 static int smbacl4_substitute_special(
807         SMB4ACL_T *theacl,
808         uid_t ownerUID,
809         gid_t ownerGID
810 )
811 {
812         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
813         SMB_ACE4_INT_T *aceint;
814
815         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
816                 SMB_ACE4PROP_T *ace = &aceint->prop;
817
818                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
819                           "mask: %x, who: %d\n",
820                           ace->aceType, ace->flags, ace->aceFlags,
821                           ace->aceMask, ace->who.id));
822
823                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
824                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
825                     ace->who.uid == ownerUID) {
826                         ace->flags |= SMB_ACE4_ID_SPECIAL;
827                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
828                         DEBUG(10,("replaced with special owner ace\n"));
829                 }
830
831                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
832                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
833                     ace->who.uid == ownerGID) {
834                         ace->flags |= SMB_ACE4_ID_SPECIAL;
835                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
836                         DEBUG(10,("replaced with special group ace\n"));
837                 }
838         }
839         return true; /* OK */
840 }
841
842 static int smbacl4_substitute_simple(
843         SMB4ACL_T *theacl,
844         uid_t ownerUID,
845         gid_t ownerGID
846 )
847 {
848         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
849         SMB_ACE4_INT_T *aceint;
850
851         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
852                 SMB_ACE4PROP_T *ace = &aceint->prop;
853
854                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
855                           "mask: %x, who: %d\n",
856                           ace->aceType, ace->flags, ace->aceFlags,
857                           ace->aceMask, ace->who.id));
858
859                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
860                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
861                     ace->who.uid == ownerUID &&
862                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
863                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
864                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
865                         ace->flags |= SMB_ACE4_ID_SPECIAL;
866                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
867                         DEBUG(10,("replaced with special owner ace\n"));
868                 }
869
870                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
871                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
872                     ace->who.uid == ownerGID &&
873                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
874                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
875                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
876                         ace->flags |= SMB_ACE4_ID_SPECIAL;
877                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
878                         DEBUG(10,("replaced with special group ace\n"));
879                 }
880         }
881         return true; /* OK */
882 }
883
884 static SMB4ACL_T *smbacl4_win2nfs4(
885         TALLOC_CTX *mem_ctx,
886         const files_struct *fsp,
887         const struct security_acl *dacl,
888         smbacl4_vfs_params *pparams,
889         uid_t ownerUID,
890         gid_t ownerGID
891 )
892 {
893         SMB4ACL_T *theacl;
894         uint32  i;
895         const char *filename = fsp->fsp_name->base_name;
896
897         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
898
899         theacl = smb_create_smb4acl(mem_ctx);
900         if (theacl==NULL)
901                 return NULL;
902
903         for(i=0; i<dacl->num_aces; i++) {
904                 SMB_ACE4PROP_T  ace_v4;
905                 bool    addNewACE = true;
906
907                 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
908                                        ownerUID, ownerGID,
909                                        dacl->aces + i, &ace_v4)) {
910                         DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
911                                   filename,
912                                   sid_string_dbg(&((dacl->aces+i)->trustee))));
913                         continue;
914                 }
915
916                 if (pparams->acedup!=e_dontcare) {
917                         if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
918                                 &ace_v4, &addNewACE, i))
919                                 return NULL;
920                 }
921
922                 if (addNewACE)
923                         smb_add_ace4(theacl, &ace_v4);
924         }
925
926         if (pparams->mode==e_simple) {
927                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
928         }
929
930         if (pparams->mode==e_special) {
931                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
932         }
933
934         return theacl;
935 }
936
937 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
938         uint32 security_info_sent,
939         const struct security_descriptor *psd,
940         set_nfs4acl_native_fn_t set_nfs4_native)
941 {
942         smbacl4_vfs_params params;
943         SMB4ACL_T *theacl = NULL;
944         bool    result;
945
946         SMB_STRUCT_STAT sbuf;
947         bool set_acl_as_root = false;
948         uid_t newUID = (uid_t)-1;
949         gid_t newGID = (gid_t)-1;
950         int saved_errno;
951         TALLOC_CTX *frame = talloc_stackframe();
952
953         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
954
955         if ((security_info_sent & (SECINFO_DACL |
956                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
957         {
958                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
959                         security_info_sent));
960                 TALLOC_FREE(frame);
961                 return NT_STATUS_OK; /* won't show error - later to be
962                                       * refined... */
963         }
964
965         /* Special behaviours */
966         if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
967                                    fsp->conn, &params)) {
968                 TALLOC_FREE(frame);
969                 return NT_STATUS_NO_MEMORY;
970         }
971
972         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
973                 TALLOC_FREE(frame);
974                 return map_nt_error_from_unix(errno);
975         }
976
977         if (params.do_chown) {
978                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
979                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
980                                                    security_info_sent, psd);
981                 if (!NT_STATUS_IS_OK(status)) {
982                         DEBUG(8, ("unpack_nt_owners failed"));
983                         TALLOC_FREE(frame);
984                         return status;
985                 }
986                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
987                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
988
989                         status = try_chown(fsp, newUID, newGID);
990                         if (!NT_STATUS_IS_OK(status)) {
991                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
992                                          "%s.\n", fsp_str_dbg(fsp),
993                                          (unsigned int)newUID,
994                                          (unsigned int)newGID,
995                                          nt_errstr(status)));
996                                 TALLOC_FREE(frame);
997                                 return status;
998                         }
999
1000                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
1001                                   fsp_str_dbg(fsp), (unsigned int)newUID,
1002                                   (unsigned int)newGID));
1003                         if (smbacl4_GetFileOwner(fsp->conn,
1004                                                  fsp->fsp_name->base_name,
1005                                                  &sbuf)){
1006                                 TALLOC_FREE(frame);
1007                                 return map_nt_error_from_unix(errno);
1008                         }
1009
1010                         /* If we successfully chowned, we know we must
1011                          * be able to set the acl, so do it as root.
1012                          */
1013                         set_acl_as_root = true;
1014                 }
1015         }
1016
1017         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1018                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1019                            security_info_sent));
1020                 TALLOC_FREE(frame);
1021                 return NT_STATUS_OK;
1022         }
1023
1024         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1025                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
1026         if (!theacl) {
1027                 TALLOC_FREE(frame);
1028                 return map_nt_error_from_unix(errno);
1029         }
1030
1031         smbacl4_dump_nfs4acl(10, theacl);
1032
1033         if (set_acl_as_root) {
1034                 become_root();
1035         }
1036         result = set_nfs4_native(handle, fsp, theacl);
1037         saved_errno = errno;
1038         if (set_acl_as_root) {
1039                 unbecome_root();
1040         }
1041
1042         TALLOC_FREE(frame);
1043
1044         if (result!=true) {
1045                 errno = saved_errno;
1046                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1047                            strerror(errno)));
1048                 return map_nt_error_from_unix(errno);
1049         }
1050
1051         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1052         return NT_STATUS_OK;
1053 }