nfs4acls: Add "smbacl4_vfs_params" parameter to smb_set_nt_acl_nfs4
[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 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 };
63
64 /*
65  * Gather special parameters for NFS4 ACL handling
66  */
67 static int smbacl4_get_vfs_params(
68         struct connection_struct *conn,
69         struct smbacl4_vfs_params *params
70 )
71 {
72         static const struct enum_list enum_smbacl4_modes[] = {
73                 { e_simple, "simple" },
74                 { e_special, "special" },
75                 { -1 , NULL }
76         };
77         static const struct enum_list enum_smbacl4_acedups[] = {
78                 { e_dontcare, "dontcare" },
79                 { e_reject, "reject" },
80                 { e_ignore, "ignore" },
81                 { e_merge, "merge" },
82                 { -1 , NULL }
83         };
84         int enumval;
85
86         ZERO_STRUCTP(params);
87
88         enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
89                                enum_smbacl4_modes, e_simple);
90         if (enumval == -1) {
91                 DEBUG(10, ("value for %s:mode unknown\n",
92                            SMBACL4_PARAM_TYPE_NAME));
93                 return -1;
94         }
95         params->mode = (enum smbacl4_mode_enum)enumval;
96
97         params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
98                 "chown", true);
99
100         enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
101                                enum_smbacl4_acedups, e_dontcare);
102         if (enumval == -1) {
103                 DEBUG(10, ("value for %s:acedup unknown\n",
104                            SMBACL4_PARAM_TYPE_NAME));
105                 return -1;
106         }
107         params->acedup = (enum smbacl4_acedup_enum)enumval;
108
109         params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110
111         DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
112                 enum_smbacl4_modes[params->mode].name,
113                 params->do_chown ? "true" : "false",
114                 enum_smbacl4_acedups[params->acedup].name,
115                 params->map_full_control ? "true" : "false"));
116
117         return 0;
118 }
119
120 /************************************************
121  Split the ACE flag mapping between nfs4 and Windows
122  into two separate functions rather than trying to do
123  it inline. Allows us to carefully control what flags
124  are mapped to what in one place.
125 ************************************************/
126
127 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
128         uint32_t nfs4_ace_flags)
129 {
130         uint32_t win_ace_flags = 0;
131
132         /* The nfs4 flags <= 0xf map perfectly. */
133         win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
134                                       SEC_ACE_FLAG_CONTAINER_INHERIT|
135                                       SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
136                                       SEC_ACE_FLAG_INHERIT_ONLY);
137
138         /* flags greater than 0xf have diverged :-(. */
139         /* See the nfs4 ace flag definitions here:
140            http://www.ietf.org/rfc/rfc3530.txt.
141            And the Windows ace flag definitions here:
142            librpc/idl/security.idl. */
143         if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
144                 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
145         }
146
147         return win_ace_flags;
148 }
149
150 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
151 {
152         uint32_t nfs4_ace_flags = 0;
153
154         /* The windows flags <= 0xf map perfectly. */
155         nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
156                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
157                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
158                                       SMB_ACE4_INHERIT_ONLY_ACE);
159
160         /* flags greater than 0xf have diverged :-(. */
161         /* See the nfs4 ace flag definitions here:
162            http://www.ietf.org/rfc/rfc3530.txt.
163            And the Windows ace flag definitions here:
164            librpc/idl/security.idl. */
165         if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
166                 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
167         }
168
169         return nfs4_ace_flags;
170 }
171
172 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
173 {
174         struct SMB4ACL_T *theacl;
175
176         theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
177         if (theacl==NULL)
178         {
179                 DEBUG(0, ("TALLOC_SIZE failed\n"));
180                 errno = ENOMEM;
181                 return NULL;
182         }
183         theacl->controlflags = SEC_DESC_SELF_RELATIVE;
184         /* theacl->first, last = NULL not needed */
185         return theacl;
186 }
187
188 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 {
190         struct SMB4ACE_T *ace;
191
192         ace = talloc_zero(acl, 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 = ace;
208                 acl->last = ace;
209         }
210         acl->naces++;
211
212         return 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 struct smb_filename *smb_fname,
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, smb_fname, 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, 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         const struct 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 = talloc_zero_array(mem_ctx, struct security_ace,
322                                         2 * acl->naces);
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; aceint != NULL; aceint = aceint->next) {
331                 uint32_t mask;
332                 struct dom_sid sid;
333                 SMB_ACE4PROP_T  *ace = &aceint->prop;
334                 uint32_t win_ace_flags;
335
336                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
337                            "mask: %x, who: %d\n",
338                            ace->aceType, ace->flags,
339                            ace->aceFlags, ace->aceMask, ace->who.id));
340
341                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
342                         switch (ace->who.special_id) {
343                         case SMB_ACE4_WHO_OWNER:
344                                 sid_copy(&sid, psid_owner);
345                                 break;
346                         case SMB_ACE4_WHO_GROUP:
347                                 sid_copy(&sid, psid_group);
348                                 break;
349                         case SMB_ACE4_WHO_EVERYONE:
350                                 sid_copy(&sid, &global_sid_World);
351                                 break;
352                         default:
353                                 DEBUG(8, ("invalid special who id %d "
354                                         "ignored\n", ace->who.special_id));
355                                 continue;
356                         }
357                 } else {
358                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
359                                 gid_to_sid(&sid, ace->who.gid);
360                         } else {
361                                 uid_to_sid(&sid, ace->who.uid);
362                         }
363                 }
364                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
365                            sid_string_dbg(&sid)));
366
367                 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
368                         ace->aceMask |= SMB_ACE4_DELETE_CHILD;
369                 }
370
371                 if (!is_directory && params->map_full_control) {
372                         /*
373                          * Do we have all access except DELETE_CHILD
374                          * (not caring about the delete bit).
375                          */
376                         uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
377                                                 SMB_ACE4_ALL_MASKS);
378                         if (test_mask == SMB_ACE4_ALL_MASKS) {
379                                 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
380                         }
381                 }
382
383                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
384                         ace->aceFlags);
385                 if (!is_directory &&
386                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
388                         /*
389                          * GPFS sets inherits dir_inhert and file_inherit flags
390                          * to files, too, which confuses windows, and seems to
391                          * be wrong anyways. ==> Map these bits away for files.
392                          */
393                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
396                 }
397                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398                       ace->aceFlags, win_ace_flags));
399
400                 mask = ace->aceMask;
401                 /* Windows clients expect SYNC on acls to
402                    correctly allow rename. See bug #7909. */
403                 /* But not on DENY ace entries. See
404                    bug #8442. */
405                 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406                         mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
407                 }
408
409                 /* Mapping of owner@ and group@ to creator owner and
410                    creator group. Keep old behavior in mode special. */
411                 if (params->mode != e_special &&
412                     ace->flags & SMB_ACE4_ID_SPECIAL &&
413                     (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
414                      ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
415                         DEBUG(10, ("Map special entry\n"));
416                         if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
417                                 uint32_t win_ace_flags_current;
418                                 DEBUG(10, ("Map current sid\n"));
419                                 win_ace_flags_current = win_ace_flags &
420                                         ~(SEC_ACE_FLAG_OBJECT_INHERIT |
421                                           SEC_ACE_FLAG_CONTAINER_INHERIT);
422                                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
423                                              ace->aceType, mask,
424                                              win_ace_flags_current);
425                         }
426                         if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
427                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
428                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
429                                 uint32_t win_ace_flags_creator;
430                                 DEBUG(10, ("Map creator owner\n"));
431                                 win_ace_flags_creator = win_ace_flags |
432                                         SMB_ACE4_INHERIT_ONLY_ACE;
433                                 init_sec_ace(&nt_ace_list[good_aces++],
434                                              &global_sid_Creator_Owner,
435                                              ace->aceType, mask,
436                                              win_ace_flags_creator);
437                         }
438                         if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
439                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
440                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
441                                 uint32_t win_ace_flags_creator;
442                                 DEBUG(10, ("Map creator owner group\n"));
443                                 win_ace_flags_creator = win_ace_flags |
444                                         SMB_ACE4_INHERIT_ONLY_ACE;
445                                 init_sec_ace(&nt_ace_list[good_aces++],
446                                              &global_sid_Creator_Group,
447                                              ace->aceType, mask,
448                                              win_ace_flags_creator);
449                         }
450                 } else {
451                         DEBUG(10, ("Map normal sid\n"));
452                         init_sec_ace(&nt_ace_list[good_aces++], &sid,
453                                      ace->aceType, mask,
454                                      win_ace_flags);
455                 }
456         }
457
458         nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
459                                      good_aces);
460
461         /* returns a NULL ace list when good_aces is zero. */
462         if (good_aces && nt_ace_list == NULL) {
463                 DEBUG(10, ("realloc error with %d aces", good_aces));
464                 errno = ENOMEM;
465                 return false;
466         }
467
468         *ppnt_ace_list = nt_ace_list;
469         *pgood_aces = good_aces;
470
471         return true;
472 }
473
474 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
475                                            const struct smbacl4_vfs_params *params,
476                                            uint32_t security_info,
477                                            TALLOC_CTX *mem_ctx,
478                                            struct security_descriptor **ppdesc,
479                                            struct SMB4ACL_T *theacl)
480 {
481         int good_aces = 0;
482         struct dom_sid sid_owner, sid_group;
483         size_t sd_size = 0;
484         struct security_ace *nt_ace_list = NULL;
485         struct security_acl *psa = NULL;
486         TALLOC_CTX *frame = talloc_stackframe();
487         bool ok;
488
489         if (theacl==NULL) {
490                 TALLOC_FREE(frame);
491                 return NT_STATUS_ACCESS_DENIED; /* special because we
492                                                  * need to think through
493                                                  * the null case.*/
494         }
495
496         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497         gid_to_sid(&sid_group, sbuf->st_ex_gid);
498
499         ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
500                               S_ISDIR(sbuf->st_ex_mode),
501                               &nt_ace_list, &good_aces);
502         if (!ok) {
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                               const struct smbacl4_vfs_params *pparams,
537                               uint32_t security_info,
538                               TALLOC_CTX *mem_ctx,
539                               struct security_descriptor **ppdesc,
540                               struct SMB4ACL_T *theacl)
541 {
542         SMB_STRUCT_STAT sbuf;
543         struct smbacl4_vfs_params params;
544
545         DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
546
547         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
548                 return map_nt_error_from_unix(errno);
549         }
550
551         /* Special behaviours */
552         if (smbacl4_get_vfs_params(fsp->conn, &params)) {
553                 return NT_STATUS_NO_MEMORY;
554         }
555
556         return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
557                                           mem_ctx, ppdesc, theacl);
558 }
559
560 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
561                              const struct smb_filename *smb_fname,
562                              const struct smbacl4_vfs_params *pparams,
563                              uint32_t security_info,
564                              TALLOC_CTX *mem_ctx,
565                              struct security_descriptor **ppdesc,
566                              struct SMB4ACL_T *theacl)
567 {
568         SMB_STRUCT_STAT sbuf;
569         struct smbacl4_vfs_params params;
570
571         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
572                 smb_fname->base_name));
573
574         if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
575                 return map_nt_error_from_unix(errno);
576         }
577
578         /* Special behaviours */
579         if (smbacl4_get_vfs_params(conn, &params)) {
580                 return NT_STATUS_NO_MEMORY;
581         }
582
583         return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
584                                           mem_ctx, ppdesc, theacl);
585 }
586
587 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
588 {
589         struct SMB4ACE_T *aceint;
590
591         DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
592
593         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
594                 SMB_ACE4PROP_T *ace = &aceint->prop;
595
596                 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
597                               "mask=0x%x, id=%d\n",
598                               ace->aceType,
599                               ace->aceFlags, ace->flags,
600                               ace->aceMask,
601                               ace->who.id));
602         }
603 }
604
605 /*
606  * Find 2 NFS4 who-special ACE property (non-copy!!!)
607  * match nonzero if "special" and who is equal
608  * return ace if found matching; otherwise NULL
609  */
610 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
611         struct SMB4ACL_T *acl,
612         SMB_ACE4PROP_T *aceNew)
613 {
614         struct SMB4ACE_T *aceint;
615
616         for (aceint = acl->first; aceint != NULL; aceint = 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         const struct 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; aceint = aceint->next) {
787                 SMB_ACE4PROP_T *ace = &aceint->prop;
788
789                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
790                           "mask: %x, who: %d\n",
791                           ace->aceType, ace->flags, ace->aceFlags,
792                           ace->aceMask, ace->who.id));
793
794                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
795                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
796                     ace->who.uid == ownerUID) {
797                         ace->flags |= SMB_ACE4_ID_SPECIAL;
798                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
799                         DEBUG(10,("replaced with special owner ace\n"));
800                 }
801
802                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
803                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
804                     ace->who.uid == ownerGID) {
805                         ace->flags |= SMB_ACE4_ID_SPECIAL;
806                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
807                         DEBUG(10,("replaced with special group ace\n"));
808                 }
809         }
810         return true; /* OK */
811 }
812
813 static int smbacl4_substitute_simple(
814         struct SMB4ACL_T *acl,
815         uid_t ownerUID,
816         gid_t ownerGID
817 )
818 {
819         struct SMB4ACE_T *aceint;
820
821         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
822                 SMB_ACE4PROP_T *ace = &aceint->prop;
823
824                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
825                           "mask: %x, who: %d\n",
826                           ace->aceType, ace->flags, ace->aceFlags,
827                           ace->aceMask, ace->who.id));
828
829                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
830                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
831                     ace->who.uid == ownerUID &&
832                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
833                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
834                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
835                         ace->flags |= SMB_ACE4_ID_SPECIAL;
836                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
837                         DEBUG(10,("replaced with special owner ace\n"));
838                 }
839
840                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
841                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
842                     ace->who.uid == ownerGID &&
843                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
844                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
845                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
846                         ace->flags |= SMB_ACE4_ID_SPECIAL;
847                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
848                         DEBUG(10,("replaced with special group ace\n"));
849                 }
850         }
851         return true; /* OK */
852 }
853
854 static struct SMB4ACL_T *smbacl4_win2nfs4(
855         TALLOC_CTX *mem_ctx,
856         const files_struct *fsp,
857         const struct security_acl *dacl,
858         const struct smbacl4_vfs_params *pparams,
859         uid_t ownerUID,
860         gid_t ownerGID
861 )
862 {
863         struct SMB4ACL_T *theacl;
864         uint32_t i;
865         const char *filename = fsp->fsp_name->base_name;
866
867         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
868
869         theacl = smb_create_smb4acl(mem_ctx);
870         if (theacl==NULL)
871                 return NULL;
872
873         for(i=0; i<dacl->num_aces; i++) {
874                 SMB_ACE4PROP_T  ace_v4;
875                 bool    addNewACE = true;
876
877                 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
878                                        ownerUID, ownerGID,
879                                        dacl->aces + i, &ace_v4)) {
880                         DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
881                                   filename,
882                                   sid_string_dbg(&((dacl->aces+i)->trustee))));
883                         continue;
884                 }
885
886                 if (pparams->acedup!=e_dontcare) {
887                         if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
888                                 &ace_v4, &addNewACE, i))
889                                 return NULL;
890                 }
891
892                 if (addNewACE)
893                         smb_add_ace4(theacl, &ace_v4);
894         }
895
896         if (pparams->mode==e_simple) {
897                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
898         }
899
900         if (pparams->mode==e_special) {
901                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
902         }
903
904         return theacl;
905 }
906
907 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
908         const struct smbacl4_vfs_params *pparams,
909         uint32_t security_info_sent,
910         const struct security_descriptor *psd,
911         set_nfs4acl_native_fn_t set_nfs4_native)
912 {
913         struct smbacl4_vfs_params params;
914         struct SMB4ACL_T *theacl = NULL;
915         bool    result;
916
917         SMB_STRUCT_STAT sbuf;
918         bool set_acl_as_root = false;
919         uid_t newUID = (uid_t)-1;
920         gid_t newGID = (gid_t)-1;
921         int saved_errno;
922         TALLOC_CTX *frame = talloc_stackframe();
923
924         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
925
926         if ((security_info_sent & (SECINFO_DACL |
927                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
928         {
929                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
930                         security_info_sent));
931                 TALLOC_FREE(frame);
932                 return NT_STATUS_OK; /* won't show error - later to be
933                                       * refined... */
934         }
935
936         /* Special behaviours */
937         if (smbacl4_get_vfs_params(fsp->conn, &params)) {
938                 TALLOC_FREE(frame);
939                 return NT_STATUS_NO_MEMORY;
940         }
941
942         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
943                 TALLOC_FREE(frame);
944                 return map_nt_error_from_unix(errno);
945         }
946
947         if (params.do_chown) {
948                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
949                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
950                                                    security_info_sent, psd);
951                 if (!NT_STATUS_IS_OK(status)) {
952                         DEBUG(8, ("unpack_nt_owners failed"));
953                         TALLOC_FREE(frame);
954                         return status;
955                 }
956                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
957                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
958
959                         status = try_chown(fsp, newUID, newGID);
960                         if (!NT_STATUS_IS_OK(status)) {
961                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
962                                          "%s.\n", fsp_str_dbg(fsp),
963                                          (unsigned int)newUID,
964                                          (unsigned int)newGID,
965                                          nt_errstr(status)));
966                                 TALLOC_FREE(frame);
967                                 return status;
968                         }
969
970                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
971                                   fsp_str_dbg(fsp), (unsigned int)newUID,
972                                   (unsigned int)newGID));
973                         if (smbacl4_GetFileOwner(fsp->conn,
974                                                  fsp->fsp_name,
975                                                  &sbuf)){
976                                 TALLOC_FREE(frame);
977                                 return map_nt_error_from_unix(errno);
978                         }
979
980                         /* If we successfully chowned, we know we must
981                          * be able to set the acl, so do it as root.
982                          */
983                         set_acl_as_root = true;
984                 }
985         }
986
987         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
988                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
989                            security_info_sent));
990                 TALLOC_FREE(frame);
991                 return NT_STATUS_OK;
992         }
993
994         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
995                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
996         if (!theacl) {
997                 TALLOC_FREE(frame);
998                 return map_nt_error_from_unix(errno);
999         }
1000
1001         smbacl4_set_controlflags(theacl, psd->type);
1002         smbacl4_dump_nfs4acl(10, theacl);
1003
1004         if (set_acl_as_root) {
1005                 become_root();
1006         }
1007         result = set_nfs4_native(handle, fsp, theacl);
1008         saved_errno = errno;
1009         if (set_acl_as_root) {
1010                 unbecome_root();
1011         }
1012
1013         TALLOC_FREE(frame);
1014
1015         if (result!=true) {
1016                 errno = saved_errno;
1017                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1018                            strerror(errno)));
1019                 return map_nt_error_from_unix(errno);
1020         }
1021
1022         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1023         return NT_STATUS_OK;
1024 }