source: vendor/3.6.0/source3/modules/nfs4_acls.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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