nfs4acls: Add "smbacl4_vfs_params" parameter to smb_fget_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                              uint32_t security_info,
563                              TALLOC_CTX *mem_ctx,
564                              struct security_descriptor **ppdesc,
565                              struct SMB4ACL_T *theacl)
566 {
567         SMB_STRUCT_STAT sbuf;
568         struct smbacl4_vfs_params params;
569
570         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
571                 smb_fname->base_name));
572
573         if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
574                 return map_nt_error_from_unix(errno);
575         }
576
577         /* Special behaviours */
578         if (smbacl4_get_vfs_params(conn, &params)) {
579                 return NT_STATUS_NO_MEMORY;
580         }
581
582         return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
583                                           mem_ctx, ppdesc, theacl);
584 }
585
586 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
587 {
588         struct SMB4ACE_T *aceint;
589
590         DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
591
592         for (aceint = acl->first; aceint != NULL; aceint = 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; aceint = aceint->next) {
616                 SMB_ACE4PROP_T *ace = &aceint->prop;
617
618                 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
619                           "new type:0x%x flags:0x%x aceFlags:0x%x\n",
620                           ace->aceType, ace->flags, ace->aceFlags,
621                           aceNew->aceType, aceNew->flags,aceNew->aceFlags));
622
623                 if (ace->flags == aceNew->flags &&
624                         ace->aceType==aceNew->aceType &&
625                         ace->aceFlags==aceNew->aceFlags)
626                 {
627                         /* keep type safety; e.g. gid is an u.short */
628                         if (ace->flags & SMB_ACE4_ID_SPECIAL)
629                         {
630                                 if (ace->who.special_id ==
631                                     aceNew->who.special_id)
632                                         return ace;
633                         } else {
634                                 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
635                                 {
636                                         if (ace->who.gid==aceNew->who.gid)
637                                                 return ace;
638                                 } else {
639                                         if (ace->who.uid==aceNew->who.uid)
640                                                 return ace;
641                                 }
642                         }
643                 }
644         }
645
646         return NULL;
647 }
648
649
650 static bool smbacl4_fill_ace4(
651         const struct smb_filename *filename,
652         const struct smbacl4_vfs_params *params,
653         uid_t ownerUID,
654         gid_t ownerGID,
655         const struct security_ace *ace_nt, /* input */
656         SMB_ACE4PROP_T *ace_v4 /* output */
657 )
658 {
659         DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
660
661         ZERO_STRUCTP(ace_v4);
662
663         /* only ACCESS|DENY supported right now */
664         ace_v4->aceType = ace_nt->type;
665
666         ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
667                 ace_nt->flags);
668
669         /* remove inheritance flags on files */
670         if (VALID_STAT(filename->st) &&
671             !S_ISDIR(filename->st.st_ex_mode)) {
672                 DEBUG(10, ("Removing inheritance flags from a file\n"));
673                 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
674                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
675                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
676                                       SMB_ACE4_INHERIT_ONLY_ACE);
677         }
678
679         ace_v4->aceMask = ace_nt->access_mask &
680                 (SEC_STD_ALL | SEC_FILE_ALL);
681
682         se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
683
684         if (ace_v4->aceFlags!=ace_nt->flags)
685                 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
686                         ace_v4->aceFlags, ace_nt->flags));
687
688         if (ace_v4->aceMask!=ace_nt->access_mask)
689                 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
690                         ace_v4->aceMask, ace_nt->access_mask));
691
692         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
693                 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
694                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
695         } else if (params->mode!=e_special &&
696                    dom_sid_equal(&ace_nt->trustee,
697                                  &global_sid_Creator_Owner)) {
698                 DEBUG(10, ("Map creator owner\n"));
699                 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
700                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
701                 /* A non inheriting creator owner entry has no effect. */
702                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
703                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
704                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
705                         return false;
706                 }
707         } else if (params->mode!=e_special &&
708                    dom_sid_equal(&ace_nt->trustee,
709                                  &global_sid_Creator_Group)) {
710                 DEBUG(10, ("Map creator owner group\n"));
711                 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
712                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
713                 /* A non inheriting creator group entry has no effect. */
714                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
715                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
716                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
717                         return false;
718                 }
719         } else {
720                 uid_t uid;
721                 gid_t gid;
722
723                 if (sid_to_gid(&ace_nt->trustee, &gid)) {
724                         ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
725                         ace_v4->who.gid = gid;
726                 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
727                         ace_v4->who.uid = uid;
728                 } else if (dom_sid_compare_domain(&ace_nt->trustee,
729                                                   &global_sid_Unix_NFS) == 0) {
730                         return false;
731                 } else {
732                         DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
733                                   "convert %s to uid or gid\n",
734                                   filename->base_name,
735                                   sid_string_dbg(&ace_nt->trustee)));
736                         return false;
737                 }
738         }
739
740         return true; /* OK */
741 }
742
743 static int smbacl4_MergeIgnoreReject(
744         enum smbacl4_acedup_enum acedup,
745         struct SMB4ACL_T *theacl, /* may modify it */
746         SMB_ACE4PROP_T *ace, /* the "new" ACE */
747         bool    *paddNewACE,
748         int     i
749 )
750 {
751         int     result = 0;
752         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
753         if (ace4found)
754         {
755                 switch(acedup)
756                 {
757                 case e_merge: /* "merge" flags */
758                         *paddNewACE = false;
759                         ace4found->aceFlags |= ace->aceFlags;
760                         ace4found->aceMask |= ace->aceMask;
761                         break;
762                 case e_ignore: /* leave out this record */
763                         *paddNewACE = false;
764                         break;
765                 case e_reject: /* do an error */
766                         DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
767                         errno = EINVAL; /* SHOULD be set on any _real_ error */
768                         result = -1;
769                         break;
770                 default:
771                         break;
772                 }
773         }
774         return result;
775 }
776
777 static int smbacl4_substitute_special(
778         struct SMB4ACL_T *acl,
779         uid_t ownerUID,
780         gid_t ownerGID
781 )
782 {
783         struct SMB4ACE_T *aceint;
784
785         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
786                 SMB_ACE4PROP_T *ace = &aceint->prop;
787
788                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
789                           "mask: %x, who: %d\n",
790                           ace->aceType, ace->flags, ace->aceFlags,
791                           ace->aceMask, ace->who.id));
792
793                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
794                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
795                     ace->who.uid == ownerUID) {
796                         ace->flags |= SMB_ACE4_ID_SPECIAL;
797                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
798                         DEBUG(10,("replaced with special owner ace\n"));
799                 }
800
801                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
802                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
803                     ace->who.uid == ownerGID) {
804                         ace->flags |= SMB_ACE4_ID_SPECIAL;
805                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
806                         DEBUG(10,("replaced with special group ace\n"));
807                 }
808         }
809         return true; /* OK */
810 }
811
812 static int smbacl4_substitute_simple(
813         struct SMB4ACL_T *acl,
814         uid_t ownerUID,
815         gid_t ownerGID
816 )
817 {
818         struct SMB4ACE_T *aceint;
819
820         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
821                 SMB_ACE4PROP_T *ace = &aceint->prop;
822
823                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
824                           "mask: %x, who: %d\n",
825                           ace->aceType, ace->flags, ace->aceFlags,
826                           ace->aceMask, ace->who.id));
827
828                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
829                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
830                     ace->who.uid == ownerUID &&
831                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
832                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
833                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
834                         ace->flags |= SMB_ACE4_ID_SPECIAL;
835                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
836                         DEBUG(10,("replaced with special owner ace\n"));
837                 }
838
839                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
840                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
841                     ace->who.uid == ownerGID &&
842                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
843                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
844                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
845                         ace->flags |= SMB_ACE4_ID_SPECIAL;
846                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
847                         DEBUG(10,("replaced with special group ace\n"));
848                 }
849         }
850         return true; /* OK */
851 }
852
853 static struct SMB4ACL_T *smbacl4_win2nfs4(
854         TALLOC_CTX *mem_ctx,
855         const files_struct *fsp,
856         const struct security_acl *dacl,
857         const struct smbacl4_vfs_params *pparams,
858         uid_t ownerUID,
859         gid_t ownerGID
860 )
861 {
862         struct SMB4ACL_T *theacl;
863         uint32_t i;
864         const char *filename = fsp->fsp_name->base_name;
865
866         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
867
868         theacl = smb_create_smb4acl(mem_ctx);
869         if (theacl==NULL)
870                 return NULL;
871
872         for(i=0; i<dacl->num_aces; i++) {
873                 SMB_ACE4PROP_T  ace_v4;
874                 bool    addNewACE = true;
875
876                 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
877                                        ownerUID, ownerGID,
878                                        dacl->aces + i, &ace_v4)) {
879                         DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
880                                   filename,
881                                   sid_string_dbg(&((dacl->aces+i)->trustee))));
882                         continue;
883                 }
884
885                 if (pparams->acedup!=e_dontcare) {
886                         if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
887                                 &ace_v4, &addNewACE, i))
888                                 return NULL;
889                 }
890
891                 if (addNewACE)
892                         smb_add_ace4(theacl, &ace_v4);
893         }
894
895         if (pparams->mode==e_simple) {
896                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
897         }
898
899         if (pparams->mode==e_special) {
900                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
901         }
902
903         return theacl;
904 }
905
906 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
907         uint32_t security_info_sent,
908         const struct security_descriptor *psd,
909         set_nfs4acl_native_fn_t set_nfs4_native)
910 {
911         struct smbacl4_vfs_params params;
912         struct SMB4ACL_T *theacl = NULL;
913         bool    result;
914
915         SMB_STRUCT_STAT sbuf;
916         bool set_acl_as_root = false;
917         uid_t newUID = (uid_t)-1;
918         gid_t newGID = (gid_t)-1;
919         int saved_errno;
920         TALLOC_CTX *frame = talloc_stackframe();
921
922         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
923
924         if ((security_info_sent & (SECINFO_DACL |
925                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
926         {
927                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
928                         security_info_sent));
929                 TALLOC_FREE(frame);
930                 return NT_STATUS_OK; /* won't show error - later to be
931                                       * refined... */
932         }
933
934         /* Special behaviours */
935         if (smbacl4_get_vfs_params(fsp->conn, &params)) {
936                 TALLOC_FREE(frame);
937                 return NT_STATUS_NO_MEMORY;
938         }
939
940         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
941                 TALLOC_FREE(frame);
942                 return map_nt_error_from_unix(errno);
943         }
944
945         if (params.do_chown) {
946                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
947                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
948                                                    security_info_sent, psd);
949                 if (!NT_STATUS_IS_OK(status)) {
950                         DEBUG(8, ("unpack_nt_owners failed"));
951                         TALLOC_FREE(frame);
952                         return status;
953                 }
954                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
955                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
956
957                         status = try_chown(fsp, newUID, newGID);
958                         if (!NT_STATUS_IS_OK(status)) {
959                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
960                                          "%s.\n", fsp_str_dbg(fsp),
961                                          (unsigned int)newUID,
962                                          (unsigned int)newGID,
963                                          nt_errstr(status)));
964                                 TALLOC_FREE(frame);
965                                 return status;
966                         }
967
968                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
969                                   fsp_str_dbg(fsp), (unsigned int)newUID,
970                                   (unsigned int)newGID));
971                         if (smbacl4_GetFileOwner(fsp->conn,
972                                                  fsp->fsp_name,
973                                                  &sbuf)){
974                                 TALLOC_FREE(frame);
975                                 return map_nt_error_from_unix(errno);
976                         }
977
978                         /* If we successfully chowned, we know we must
979                          * be able to set the acl, so do it as root.
980                          */
981                         set_acl_as_root = true;
982                 }
983         }
984
985         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
986                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
987                            security_info_sent));
988                 TALLOC_FREE(frame);
989                 return NT_STATUS_OK;
990         }
991
992         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
993                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
994         if (!theacl) {
995                 TALLOC_FREE(frame);
996                 return map_nt_error_from_unix(errno);
997         }
998
999         smbacl4_set_controlflags(theacl, psd->type);
1000         smbacl4_dump_nfs4acl(10, theacl);
1001
1002         if (set_acl_as_root) {
1003                 become_root();
1004         }
1005         result = set_nfs4_native(handle, fsp, theacl);
1006         saved_errno = errno;
1007         if (set_acl_as_root) {
1008                 unbecome_root();
1009         }
1010
1011         TALLOC_FREE(frame);
1012
1013         if (result!=true) {
1014                 errno = saved_errno;
1015                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1016                            strerror(errno)));
1017                 return map_nt_error_from_unix(errno);
1018         }
1019
1020         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1021         return NT_STATUS_OK;
1022 }