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