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