Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB NT Security Descriptor / Unix permission conversion.
4 : Copyright (C) Jeremy Allison 1994-2009.
5 : Copyright (C) Andreas Gruenbacher 2002.
6 : Copyright (C) Simo Sorce <idra@samba.org> 2009.
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "smbd/smbd.h"
24 : #include "system/filesys.h"
25 : #include "../libcli/security/security.h"
26 : #include "trans2.h"
27 : #include "passdb/lookup_sid.h"
28 : #include "auth.h"
29 : #include "../librpc/gen_ndr/idmap.h"
30 : #include "../librpc/gen_ndr/ndr_smb_acl.h"
31 : #include "lib/param/loadparm.h"
32 :
33 : extern const struct generic_mapping file_generic_mapping;
34 :
35 : #undef DBGC_CLASS
36 : #define DBGC_CLASS DBGC_ACLS
37 :
38 : /****************************************************************************
39 : Data structures representing the internal ACE format.
40 : ****************************************************************************/
41 :
42 : enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
43 : enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
44 :
45 : typedef struct canon_ace {
46 : struct canon_ace *next, *prev;
47 : SMB_ACL_TAG_T type;
48 : mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
49 : struct dom_sid trustee;
50 : enum ace_owner owner_type;
51 : enum ace_attribute attr;
52 : struct unixid unix_ug;
53 : uint8_t ace_flags; /* From windows ACE entry. */
54 : } canon_ace;
55 :
56 : #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
57 :
58 : /*
59 : * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
60 : * attribute on disk - version 1.
61 : * All values are little endian.
62 : *
63 : * | 1 | 1 | 2 | 2 | ....
64 : * +------+------+-------------+---------------------+-------------+--------------------+
65 : * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
66 : * +------+------+-------------+---------------------+-------------+--------------------+
67 : *
68 : * Entry format is :
69 : *
70 : * | 1 | 4 |
71 : * +------+-------------------+
72 : * | value| uid/gid or world |
73 : * | type | value |
74 : * +------+-------------------+
75 : *
76 : * Version 2 format. Stores extra Windows metadata about an ACL.
77 : *
78 : * | 1 | 2 | 2 | 2 | ....
79 : * +------+----------+-------------+---------------------+-------------+--------------------+
80 : * | vers | ace | num_entries | num_default_entries | ..entries.. | default_entries... |
81 : * | 2 | type | | | | |
82 : * +------+----------+-------------+---------------------+-------------+--------------------+
83 : *
84 : * Entry format is :
85 : *
86 : * | 1 | 1 | 4 |
87 : * +------+------+-------------------+
88 : * | ace | value| uid/gid or world |
89 : * | flag | type | value |
90 : * +------+-------------------+------+
91 : *
92 : */
93 :
94 : #define PAI_VERSION_OFFSET 0
95 :
96 : #define PAI_V1_FLAG_OFFSET 1
97 : #define PAI_V1_NUM_ENTRIES_OFFSET 2
98 : #define PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET 4
99 : #define PAI_V1_ENTRIES_BASE 6
100 : #define PAI_V1_ACL_FLAG_PROTECTED 0x1
101 : #define PAI_V1_ENTRY_LENGTH 5
102 :
103 : #define PAI_V1_VERSION 1
104 :
105 : #define PAI_V2_TYPE_OFFSET 1
106 : #define PAI_V2_NUM_ENTRIES_OFFSET 3
107 : #define PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET 5
108 : #define PAI_V2_ENTRIES_BASE 7
109 : #define PAI_V2_ENTRY_LENGTH 6
110 :
111 : #define PAI_V2_VERSION 2
112 :
113 : /*
114 : * In memory format of user.SAMBA_PAI attribute.
115 : */
116 :
117 : struct pai_entry {
118 : struct pai_entry *next, *prev;
119 : uint8_t ace_flags;
120 : enum ace_owner owner_type;
121 : struct unixid unix_ug;
122 : };
123 :
124 : struct pai_val {
125 : uint16_t sd_type;
126 : unsigned int num_entries;
127 : struct pai_entry *entry_list;
128 : unsigned int num_def_entries;
129 : struct pai_entry *def_entry_list;
130 : };
131 :
132 : /************************************************************************
133 : Return a uint32_t of the pai_entry principal.
134 : ************************************************************************/
135 :
136 0 : static uint32_t get_pai_entry_val(struct pai_entry *paie)
137 : {
138 0 : switch (paie->owner_type) {
139 0 : case UID_ACE:
140 0 : DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.id ));
141 0 : return (uint32_t)paie->unix_ug.id;
142 0 : case GID_ACE:
143 0 : DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.id ));
144 0 : return (uint32_t)paie->unix_ug.id;
145 0 : case WORLD_ACE:
146 : default:
147 0 : DEBUG(10,("get_pai_entry_val: world ace\n"));
148 0 : return (uint32_t)-1;
149 : }
150 : }
151 :
152 : /************************************************************************
153 : Return a uint32_t of the entry principal.
154 : ************************************************************************/
155 :
156 0 : static uint32_t get_entry_val(canon_ace *ace_entry)
157 : {
158 0 : switch (ace_entry->owner_type) {
159 0 : case UID_ACE:
160 0 : DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
161 0 : return (uint32_t)ace_entry->unix_ug.id;
162 0 : case GID_ACE:
163 0 : DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
164 0 : return (uint32_t)ace_entry->unix_ug.id;
165 0 : case WORLD_ACE:
166 : default:
167 0 : DEBUG(10,("get_entry_val: world ace\n"));
168 0 : return (uint32_t)-1;
169 : }
170 : }
171 :
172 : /************************************************************************
173 : Create the on-disk format (always v2 now). Caller must free.
174 : ************************************************************************/
175 :
176 0 : static char *create_pai_buf_v2(canon_ace *file_ace_list,
177 : canon_ace *dir_ace_list,
178 : uint16_t sd_type,
179 : size_t *store_size)
180 : {
181 0 : char *pai_buf = NULL;
182 0 : canon_ace *ace_list = NULL;
183 0 : char *entry_offset = NULL;
184 0 : unsigned int num_entries = 0;
185 0 : unsigned int num_def_entries = 0;
186 0 : unsigned int i;
187 :
188 0 : for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
189 0 : num_entries++;
190 : }
191 :
192 0 : for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
193 0 : num_def_entries++;
194 : }
195 :
196 0 : DEBUG(10,("create_pai_buf_v2: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
197 :
198 0 : *store_size = PAI_V2_ENTRIES_BASE +
199 0 : ((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH);
200 :
201 0 : pai_buf = talloc_array(talloc_tos(), char, *store_size);
202 0 : if (!pai_buf) {
203 0 : return NULL;
204 : }
205 :
206 : /* Set up the header. */
207 0 : memset(pai_buf, '\0', PAI_V2_ENTRIES_BASE);
208 0 : SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_V2_VERSION);
209 0 : SSVAL(pai_buf,PAI_V2_TYPE_OFFSET, sd_type);
210 0 : SSVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET,num_entries);
211 0 : SSVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
212 :
213 0 : DEBUG(10,("create_pai_buf_v2: sd_type = 0x%x\n",
214 : (unsigned int)sd_type ));
215 :
216 0 : entry_offset = pai_buf + PAI_V2_ENTRIES_BASE;
217 :
218 0 : i = 0;
219 0 : for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
220 0 : uint8_t type_val = (uint8_t)ace_list->owner_type;
221 0 : uint32_t entry_val = get_entry_val(ace_list);
222 :
223 0 : SCVAL(entry_offset,0,ace_list->ace_flags);
224 0 : SCVAL(entry_offset,1,type_val);
225 0 : SIVAL(entry_offset,2,entry_val);
226 0 : DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
227 : i,
228 : (unsigned int)ace_list->ace_flags,
229 : (unsigned int)type_val,
230 : (unsigned int)entry_val ));
231 0 : i++;
232 0 : entry_offset += PAI_V2_ENTRY_LENGTH;
233 : }
234 :
235 0 : for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
236 0 : uint8_t type_val = (uint8_t)ace_list->owner_type;
237 0 : uint32_t entry_val = get_entry_val(ace_list);
238 :
239 0 : SCVAL(entry_offset,0,ace_list->ace_flags);
240 0 : SCVAL(entry_offset,1,type_val);
241 0 : SIVAL(entry_offset,2,entry_val);
242 0 : DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
243 : i,
244 : (unsigned int)ace_list->ace_flags,
245 : (unsigned int)type_val,
246 : (unsigned int)entry_val ));
247 0 : i++;
248 0 : entry_offset += PAI_V2_ENTRY_LENGTH;
249 : }
250 :
251 0 : return pai_buf;
252 : }
253 :
254 : /************************************************************************
255 : Store the user.SAMBA_PAI attribute on disk.
256 : ************************************************************************/
257 :
258 153015 : static void store_inheritance_attributes(files_struct *fsp,
259 : canon_ace *file_ace_list,
260 : canon_ace *dir_ace_list,
261 : uint16_t sd_type)
262 : {
263 412 : int ret;
264 412 : size_t store_size;
265 412 : char *pai_buf;
266 :
267 153015 : if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
268 153015 : return;
269 : }
270 :
271 0 : pai_buf = create_pai_buf_v2(file_ace_list, dir_ace_list,
272 : sd_type, &store_size);
273 :
274 0 : ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
275 : pai_buf, store_size, 0);
276 :
277 0 : TALLOC_FREE(pai_buf);
278 :
279 0 : DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n",
280 : (unsigned int)sd_type,
281 : fsp_str_dbg(fsp)));
282 :
283 0 : if (ret == -1 && !no_acl_syscall_error(errno)) {
284 0 : DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
285 : }
286 : }
287 :
288 : /************************************************************************
289 : Delete the in memory inheritance info.
290 : ************************************************************************/
291 :
292 420626 : static void free_inherited_info(struct pai_val *pal)
293 : {
294 420626 : if (pal) {
295 0 : struct pai_entry *paie, *paie_next;
296 0 : for (paie = pal->entry_list; paie; paie = paie_next) {
297 0 : paie_next = paie->next;
298 0 : TALLOC_FREE(paie);
299 : }
300 0 : for (paie = pal->def_entry_list; paie; paie = paie_next) {
301 0 : paie_next = paie->next;
302 0 : TALLOC_FREE(paie);
303 : }
304 0 : TALLOC_FREE(pal);
305 : }
306 420626 : }
307 :
308 : /************************************************************************
309 : Get any stored ACE flags.
310 : ************************************************************************/
311 :
312 1094197 : static uint16_t get_pai_flags(struct pai_val *pal, canon_ace *ace_entry, bool default_ace)
313 : {
314 3885 : struct pai_entry *paie;
315 :
316 1094197 : if (!pal) {
317 1090312 : return 0;
318 : }
319 :
320 : /* If the entry exists it is inherited. */
321 0 : for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
322 0 : if (ace_entry->owner_type == paie->owner_type &&
323 0 : get_entry_val(ace_entry) == get_pai_entry_val(paie))
324 0 : return paie->ace_flags;
325 : }
326 0 : return 0;
327 : }
328 :
329 : /************************************************************************
330 : Ensure an attribute just read is valid - v1.
331 : ************************************************************************/
332 :
333 0 : static bool check_pai_ok_v1(const char *pai_buf, size_t pai_buf_data_size)
334 : {
335 0 : uint16_t num_entries;
336 0 : uint16_t num_def_entries;
337 :
338 0 : if (pai_buf_data_size < PAI_V1_ENTRIES_BASE) {
339 : /* Corrupted - too small. */
340 0 : return false;
341 : }
342 :
343 0 : if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_V1_VERSION) {
344 0 : return false;
345 : }
346 :
347 0 : num_entries = SVAL(pai_buf,PAI_V1_NUM_ENTRIES_OFFSET);
348 0 : num_def_entries = SVAL(pai_buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
349 :
350 : /* Check the entry lists match. */
351 : /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
352 :
353 0 : if (((num_entries + num_def_entries)*PAI_V1_ENTRY_LENGTH) +
354 : PAI_V1_ENTRIES_BASE != pai_buf_data_size) {
355 0 : return false;
356 : }
357 :
358 0 : return true;
359 : }
360 :
361 : /************************************************************************
362 : Ensure an attribute just read is valid - v2.
363 : ************************************************************************/
364 :
365 0 : static bool check_pai_ok_v2(const char *pai_buf, size_t pai_buf_data_size)
366 : {
367 0 : uint16_t num_entries;
368 0 : uint16_t num_def_entries;
369 :
370 0 : if (pai_buf_data_size < PAI_V2_ENTRIES_BASE) {
371 : /* Corrupted - too small. */
372 0 : return false;
373 : }
374 :
375 0 : if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_V2_VERSION) {
376 0 : return false;
377 : }
378 :
379 0 : num_entries = SVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET);
380 0 : num_def_entries = SVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET);
381 :
382 : /* Check the entry lists match. */
383 : /* Each entry is 6 bytes (flags + type + 4 bytes of uid or gid). */
384 :
385 0 : if (((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH) +
386 : PAI_V2_ENTRIES_BASE != pai_buf_data_size) {
387 0 : return false;
388 : }
389 :
390 0 : return true;
391 : }
392 :
393 : /************************************************************************
394 : Decode the owner.
395 : ************************************************************************/
396 :
397 0 : static bool get_pai_owner_type(struct pai_entry *paie, const char *entry_offset)
398 : {
399 0 : paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
400 0 : switch( paie->owner_type) {
401 0 : case UID_ACE:
402 0 : paie->unix_ug.type = ID_TYPE_UID;
403 0 : paie->unix_ug.id = (uid_t)IVAL(entry_offset,1);
404 0 : DEBUG(10,("get_pai_owner_type: uid = %u\n",
405 : (unsigned int)paie->unix_ug.id ));
406 0 : break;
407 0 : case GID_ACE:
408 0 : paie->unix_ug.type = ID_TYPE_GID;
409 0 : paie->unix_ug.id = (gid_t)IVAL(entry_offset,1);
410 0 : DEBUG(10,("get_pai_owner_type: gid = %u\n",
411 : (unsigned int)paie->unix_ug.id ));
412 0 : break;
413 0 : case WORLD_ACE:
414 0 : paie->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
415 0 : paie->unix_ug.id = -1;
416 0 : DEBUG(10,("get_pai_owner_type: world ace\n"));
417 0 : break;
418 0 : default:
419 0 : DEBUG(10,("get_pai_owner_type: unknown type %u\n",
420 : (unsigned int)paie->owner_type ));
421 0 : return false;
422 : }
423 0 : return true;
424 : }
425 :
426 : /************************************************************************
427 : Process v2 entries.
428 : ************************************************************************/
429 :
430 0 : static const char *create_pai_v1_entries(struct pai_val *paiv,
431 : const char *entry_offset,
432 : bool def_entry)
433 : {
434 0 : unsigned int i;
435 :
436 0 : for (i = 0; i < paiv->num_entries; i++) {
437 0 : struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
438 0 : if (!paie) {
439 0 : return NULL;
440 : }
441 :
442 0 : paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
443 0 : if (!get_pai_owner_type(paie, entry_offset)) {
444 0 : TALLOC_FREE(paie);
445 0 : return NULL;
446 : }
447 :
448 0 : if (!def_entry) {
449 0 : DLIST_ADD(paiv->entry_list, paie);
450 : } else {
451 0 : DLIST_ADD(paiv->def_entry_list, paie);
452 : }
453 0 : entry_offset += PAI_V1_ENTRY_LENGTH;
454 : }
455 0 : return entry_offset;
456 : }
457 :
458 : /************************************************************************
459 : Convert to in-memory format from version 1.
460 : ************************************************************************/
461 :
462 0 : static struct pai_val *create_pai_val_v1(const char *buf, size_t size)
463 : {
464 0 : const char *entry_offset;
465 0 : struct pai_val *paiv = NULL;
466 :
467 0 : if (!check_pai_ok_v1(buf, size)) {
468 0 : return NULL;
469 : }
470 :
471 0 : paiv = talloc(talloc_tos(), struct pai_val);
472 0 : if (!paiv) {
473 0 : return NULL;
474 : }
475 :
476 0 : memset(paiv, '\0', sizeof(struct pai_val));
477 :
478 0 : paiv->sd_type = (CVAL(buf,PAI_V1_FLAG_OFFSET) == PAI_V1_ACL_FLAG_PROTECTED) ?
479 : SEC_DESC_DACL_PROTECTED : 0;
480 :
481 0 : paiv->num_entries = SVAL(buf,PAI_V1_NUM_ENTRIES_OFFSET);
482 0 : paiv->num_def_entries = SVAL(buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
483 :
484 0 : entry_offset = buf + PAI_V1_ENTRIES_BASE;
485 :
486 0 : DEBUG(10,("create_pai_val: num_entries = %u, num_def_entries = %u\n",
487 : paiv->num_entries, paiv->num_def_entries ));
488 :
489 0 : entry_offset = create_pai_v1_entries(paiv, entry_offset, false);
490 0 : if (entry_offset == NULL) {
491 0 : free_inherited_info(paiv);
492 0 : return NULL;
493 : }
494 0 : entry_offset = create_pai_v1_entries(paiv, entry_offset, true);
495 0 : if (entry_offset == NULL) {
496 0 : free_inherited_info(paiv);
497 0 : return NULL;
498 : }
499 :
500 0 : return paiv;
501 : }
502 :
503 : /************************************************************************
504 : Process v2 entries.
505 : ************************************************************************/
506 :
507 0 : static const char *create_pai_v2_entries(struct pai_val *paiv,
508 : unsigned int num_entries,
509 : const char *entry_offset,
510 : bool def_entry)
511 : {
512 0 : unsigned int i;
513 :
514 0 : for (i = 0; i < num_entries; i++) {
515 0 : struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
516 0 : if (!paie) {
517 0 : return NULL;
518 : }
519 :
520 0 : paie->ace_flags = CVAL(entry_offset,0);
521 :
522 0 : if (!get_pai_owner_type(paie, entry_offset+1)) {
523 0 : TALLOC_FREE(paie);
524 0 : return NULL;
525 : }
526 0 : if (!def_entry) {
527 0 : DLIST_ADD(paiv->entry_list, paie);
528 : } else {
529 0 : DLIST_ADD(paiv->def_entry_list, paie);
530 : }
531 0 : entry_offset += PAI_V2_ENTRY_LENGTH;
532 : }
533 0 : return entry_offset;
534 : }
535 :
536 : /************************************************************************
537 : Convert to in-memory format from version 2.
538 : ************************************************************************/
539 :
540 0 : static struct pai_val *create_pai_val_v2(const char *buf, size_t size)
541 : {
542 0 : const char *entry_offset;
543 0 : struct pai_val *paiv = NULL;
544 :
545 0 : if (!check_pai_ok_v2(buf, size)) {
546 0 : return NULL;
547 : }
548 :
549 0 : paiv = talloc(talloc_tos(), struct pai_val);
550 0 : if (!paiv) {
551 0 : return NULL;
552 : }
553 :
554 0 : memset(paiv, '\0', sizeof(struct pai_val));
555 :
556 0 : paiv->sd_type = SVAL(buf,PAI_V2_TYPE_OFFSET);
557 :
558 0 : paiv->num_entries = SVAL(buf,PAI_V2_NUM_ENTRIES_OFFSET);
559 0 : paiv->num_def_entries = SVAL(buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET);
560 :
561 0 : entry_offset = buf + PAI_V2_ENTRIES_BASE;
562 :
563 0 : DEBUG(10,("create_pai_val_v2: sd_type = 0x%x num_entries = %u, num_def_entries = %u\n",
564 : (unsigned int)paiv->sd_type,
565 : paiv->num_entries, paiv->num_def_entries ));
566 :
567 0 : entry_offset = create_pai_v2_entries(paiv, paiv->num_entries,
568 : entry_offset, false);
569 0 : if (entry_offset == NULL) {
570 0 : free_inherited_info(paiv);
571 0 : return NULL;
572 : }
573 0 : entry_offset = create_pai_v2_entries(paiv, paiv->num_def_entries,
574 : entry_offset, true);
575 0 : if (entry_offset == NULL) {
576 0 : free_inherited_info(paiv);
577 0 : return NULL;
578 : }
579 :
580 0 : return paiv;
581 : }
582 :
583 : /************************************************************************
584 : Convert to in-memory format - from either version 1 or 2.
585 : ************************************************************************/
586 :
587 0 : static struct pai_val *create_pai_val(const char *buf, size_t size)
588 : {
589 0 : if (size < 1) {
590 0 : return NULL;
591 : }
592 0 : if (CVAL(buf,PAI_VERSION_OFFSET) == PAI_V1_VERSION) {
593 0 : return create_pai_val_v1(buf, size);
594 0 : } else if (CVAL(buf,PAI_VERSION_OFFSET) == PAI_V2_VERSION) {
595 0 : return create_pai_val_v2(buf, size);
596 : } else {
597 0 : return NULL;
598 : }
599 : }
600 :
601 : /************************************************************************
602 : Load the user.SAMBA_PAI attribute.
603 : ************************************************************************/
604 :
605 420626 : static struct pai_val *fload_inherited_info(files_struct *fsp)
606 : {
607 1655 : char *pai_buf;
608 420626 : size_t pai_buf_size = 1024;
609 420626 : struct pai_val *paiv = NULL;
610 1655 : ssize_t ret;
611 :
612 420626 : if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
613 418971 : return NULL;
614 : }
615 :
616 0 : if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL) {
617 0 : return NULL;
618 : }
619 :
620 0 : do {
621 0 : ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
622 : pai_buf, pai_buf_size);
623 0 : if (ret == -1) {
624 0 : if (errno != ERANGE) {
625 0 : break;
626 : }
627 : /* Buffer too small - enlarge it. */
628 0 : pai_buf_size *= 2;
629 0 : TALLOC_FREE(pai_buf);
630 0 : if (pai_buf_size > 1024*1024) {
631 0 : return NULL; /* Limit malloc to 1mb. */
632 : }
633 0 : if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL)
634 0 : return NULL;
635 : }
636 0 : } while (ret == -1);
637 :
638 0 : DEBUG(10,("load_inherited_info: ret = %lu for file %s\n",
639 : (unsigned long)ret, fsp_str_dbg(fsp)));
640 :
641 0 : if (ret == -1) {
642 : /* No attribute or not supported. */
643 : #if defined(ENOATTR)
644 0 : if (errno != ENOATTR)
645 0 : DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
646 : #else
647 : if (errno != ENOSYS)
648 : DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
649 : #endif
650 0 : TALLOC_FREE(pai_buf);
651 0 : return NULL;
652 : }
653 :
654 0 : paiv = create_pai_val(pai_buf, ret);
655 :
656 0 : if (paiv) {
657 0 : DEBUG(10,("load_inherited_info: ACL type is 0x%x for file %s\n",
658 : (unsigned int)paiv->sd_type, fsp_str_dbg(fsp)));
659 : }
660 :
661 0 : TALLOC_FREE(pai_buf);
662 0 : return paiv;
663 : }
664 :
665 : /****************************************************************************
666 : Functions to manipulate the internal ACE format.
667 : ****************************************************************************/
668 :
669 : /****************************************************************************
670 : Count a linked list of canonical ACE entries.
671 : ****************************************************************************/
672 :
673 1413238 : static size_t count_canon_ace_list( canon_ace *l_head )
674 : {
675 1413238 : size_t count = 0;
676 3722 : canon_ace *ace;
677 :
678 5189096 : for (ace = l_head; ace; ace = ace->next)
679 3777006 : count++;
680 :
681 1413238 : return count;
682 : }
683 :
684 : /****************************************************************************
685 : Free a linked list of canonical ACE entries.
686 : ****************************************************************************/
687 :
688 1147334 : static void free_canon_ace_list( canon_ace *l_head )
689 : {
690 4134 : canon_ace *list, *next;
691 :
692 3653113 : for (list = l_head; list; list = next) {
693 2505779 : next = list->next;
694 2505779 : DLIST_REMOVE(l_head, list);
695 2505779 : TALLOC_FREE(list);
696 : }
697 1147334 : }
698 :
699 : /****************************************************************************
700 : Function to duplicate a canon_ace entry.
701 : ****************************************************************************/
702 :
703 20406 : static canon_ace *dup_canon_ace( canon_ace *src_ace)
704 : {
705 20406 : canon_ace *dst_ace = talloc(talloc_tos(), canon_ace);
706 :
707 20406 : if (dst_ace == NULL)
708 0 : return NULL;
709 :
710 20406 : *dst_ace = *src_ace;
711 20406 : dst_ace->prev = dst_ace->next = NULL;
712 20406 : return dst_ace;
713 : }
714 :
715 : /****************************************************************************
716 : Print out a canon ace.
717 : ****************************************************************************/
718 :
719 0 : static void print_canon_ace(canon_ace *pace, int num)
720 : {
721 0 : struct dom_sid_buf buf;
722 0 : dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
723 0 : dbgtext( "SID = %s ", dom_sid_str_buf(&pace->trustee, &buf));
724 0 : if (pace->owner_type == UID_ACE) {
725 0 : dbgtext( "uid %u ", (unsigned int)pace->unix_ug.id);
726 0 : } else if (pace->owner_type == GID_ACE) {
727 0 : dbgtext( "gid %u ", (unsigned int)pace->unix_ug.id);
728 : } else
729 0 : dbgtext( "other ");
730 0 : switch (pace->type) {
731 0 : case SMB_ACL_USER:
732 0 : dbgtext( "SMB_ACL_USER ");
733 0 : break;
734 0 : case SMB_ACL_USER_OBJ:
735 0 : dbgtext( "SMB_ACL_USER_OBJ ");
736 0 : break;
737 0 : case SMB_ACL_GROUP:
738 0 : dbgtext( "SMB_ACL_GROUP ");
739 0 : break;
740 0 : case SMB_ACL_GROUP_OBJ:
741 0 : dbgtext( "SMB_ACL_GROUP_OBJ ");
742 0 : break;
743 0 : case SMB_ACL_OTHER:
744 0 : dbgtext( "SMB_ACL_OTHER ");
745 0 : break;
746 0 : default:
747 0 : dbgtext( "MASK " );
748 0 : break;
749 : }
750 :
751 0 : dbgtext( "ace_flags = 0x%x ", (unsigned int)pace->ace_flags);
752 0 : dbgtext( "perms ");
753 0 : dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
754 0 : dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
755 0 : dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
756 0 : }
757 :
758 : /****************************************************************************
759 : Print out a canon ace list.
760 : ****************************************************************************/
761 :
762 1656843 : static void print_canon_ace_list(const char *name, canon_ace *ace_list)
763 : {
764 1656843 : int count = 0;
765 :
766 1656843 : if( DEBUGLVL( 10 )) {
767 0 : dbgtext( "print_canon_ace_list: %s\n", name );
768 0 : for (;ace_list; ace_list = ace_list->next, count++)
769 0 : print_canon_ace(ace_list, count );
770 : }
771 1656843 : }
772 :
773 : /****************************************************************************
774 : Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
775 : ****************************************************************************/
776 :
777 1263517 : static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
778 : {
779 1263517 : mode_t ret = 0;
780 :
781 1263517 : ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
782 1263517 : ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
783 1263517 : ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
784 :
785 1263517 : return ret;
786 : }
787 :
788 : /****************************************************************************
789 : Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
790 : ****************************************************************************/
791 :
792 573897 : mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
793 : {
794 573897 : mode_t ret = 0;
795 :
796 573897 : if (mode & r_mask)
797 572620 : ret |= S_IRUSR;
798 573897 : if (mode & w_mask)
799 273961 : ret |= S_IWUSR;
800 573897 : if (mode & x_mask)
801 560109 : ret |= S_IXUSR;
802 :
803 573897 : return ret;
804 : }
805 :
806 : /****************************************************************************
807 : Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
808 : an SMB_ACL_PERMSET_T.
809 : ****************************************************************************/
810 :
811 1004438 : int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
812 : {
813 1004438 : if (sys_acl_clear_perms(*p_permset) == -1)
814 0 : return -1;
815 1004438 : if (mode & S_IRUSR) {
816 984857 : if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
817 0 : return -1;
818 : }
819 1004438 : if (mode & S_IWUSR) {
820 504931 : if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
821 0 : return -1;
822 : }
823 1004438 : if (mode & S_IXUSR) {
824 979409 : if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
825 0 : return -1;
826 : }
827 1000406 : return 0;
828 : }
829 :
830 : /****************************************************************************
831 : Function to create owner and group SIDs from a SMB_STRUCT_STAT.
832 : ****************************************************************************/
833 :
834 578318 : static void create_file_sids(const SMB_STRUCT_STAT *psbuf,
835 : struct dom_sid *powner_sid,
836 : struct dom_sid *pgroup_sid)
837 : {
838 578318 : uid_to_sid( powner_sid, psbuf->st_ex_uid );
839 578318 : gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
840 576211 : }
841 :
842 : /****************************************************************************
843 : Merge aces with a common UID or GID - if both are allow or deny, OR the permissions together and
844 : delete the second one. If the first is deny, mask the permissions off and delete the allow
845 : if the permissions become zero, delete the deny if the permissions are non zero.
846 : ****************************************************************************/
847 :
848 306030 : static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
849 : {
850 306030 : canon_ace *l_head = *pp_list_head;
851 824 : canon_ace *curr_ace_outer;
852 824 : canon_ace *curr_ace_outer_next;
853 :
854 : /*
855 : * First, merge allow entries with identical SIDs, and deny entries
856 : * with identical SIDs.
857 : */
858 :
859 863025 : for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
860 2534 : canon_ace *curr_ace;
861 2534 : canon_ace *curr_ace_next;
862 :
863 556995 : curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
864 :
865 1286241 : for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
866 729246 : bool can_merge = false;
867 :
868 729246 : curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
869 :
870 : /* For file ACLs we can merge if the SIDs and ALLOW/DENY
871 : * types are the same. For directory acls we must also
872 : * ensure the POSIX ACL types are the same.
873 : *
874 : * For the IDMAP_BOTH case, we must not merge
875 : * the UID and GID ACE values for same SID
876 : */
877 :
878 729246 : if (!dir_acl) {
879 662182 : can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
880 663704 : curr_ace->owner_type == curr_ace_outer->owner_type &&
881 1522 : (curr_ace->attr == curr_ace_outer->attr));
882 : } else {
883 67064 : can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
884 6584 : curr_ace->owner_type == curr_ace_outer->owner_type &&
885 73789 : (curr_ace->type == curr_ace_outer->type) &&
886 346 : (curr_ace->attr == curr_ace_outer->attr));
887 : }
888 :
889 729246 : if (can_merge) {
890 1860 : if( DEBUGLVL( 10 )) {
891 0 : dbgtext("merge_aces: Merging ACE's\n");
892 0 : print_canon_ace( curr_ace_outer, 0);
893 0 : print_canon_ace( curr_ace, 0);
894 : }
895 :
896 : /* Merge two allow or two deny ACE's. */
897 :
898 : /* Theoretically we shouldn't merge a dir ACE if
899 : * one ACE has the CI flag set, and the other
900 : * ACE has the OI flag set, but this is rare
901 : * enough we can ignore it. */
902 :
903 1860 : curr_ace_outer->perms |= curr_ace->perms;
904 1860 : curr_ace_outer->ace_flags |= curr_ace->ace_flags;
905 1860 : DLIST_REMOVE(l_head, curr_ace);
906 1860 : TALLOC_FREE(curr_ace);
907 1860 : curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
908 : }
909 : }
910 : }
911 :
912 : /*
913 : * Now go through and mask off allow permissions with deny permissions.
914 : * We can delete either the allow or deny here as we know that each SID
915 : * appears only once in the list.
916 : */
917 :
918 863025 : for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
919 2534 : canon_ace *curr_ace;
920 2534 : canon_ace *curr_ace_next;
921 :
922 556995 : curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
923 :
924 1283245 : for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
925 :
926 726258 : curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
927 :
928 : /*
929 : * Subtract ACE's with different entries. Due to the ordering constraints
930 : * we've put on the ACL, we know the deny must be the first one.
931 : */
932 :
933 726258 : if (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
934 70928 : (curr_ace->owner_type == curr_ace_outer->owner_type) &&
935 976 : (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
936 :
937 8 : if( DEBUGLVL( 10 )) {
938 0 : dbgtext("merge_aces: Masking ACE's\n");
939 0 : print_canon_ace( curr_ace_outer, 0);
940 0 : print_canon_ace( curr_ace, 0);
941 : }
942 :
943 8 : curr_ace->perms &= ~curr_ace_outer->perms;
944 :
945 8 : if (curr_ace->perms == 0) {
946 :
947 : /*
948 : * The deny overrides the allow. Remove the allow.
949 : */
950 :
951 0 : DLIST_REMOVE(l_head, curr_ace);
952 0 : TALLOC_FREE(curr_ace);
953 0 : curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
954 :
955 : } else {
956 :
957 : /*
958 : * Even after removing permissions, there
959 : * are still allow permissions - delete the deny.
960 : * It is safe to delete the deny here,
961 : * as we are guaranteed by the deny first
962 : * ordering that all the deny entries for
963 : * this SID have already been merged into one
964 : * before we can get to an allow ace.
965 : */
966 :
967 8 : DLIST_REMOVE(l_head, curr_ace_outer);
968 8 : TALLOC_FREE(curr_ace_outer);
969 8 : break;
970 : }
971 : }
972 :
973 : } /* end for curr_ace */
974 : } /* end for curr_ace_outer */
975 :
976 : /* We may have modified the list. */
977 :
978 306030 : *pp_list_head = l_head;
979 306030 : }
980 :
981 : /****************************************************************************
982 : Map canon_ace perms to permission bits NT.
983 : The attr element is not used here - we only process deny entries on set,
984 : not get. Deny entries are implicit on get with ace->perms = 0.
985 : ****************************************************************************/
986 :
987 1818397 : uint32_t map_canon_ace_perms(int snum,
988 : enum security_ace_type *pacl_type,
989 : mode_t perms,
990 : bool directory_ace)
991 : {
992 1818397 : uint32_t nt_mask = 0;
993 :
994 1818397 : *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
995 :
996 1818397 : if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
997 743516 : if (directory_ace) {
998 229463 : nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
999 : } else {
1000 510254 : nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS);
1001 : }
1002 1074881 : } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
1003 : /*
1004 : * Windows NT refuses to display ACEs with no permissions in them (but
1005 : * they are perfectly legal with Windows 2000). If the ACE has empty
1006 : * permissions we cannot use 0, so we use the otherwise unused
1007 : * WRITE_OWNER permission, which we ignore when we set an ACL.
1008 : * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
1009 : * to be changed in the future.
1010 : */
1011 :
1012 26287 : nt_mask = 0;
1013 : } else {
1014 1048374 : if (directory_ace) {
1015 140737 : nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
1016 140737 : nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
1017 140737 : nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
1018 : } else {
1019 907637 : nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
1020 907637 : nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
1021 907661 : nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
1022 : }
1023 : }
1024 :
1025 1818397 : if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
1026 771782 : nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
1027 : }
1028 :
1029 1818397 : DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
1030 : (unsigned int)perms, (unsigned int)nt_mask ));
1031 :
1032 1818397 : return nt_mask;
1033 : }
1034 :
1035 : /****************************************************************************
1036 : Map NT perms to a UNIX mode_t.
1037 : ****************************************************************************/
1038 :
1039 : #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA)
1040 : #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA)
1041 : #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
1042 :
1043 540781 : static mode_t map_nt_perms( uint32_t *mask, int type)
1044 : {
1045 540781 : mode_t mode = 0;
1046 :
1047 540781 : switch(type) {
1048 538745 : case S_IRUSR:
1049 540781 : if((*mask) & GENERIC_ALL_ACCESS)
1050 0 : mode = S_IRUSR|S_IWUSR|S_IXUSR;
1051 : else {
1052 540781 : mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
1053 540781 : mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
1054 540781 : mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
1055 : }
1056 538745 : break;
1057 0 : case S_IRGRP:
1058 0 : if((*mask) & GENERIC_ALL_ACCESS)
1059 0 : mode = S_IRGRP|S_IWGRP|S_IXGRP;
1060 : else {
1061 0 : mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
1062 0 : mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
1063 0 : mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
1064 : }
1065 0 : break;
1066 0 : case S_IROTH:
1067 0 : if((*mask) & GENERIC_ALL_ACCESS)
1068 0 : mode = S_IROTH|S_IWOTH|S_IXOTH;
1069 : else {
1070 0 : mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
1071 0 : mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
1072 0 : mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
1073 : }
1074 0 : break;
1075 : }
1076 :
1077 540781 : return mode;
1078 : }
1079 :
1080 : /****************************************************************************
1081 : Unpack a struct security_descriptor into a UNIX owner and group.
1082 : ****************************************************************************/
1083 :
1084 162706 : static NTSTATUS unpack_nt_owners(struct connection_struct *conn,
1085 : uid_t *puser, gid_t *pgrp,
1086 : uint32_t security_info_sent,
1087 : const struct security_descriptor *psd)
1088 : {
1089 162706 : *puser = (uid_t)-1;
1090 162706 : *pgrp = (gid_t)-1;
1091 :
1092 162706 : if(security_info_sent == 0) {
1093 8 : DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
1094 8 : return NT_STATUS_OK;
1095 : }
1096 :
1097 : /*
1098 : * Validate the owner and group SID's.
1099 : */
1100 :
1101 162698 : DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
1102 :
1103 : /*
1104 : * Don't immediately fail if the owner sid cannot be validated.
1105 : * This may be a group chown only set.
1106 : */
1107 :
1108 162698 : if (security_info_sent & SECINFO_OWNER) {
1109 153987 : if (!sid_to_uid(psd->owner_sid, puser)) {
1110 582 : if (lp_force_unknown_acl_user(SNUM(conn))) {
1111 : /* this allows take ownership to work
1112 : * reasonably */
1113 582 : *puser = get_current_uid(conn);
1114 : } else {
1115 0 : struct dom_sid_buf buf;
1116 0 : DBG_NOTICE("unable to validate"
1117 : " owner sid for %s\n",
1118 : dom_sid_str_buf(psd->owner_sid,
1119 : &buf));
1120 0 : return NT_STATUS_INVALID_OWNER;
1121 : }
1122 : }
1123 153987 : DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
1124 : (unsigned int)*puser ));
1125 : }
1126 :
1127 : /*
1128 : * Don't immediately fail if the group sid cannot be validated.
1129 : * This may be an owner chown only set.
1130 : */
1131 :
1132 162698 : if (security_info_sent & SECINFO_GROUP) {
1133 151511 : if (!sid_to_gid(psd->group_sid, pgrp)) {
1134 10 : if (lp_force_unknown_acl_user(SNUM(conn))) {
1135 : /* this allows take group ownership to work
1136 : * reasonably */
1137 10 : *pgrp = get_current_gid(conn);
1138 : } else {
1139 0 : DEBUG(3,("unpack_nt_owners: unable to validate"
1140 : " group sid.\n"));
1141 0 : return NT_STATUS_INVALID_OWNER;
1142 : }
1143 : }
1144 151511 : DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
1145 : (unsigned int)*pgrp));
1146 : }
1147 :
1148 162698 : DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
1149 :
1150 162698 : return NT_STATUS_OK;
1151 : }
1152 :
1153 :
1154 556987 : static void trim_ace_perms(canon_ace *pace)
1155 : {
1156 556987 : pace->perms = pace->perms & (S_IXUSR|S_IWUSR|S_IRUSR);
1157 554453 : }
1158 :
1159 164096 : static void ensure_minimal_owner_ace_perms(const bool is_directory,
1160 : canon_ace *pace)
1161 : {
1162 164096 : pace->perms |= S_IRUSR;
1163 164096 : if (is_directory) {
1164 22483 : pace->perms |= (S_IWUSR|S_IXUSR);
1165 : }
1166 163561 : }
1167 :
1168 : /****************************************************************************
1169 : Check if a given uid/SID is in a group gid/SID. This is probably very
1170 : expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1171 : ****************************************************************************/
1172 :
1173 8893 : static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, canon_ace *group_ace )
1174 : {
1175 8893 : bool is_sid = false;
1176 8893 : bool has_sid = false;
1177 8893 : struct security_token *security_token = NULL;
1178 :
1179 : /* "Everyone" always matches every uid. */
1180 :
1181 8893 : if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
1182 0 : return True;
1183 :
1184 8893 : security_token = conn->session_info->security_token;
1185 : /* security_token should not be NULL */
1186 8893 : SMB_ASSERT(security_token);
1187 9383 : is_sid = security_token_is_sid(security_token,
1188 8893 : &uid_ace->trustee);
1189 8893 : if (is_sid) {
1190 6298 : has_sid = security_token_has_sid(security_token,
1191 5858 : &group_ace->trustee);
1192 :
1193 6298 : if (has_sid) {
1194 2964 : return true;
1195 : }
1196 : }
1197 :
1198 : /*
1199 : * if it's the current user, we already have the unix token
1200 : * and don't need to do the complex user_in_group_sid() call
1201 : */
1202 5709 : if (uid_ace->unix_ug.id == get_current_uid(conn)) {
1203 686 : const struct security_unix_token *curr_utok = NULL;
1204 162 : size_t i;
1205 :
1206 686 : if (group_ace->unix_ug.id == get_current_gid(conn)) {
1207 0 : return True;
1208 : }
1209 :
1210 686 : curr_utok = get_current_utok(conn);
1211 865 : for (i=0; i < curr_utok->ngroups; i++) {
1212 17 : if (group_ace->unix_ug.id == curr_utok->groups[i]) {
1213 0 : return True;
1214 : }
1215 : }
1216 : }
1217 :
1218 : /*
1219 : * user_in_group_sid() uses create_token_from_sid()
1220 : * which creates an artificial NT token given just a username,
1221 : * so this is not reliable for users from foreign domains
1222 : * exported by winbindd!
1223 : */
1224 5709 : return user_sid_in_group_sid(&uid_ace->trustee, &group_ace->trustee);
1225 : }
1226 :
1227 : /****************************************************************************
1228 : A well formed POSIX file or default ACL has at least 3 entries, a
1229 : SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1230 : In addition, the owner must always have at least read access.
1231 : When using this call on get_acl, the pst struct is valid and contains
1232 : the mode of the file.
1233 : ****************************************************************************/
1234 :
1235 432723 : static bool ensure_canon_entry_valid_on_get(connection_struct *conn,
1236 : canon_ace **pp_ace,
1237 : const struct dom_sid *pfile_owner_sid,
1238 : const struct dom_sid *pfile_grp_sid,
1239 : const SMB_STRUCT_STAT *pst)
1240 : {
1241 1791 : canon_ace *pace;
1242 432723 : bool got_user = false;
1243 432723 : bool got_group = false;
1244 432723 : bool got_other = false;
1245 :
1246 1526920 : for (pace = *pp_ace; pace; pace = pace->next) {
1247 1094197 : if (pace->type == SMB_ACL_USER_OBJ) {
1248 241742 : got_user = true;
1249 851888 : } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1250 241742 : got_group = true;
1251 609579 : } else if (pace->type == SMB_ACL_OTHER) {
1252 242309 : got_other = true;
1253 : }
1254 : }
1255 :
1256 432723 : if (!got_user) {
1257 190414 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1258 0 : DEBUG(0,("malloc fail.\n"));
1259 0 : return false;
1260 : }
1261 :
1262 190414 : ZERO_STRUCTP(pace);
1263 190414 : pace->type = SMB_ACL_USER_OBJ;
1264 190414 : pace->owner_type = UID_ACE;
1265 190414 : pace->unix_ug.type = ID_TYPE_UID;
1266 190414 : pace->unix_ug.id = pst->st_ex_uid;
1267 190414 : pace->trustee = *pfile_owner_sid;
1268 190414 : pace->attr = ALLOW_ACE;
1269 190414 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1270 190414 : DLIST_ADD(*pp_ace, pace);
1271 : }
1272 :
1273 432723 : if (!got_group) {
1274 190414 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1275 0 : DEBUG(0,("malloc fail.\n"));
1276 0 : return false;
1277 : }
1278 :
1279 190414 : ZERO_STRUCTP(pace);
1280 190414 : pace->type = SMB_ACL_GROUP_OBJ;
1281 190414 : pace->owner_type = GID_ACE;
1282 190414 : pace->unix_ug.type = ID_TYPE_GID;
1283 190414 : pace->unix_ug.id = pst->st_ex_gid;
1284 190414 : pace->trustee = *pfile_grp_sid;
1285 190414 : pace->attr = ALLOW_ACE;
1286 190414 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1287 190414 : DLIST_ADD(*pp_ace, pace);
1288 : }
1289 :
1290 432723 : if (!got_other) {
1291 190414 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1292 0 : DEBUG(0,("malloc fail.\n"));
1293 0 : return false;
1294 : }
1295 :
1296 190414 : ZERO_STRUCTP(pace);
1297 190414 : pace->type = SMB_ACL_OTHER;
1298 190414 : pace->owner_type = WORLD_ACE;
1299 190414 : pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1300 190414 : pace->unix_ug.id = -1;
1301 190414 : pace->trustee = global_sid_World;
1302 190414 : pace->attr = ALLOW_ACE;
1303 190414 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
1304 190414 : DLIST_ADD(*pp_ace, pace);
1305 : }
1306 :
1307 430932 : return true;
1308 : }
1309 :
1310 : /****************************************************************************
1311 : A well formed POSIX file or default ACL has at least 3 entries, a
1312 : SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1313 : In addition, the owner must always have at least read access.
1314 : When using this call on set_acl, the pst struct has
1315 : been modified to have a mode containing the default for this file or directory
1316 : type.
1317 : ****************************************************************************/
1318 :
1319 164096 : static bool ensure_canon_entry_valid_on_set(connection_struct *conn,
1320 : canon_ace **pp_ace,
1321 : bool is_default_acl,
1322 : const struct share_params *params,
1323 : const bool is_directory,
1324 : const struct dom_sid *pfile_owner_sid,
1325 : const struct dom_sid *pfile_grp_sid,
1326 : const SMB_STRUCT_STAT *pst)
1327 : {
1328 535 : canon_ace *pace;
1329 164096 : canon_ace *pace_user = NULL;
1330 164096 : canon_ace *pace_group = NULL;
1331 164096 : canon_ace *pace_other = NULL;
1332 164096 : bool got_duplicate_user = false;
1333 164096 : bool got_duplicate_group = false;
1334 :
1335 721083 : for (pace = *pp_ace; pace; pace = pace->next) {
1336 556987 : trim_ace_perms(pace);
1337 556987 : if (pace->type == SMB_ACL_USER_OBJ) {
1338 163720 : ensure_minimal_owner_ace_perms(is_directory, pace);
1339 161050 : pace_user = pace;
1340 395522 : } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1341 156447 : pace_group = pace;
1342 238595 : } else if (pace->type == SMB_ACL_OTHER) {
1343 157479 : pace_other = pace;
1344 : }
1345 : }
1346 :
1347 164096 : if (!pace_user) {
1348 120 : canon_ace *pace_iter;
1349 :
1350 2631 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1351 0 : DEBUG(0,("talloc fail.\n"));
1352 0 : return false;
1353 : }
1354 :
1355 2631 : ZERO_STRUCTP(pace);
1356 2631 : pace->type = SMB_ACL_USER_OBJ;
1357 2631 : pace->owner_type = UID_ACE;
1358 2631 : pace->unix_ug.type = ID_TYPE_UID;
1359 2631 : pace->unix_ug.id = pst->st_ex_uid;
1360 2631 : pace->trustee = *pfile_owner_sid;
1361 2631 : pace->attr = ALLOW_ACE;
1362 : /* Start with existing user permissions, principle of least
1363 : surprises for the user. */
1364 2631 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1365 :
1366 : /* See if the owning user is in any of the other groups in
1367 : the ACE, or if there's a matching user entry (by uid
1368 : or in the case of ID_TYPE_BOTH by SID).
1369 : If so, OR in the permissions from that entry. */
1370 :
1371 :
1372 20827 : for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1373 18196 : if (pace_iter->type == SMB_ACL_USER &&
1374 8746 : pace_iter->unix_ug.id == pace->unix_ug.id) {
1375 423 : pace->perms |= pace_iter->perms;
1376 17773 : } else if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1377 9206 : if (dom_sid_equal(&pace->trustee, &pace_iter->trustee)) {
1378 321 : pace->perms |= pace_iter->perms;
1379 8885 : } else if (uid_entry_in_group(conn, pace, pace_iter)) {
1380 3580 : pace->perms |= pace_iter->perms;
1381 : }
1382 : }
1383 : }
1384 :
1385 2631 : if (pace->perms == 0) {
1386 : /* If we only got an "everyone" perm, just use that. */
1387 0 : if (pace_other)
1388 0 : pace->perms = pace_other->perms;
1389 : }
1390 :
1391 : /*
1392 : * Ensure we have default parameters for the
1393 : * user (owner) even on default ACLs.
1394 : */
1395 2631 : ensure_minimal_owner_ace_perms(is_directory, pace);
1396 :
1397 2631 : DLIST_ADD(*pp_ace, pace);
1398 2511 : pace_user = pace;
1399 : }
1400 :
1401 164096 : if (!pace_group) {
1402 7169 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1403 0 : DEBUG(0,("talloc fail.\n"));
1404 0 : return false;
1405 : }
1406 :
1407 7169 : ZERO_STRUCTP(pace);
1408 7169 : pace->type = SMB_ACL_GROUP_OBJ;
1409 7169 : pace->owner_type = GID_ACE;
1410 7169 : pace->unix_ug.type = ID_TYPE_GID;
1411 7169 : pace->unix_ug.id = pst->st_ex_gid;
1412 7169 : pace->trustee = *pfile_grp_sid;
1413 7169 : pace->attr = ALLOW_ACE;
1414 :
1415 : /* If we only got an "everyone" perm, just use that. */
1416 7169 : if (pace_other) {
1417 1582 : pace->perms = pace_other->perms;
1418 : } else {
1419 5587 : pace->perms = 0;
1420 : }
1421 :
1422 7169 : DLIST_ADD(*pp_ace, pace);
1423 7114 : pace_group = pace;
1424 : }
1425 :
1426 164096 : if (!pace_other) {
1427 6617 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1428 0 : DEBUG(0,("talloc fail.\n"));
1429 0 : return false;
1430 : }
1431 :
1432 6617 : ZERO_STRUCTP(pace);
1433 6617 : pace->type = SMB_ACL_OTHER;
1434 6617 : pace->owner_type = WORLD_ACE;
1435 6617 : pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1436 6617 : pace->unix_ug.id = -1;
1437 6617 : pace->trustee = global_sid_World;
1438 6617 : pace->attr = ALLOW_ACE;
1439 6617 : pace->perms = 0;
1440 :
1441 6617 : DLIST_ADD(*pp_ace, pace);
1442 7032 : pace_other = pace;
1443 : }
1444 :
1445 : /* Ensure when setting a POSIX ACL, that the uid for a
1446 : SMB_ACL_USER_OBJ ACE (the owner ACE entry) has a duplicate
1447 : permission entry as an SMB_ACL_USER, and a gid for a
1448 : SMB_ACL_GROUP_OBJ ACE (the primary group ACE entry) also has
1449 : a duplicate permission entry as an SMB_ACL_GROUP. If not,
1450 : then if the ownership or group ownership of this file or
1451 : directory gets changed, the user or group can lose their
1452 : access. */
1453 :
1454 737500 : for (pace = *pp_ace; pace; pace = pace->next) {
1455 573404 : if (pace->type == SMB_ACL_USER &&
1456 11281 : pace->unix_ug.id == pace_user->unix_ug.id) {
1457 : /* Already got one. */
1458 1391 : got_duplicate_user = true;
1459 572013 : } else if (pace->type == SMB_ACL_GROUP &&
1460 69835 : pace->unix_ug.id == pace_group->unix_ug.id) {
1461 : /* Already got one. */
1462 811 : got_duplicate_group = true;
1463 571147 : } else if ((pace->type == SMB_ACL_GROUP)
1464 68969 : && (dom_sid_equal(&pace->trustee, &pace_user->trustee))) {
1465 : /* If the SID owning the file appears
1466 : * in a group entry, then we have
1467 : * enough duplication, they will still
1468 : * have access */
1469 59350 : got_duplicate_user = true;
1470 : }
1471 : }
1472 :
1473 : /* If the SID is equal for the user and group that we need
1474 : to add the duplicate for, add only the group */
1475 164096 : if (!got_duplicate_user && !got_duplicate_group
1476 102810 : && dom_sid_equal(&pace_group->trustee,
1477 102810 : &pace_user->trustee)) {
1478 : /* Add a duplicate SMB_ACL_GROUP entry, this
1479 : * will cover the owning SID as well, as it
1480 : * will always be mapped to both a uid and
1481 : * gid. */
1482 :
1483 0 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1484 0 : DEBUG(0,("talloc fail.\n"));
1485 0 : return false;
1486 : }
1487 :
1488 0 : ZERO_STRUCTP(pace);
1489 0 : pace->type = SMB_ACL_GROUP;;
1490 0 : pace->owner_type = GID_ACE;
1491 0 : pace->unix_ug.type = ID_TYPE_GID;
1492 0 : pace->unix_ug.id = pace_group->unix_ug.id;
1493 0 : pace->trustee = pace_group->trustee;
1494 0 : pace->attr = pace_group->attr;
1495 0 : pace->perms = pace_group->perms;
1496 :
1497 0 : DLIST_ADD(*pp_ace, pace);
1498 :
1499 : /* We're done here, make sure the
1500 : statements below are not executed. */
1501 0 : got_duplicate_user = true;
1502 0 : got_duplicate_group = true;
1503 : }
1504 :
1505 164096 : if (!got_duplicate_user) {
1506 : /* Add a duplicate SMB_ACL_USER entry. */
1507 103676 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1508 0 : DEBUG(0,("talloc fail.\n"));
1509 0 : return false;
1510 : }
1511 :
1512 103676 : ZERO_STRUCTP(pace);
1513 103676 : pace->type = SMB_ACL_USER;;
1514 103676 : pace->owner_type = UID_ACE;
1515 103676 : pace->unix_ug.type = ID_TYPE_UID;
1516 103676 : pace->unix_ug.id = pace_user->unix_ug.id;
1517 103676 : pace->trustee = pace_user->trustee;
1518 103676 : pace->attr = pace_user->attr;
1519 103676 : pace->perms = pace_user->perms;
1520 :
1521 103676 : DLIST_ADD(*pp_ace, pace);
1522 :
1523 104023 : got_duplicate_user = true;
1524 : }
1525 :
1526 164096 : if (!got_duplicate_group) {
1527 : /* Add a duplicate SMB_ACL_GROUP entry. */
1528 163230 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1529 0 : DEBUG(0,("talloc fail.\n"));
1530 0 : return false;
1531 : }
1532 :
1533 163230 : ZERO_STRUCTP(pace);
1534 163230 : pace->type = SMB_ACL_GROUP;;
1535 163230 : pace->owner_type = GID_ACE;
1536 163230 : pace->unix_ug.type = ID_TYPE_GID;
1537 163230 : pace->unix_ug.id = pace_group->unix_ug.id;
1538 163230 : pace->trustee = pace_group->trustee;
1539 163230 : pace->attr = pace_group->attr;
1540 163230 : pace->perms = pace_group->perms;
1541 :
1542 163230 : DLIST_ADD(*pp_ace, pace);
1543 :
1544 163285 : got_duplicate_group = true;
1545 : }
1546 :
1547 163561 : return true;
1548 : }
1549 :
1550 : /****************************************************************************
1551 : Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1552 : If it does not have them, check if there are any entries where the trustee is the
1553 : file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1554 : Note we must not do this to default directory ACLs.
1555 : ****************************************************************************/
1556 :
1557 153015 : static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
1558 : {
1559 412 : bool got_user_obj, got_group_obj;
1560 412 : canon_ace *current_ace;
1561 412 : int i, entries;
1562 :
1563 153015 : entries = count_canon_ace_list(ace);
1564 153015 : got_user_obj = False;
1565 153015 : got_group_obj = False;
1566 :
1567 671882 : for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1568 518867 : if (current_ace->type == SMB_ACL_USER_OBJ)
1569 151784 : got_user_obj = True;
1570 366736 : else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1571 147219 : got_group_obj = True;
1572 : }
1573 153015 : if (got_user_obj && got_group_obj) {
1574 146149 : DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1575 146149 : return;
1576 : }
1577 :
1578 28548 : for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1579 25764 : if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1580 4082 : dom_sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
1581 0 : current_ace->type = SMB_ACL_USER_OBJ;
1582 0 : got_user_obj = True;
1583 : }
1584 26596 : if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1585 4914 : dom_sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
1586 0 : current_ace->type = SMB_ACL_GROUP_OBJ;
1587 0 : got_group_obj = True;
1588 : }
1589 : }
1590 6866 : if (!got_user_obj)
1591 1318 : DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1592 6866 : if (!got_group_obj)
1593 5796 : DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1594 : }
1595 :
1596 540781 : static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
1597 : canon_ace **file_ace, canon_ace **dir_ace,
1598 : bool *got_file_allow, bool *got_dir_allow,
1599 : bool *all_aces_are_inherit_only,
1600 : canon_ace *current_ace)
1601 : {
1602 :
1603 : /*
1604 : * Map the given NT permissions into a UNIX mode_t containing only
1605 : * S_I(R|W|X)USR bits.
1606 : */
1607 :
1608 540781 : current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
1609 540781 : current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1610 :
1611 : /* Store the ace_flag. */
1612 540781 : current_ace->ace_flags = psa->flags;
1613 :
1614 : /*
1615 : * Now add the created ace to either the file list, the directory
1616 : * list, or both. We *MUST* preserve the order here (hence we use
1617 : * DLIST_ADD_END) as NT ACLs are order dependent.
1618 : */
1619 :
1620 540781 : if (fsp->fsp_flags.is_directory) {
1621 :
1622 : /*
1623 : * We can only add to the default POSIX ACE list if the ACE is
1624 : * designed to be inherited by both files and directories.
1625 : */
1626 :
1627 63692 : if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1628 : (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1629 :
1630 39988 : canon_ace *current_dir_ace = current_ace;
1631 39988 : DLIST_ADD_END(*dir_ace, current_ace);
1632 :
1633 : /*
1634 : * Note if this was an allow ace. We can't process
1635 : * any further deny ace's after this.
1636 : */
1637 :
1638 39988 : if (current_ace->attr == ALLOW_ACE)
1639 39988 : *got_dir_allow = True;
1640 :
1641 39988 : if ((current_ace->attr == DENY_ACE) && *got_dir_allow) {
1642 0 : DEBUG(0,("add_current_ace_to_acl: "
1643 : "malformed ACL in "
1644 : "inheritable ACL! Deny entry "
1645 : "after Allow entry. Failing "
1646 : "to set on file %s.\n",
1647 : fsp_str_dbg(fsp)));
1648 0 : return False;
1649 : }
1650 :
1651 39988 : if( DEBUGLVL( 10 )) {
1652 0 : dbgtext("add_current_ace_to_acl: adding dir ACL:\n");
1653 0 : print_canon_ace( current_ace, 0);
1654 : }
1655 :
1656 : /*
1657 : * If this is not an inherit only ACE we need to add a duplicate
1658 : * to the file acl.
1659 : */
1660 :
1661 39988 : if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1662 20406 : canon_ace *dup_ace = dup_canon_ace(current_ace);
1663 :
1664 20406 : if (!dup_ace) {
1665 0 : DEBUG(0,("add_current_ace_to_acl: malloc fail !\n"));
1666 0 : return False;
1667 : }
1668 :
1669 : /*
1670 : * We must not free current_ace here as its
1671 : * pointer is now owned by the dir_ace list.
1672 : */
1673 20406 : current_ace = dup_ace;
1674 : /* We've essentially split this ace into two,
1675 : * and added the ace with inheritance request
1676 : * bits to the directory ACL. Drop those bits for
1677 : * the ACE we're adding to the file list. */
1678 20406 : current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
1679 : SEC_ACE_FLAG_CONTAINER_INHERIT|
1680 : SEC_ACE_FLAG_INHERIT_ONLY);
1681 : } else {
1682 : /*
1683 : * We must not free current_ace here as its
1684 : * pointer is now owned by the dir_ace list.
1685 : */
1686 19446 : current_ace = NULL;
1687 : }
1688 :
1689 : /*
1690 : * current_ace is now either owned by file_ace
1691 : * or is NULL. We can safely operate on current_dir_ace
1692 : * to treat mapping for default acl entries differently
1693 : * than access acl entries.
1694 : */
1695 :
1696 39988 : if (current_dir_ace->owner_type == UID_ACE) {
1697 : /*
1698 : * We already decided above this is a uid,
1699 : * for default acls ace's only CREATOR_OWNER
1700 : * maps to ACL_USER_OBJ. All other uid
1701 : * ace's are ACL_USER.
1702 : */
1703 15492 : if (dom_sid_equal(¤t_dir_ace->trustee,
1704 : &global_sid_Creator_Owner)) {
1705 9768 : current_dir_ace->type = SMB_ACL_USER_OBJ;
1706 : } else {
1707 5724 : current_dir_ace->type = SMB_ACL_USER;
1708 : }
1709 : }
1710 :
1711 39988 : if (current_dir_ace->owner_type == GID_ACE) {
1712 : /*
1713 : * We already decided above this is a gid,
1714 : * for default acls ace's only CREATOR_GROUP
1715 : * maps to ACL_GROUP_OBJ. All other uid
1716 : * ace's are ACL_GROUP.
1717 : */
1718 14520 : if (dom_sid_equal(¤t_dir_ace->trustee,
1719 : &global_sid_Creator_Group)) {
1720 9708 : current_dir_ace->type = SMB_ACL_GROUP_OBJ;
1721 : } else {
1722 4812 : current_dir_ace->type = SMB_ACL_GROUP;
1723 : }
1724 : }
1725 : }
1726 : }
1727 :
1728 : /*
1729 : * Only add to the file ACL if not inherit only.
1730 : */
1731 :
1732 540781 : if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1733 518897 : DLIST_ADD_END(*file_ace, current_ace);
1734 :
1735 : /*
1736 : * Note if this was an allow ace. We can't process
1737 : * any further deny ace's after this.
1738 : */
1739 :
1740 518897 : if (current_ace->attr == ALLOW_ACE)
1741 518869 : *got_file_allow = True;
1742 :
1743 518897 : if ((current_ace->attr == DENY_ACE) && *got_file_allow) {
1744 10 : DEBUG(0,("add_current_ace_to_acl: malformed "
1745 : "ACL in file ACL ! Deny entry after "
1746 : "Allow entry. Failing to set on file "
1747 : "%s.\n", fsp_str_dbg(fsp)));
1748 10 : return False;
1749 : }
1750 :
1751 518887 : if( DEBUGLVL( 10 )) {
1752 0 : dbgtext("add_current_ace_to_acl: adding file ACL:\n");
1753 0 : print_canon_ace( current_ace, 0);
1754 : }
1755 518887 : *all_aces_are_inherit_only = False;
1756 : /*
1757 : * We must not free current_ace here as its
1758 : * pointer is now owned by the file_ace list.
1759 : */
1760 518887 : current_ace = NULL;
1761 : }
1762 :
1763 : /*
1764 : * Free if ACE was not added.
1765 : */
1766 :
1767 540771 : TALLOC_FREE(current_ace);
1768 538735 : return true;
1769 : }
1770 :
1771 : /****************************************************************************
1772 : Unpack a struct security_descriptor into two canonical ace lists.
1773 : ****************************************************************************/
1774 :
1775 155598 : static bool create_canon_ace_lists(files_struct *fsp,
1776 : const SMB_STRUCT_STAT *pst,
1777 : struct dom_sid *pfile_owner_sid,
1778 : struct dom_sid *pfile_grp_sid,
1779 : canon_ace **ppfile_ace,
1780 : canon_ace **ppdir_ace,
1781 : const struct security_acl *dacl)
1782 : {
1783 155598 : bool all_aces_are_inherit_only = (fsp->fsp_flags.is_directory);
1784 155598 : canon_ace *file_ace = NULL;
1785 155598 : canon_ace *dir_ace = NULL;
1786 155598 : canon_ace *current_ace = NULL;
1787 155598 : bool got_dir_allow = False;
1788 155598 : bool got_file_allow = False;
1789 452 : uint32_t i, j;
1790 :
1791 155598 : *ppfile_ace = NULL;
1792 155598 : *ppdir_ace = NULL;
1793 :
1794 : /*
1795 : * Convert the incoming ACL into a more regular form.
1796 : */
1797 :
1798 646567 : for(i = 0; i < dacl->num_aces; i++) {
1799 493497 : struct security_ace *psa = &dacl->aces[i];
1800 :
1801 493497 : if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1802 2528 : DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1803 2528 : return False;
1804 : }
1805 : }
1806 :
1807 : /*
1808 : * Deal with the fact that NT 4.x re-writes the canonical format
1809 : * that we return for default ACLs. If a directory ACE is identical
1810 : * to a inherited directory ACE then NT changes the bits so that the
1811 : * first ACE is set to OI|IO and the second ACE for this SID is set
1812 : * to CI. We need to repair this. JRA.
1813 : */
1814 :
1815 629429 : for(i = 0; i < dacl->num_aces; i++) {
1816 476359 : struct security_ace *psa1 = &dacl->aces[i];
1817 :
1818 1022012 : for (j = i + 1; j < dacl->num_aces; j++) {
1819 545653 : struct security_ace *psa2 = &dacl->aces[j];
1820 :
1821 545653 : if (psa1->access_mask != psa2->access_mask)
1822 354562 : continue;
1823 :
1824 191091 : if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
1825 187579 : continue;
1826 :
1827 : /*
1828 : * Ok - permission bits and SIDs are equal.
1829 : * Check if flags were re-written.
1830 : */
1831 :
1832 3512 : if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1833 :
1834 1198 : psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1835 1198 : psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1836 :
1837 2314 : } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1838 :
1839 4 : psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1840 4 : psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1841 :
1842 : }
1843 : }
1844 : }
1845 :
1846 629411 : for(i = 0; i < dacl->num_aces; i++) {
1847 476351 : struct security_ace *psa = &dacl->aces[i];
1848 :
1849 : /*
1850 : * Create a canon_ace entry representing this NT DACL ACE.
1851 : */
1852 :
1853 476351 : if ((current_ace = talloc(talloc_tos(), canon_ace)) == NULL) {
1854 0 : free_canon_ace_list(file_ace);
1855 0 : free_canon_ace_list(dir_ace);
1856 0 : DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1857 0 : return False;
1858 : }
1859 :
1860 476351 : ZERO_STRUCTP(current_ace);
1861 :
1862 476351 : sid_copy(¤t_ace->trustee, &psa->trustee);
1863 :
1864 : /*
1865 : * Try and work out if the SID is a user or group
1866 : * as we need to flag these differently for POSIX.
1867 : * Note what kind of a POSIX ACL this should map to.
1868 : */
1869 :
1870 476351 : if( dom_sid_equal(¤t_ace->trustee, &global_sid_World)) {
1871 148899 : current_ace->owner_type = WORLD_ACE;
1872 148899 : current_ace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1873 148899 : current_ace->unix_ug.id = -1;
1874 148899 : current_ace->type = SMB_ACL_OTHER;
1875 327452 : } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
1876 10994 : current_ace->owner_type = UID_ACE;
1877 10994 : current_ace->unix_ug.type = ID_TYPE_UID;
1878 10994 : current_ace->unix_ug.id = pst->st_ex_uid;
1879 10994 : current_ace->type = SMB_ACL_USER_OBJ;
1880 :
1881 : /*
1882 : * The Creator Owner entry only specifies inheritable permissions,
1883 : * never access permissions. WinNT doesn't always set the ACE to
1884 : * INHERIT_ONLY, though.
1885 : */
1886 :
1887 10994 : psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1888 :
1889 316458 : } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
1890 10748 : current_ace->owner_type = GID_ACE;
1891 10748 : current_ace->unix_ug.type = ID_TYPE_GID;
1892 10748 : current_ace->unix_ug.id = pst->st_ex_gid;
1893 10748 : current_ace->type = SMB_ACL_GROUP_OBJ;
1894 :
1895 : /*
1896 : * The Creator Group entry only specifies inheritable permissions,
1897 : * never access permissions. WinNT doesn't always set the ACE to
1898 : * INHERIT_ONLY, though.
1899 : */
1900 10748 : psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1901 :
1902 : } else {
1903 961 : struct unixid unixid;
1904 :
1905 305710 : if (!sids_to_unixids(¤t_ace->trustee, 1, &unixid)) {
1906 0 : struct dom_sid_buf buf;
1907 0 : free_canon_ace_list(file_ace);
1908 0 : free_canon_ace_list(dir_ace);
1909 0 : TALLOC_FREE(current_ace);
1910 0 : DBG_ERR("sids_to_unixids failed for %s "
1911 : "(allocation failure)\n",
1912 : dom_sid_str_buf(¤t_ace->trustee,
1913 : &buf));
1914 0 : return false;
1915 : }
1916 :
1917 305710 : if (unixid.type == ID_TYPE_BOTH) {
1918 : /*
1919 : * We must add both a user and group
1920 : * entry POSIX_ACL.
1921 : * This is due to the fact that in POSIX
1922 : * user entries are more specific than
1923 : * groups.
1924 : */
1925 64682 : current_ace->owner_type = UID_ACE;
1926 64682 : current_ace->unix_ug.type = ID_TYPE_UID;
1927 64682 : current_ace->unix_ug.id = unixid.id;
1928 65274 : current_ace->type =
1929 64682 : (unixid.id == pst->st_ex_uid) ?
1930 64682 : SMB_ACL_USER_OBJ :
1931 : SMB_ACL_USER;
1932 :
1933 : /* Add the user object to the posix ACL,
1934 : and proceed to the group mapping
1935 : below. This handles the talloc_free
1936 : of current_ace if not added for some
1937 : reason */
1938 64682 : if (!add_current_ace_to_acl(fsp,
1939 : psa,
1940 : &file_ace,
1941 : &dir_ace,
1942 : &got_file_allow,
1943 : &got_dir_allow,
1944 : &all_aces_are_inherit_only,
1945 : current_ace)) {
1946 4 : free_canon_ace_list(file_ace);
1947 4 : free_canon_ace_list(dir_ace);
1948 4 : return false;
1949 : }
1950 :
1951 64678 : if ((current_ace = talloc(talloc_tos(),
1952 : canon_ace)) == NULL) {
1953 0 : free_canon_ace_list(file_ace);
1954 0 : free_canon_ace_list(dir_ace);
1955 0 : DEBUG(0,("create_canon_ace_lists: "
1956 : "malloc fail.\n"));
1957 0 : return False;
1958 : }
1959 :
1960 64678 : ZERO_STRUCTP(current_ace);
1961 :
1962 64678 : sid_copy(¤t_ace->trustee, &psa->trustee);
1963 :
1964 64678 : current_ace->unix_ug.type = ID_TYPE_GID;
1965 64678 : current_ace->unix_ug.id = unixid.id;
1966 64678 : current_ace->owner_type = GID_ACE;
1967 : /* If it's the primary group, this is a
1968 : group_obj, not a group. */
1969 64678 : if (current_ace->unix_ug.id == pst->st_ex_gid) {
1970 1167 : current_ace->type = SMB_ACL_GROUP_OBJ;
1971 : } else {
1972 63511 : current_ace->type = SMB_ACL_GROUP;
1973 : }
1974 :
1975 241028 : } else if (unixid.type == ID_TYPE_UID) {
1976 93150 : current_ace->owner_type = UID_ACE;
1977 93150 : current_ace->unix_ug.type = ID_TYPE_UID;
1978 93150 : current_ace->unix_ug.id = unixid.id;
1979 : /* If it's the owning user, this is a user_obj,
1980 : not a user. */
1981 93150 : if (current_ace->unix_ug.id == pst->st_ex_uid) {
1982 93124 : current_ace->type = SMB_ACL_USER_OBJ;
1983 : } else {
1984 26 : current_ace->type = SMB_ACL_USER;
1985 : }
1986 147878 : } else if (unixid.type == ID_TYPE_GID) {
1987 147630 : current_ace->unix_ug.type = ID_TYPE_GID;
1988 147630 : current_ace->unix_ug.id = unixid.id;
1989 147630 : current_ace->owner_type = GID_ACE;
1990 : /* If it's the primary group, this is a
1991 : group_obj, not a group. */
1992 147630 : if (current_ace->unix_ug.id == pst->st_ex_gid) {
1993 146052 : current_ace->type = SMB_ACL_GROUP_OBJ;
1994 : } else {
1995 1578 : current_ace->type = SMB_ACL_GROUP;
1996 : }
1997 : } else {
1998 0 : struct dom_sid_buf buf;
1999 : /*
2000 : * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
2001 : */
2002 :
2003 248 : if (non_mappable_sid(&psa->trustee)) {
2004 8 : DBG_DEBUG("ignoring "
2005 : "non-mappable SID %s\n",
2006 : dom_sid_str_buf(
2007 : &psa->trustee,
2008 : &buf));
2009 8 : TALLOC_FREE(current_ace);
2010 248 : continue;
2011 : }
2012 :
2013 240 : if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
2014 240 : DBG_DEBUG("ignoring unknown or "
2015 : "foreign SID %s\n",
2016 : dom_sid_str_buf(
2017 : &psa->trustee,
2018 : &buf));
2019 240 : TALLOC_FREE(current_ace);
2020 240 : continue;
2021 : }
2022 :
2023 0 : free_canon_ace_list(file_ace);
2024 0 : free_canon_ace_list(dir_ace);
2025 0 : DBG_ERR("unable to map SID %s to uid or "
2026 : "gid.\n",
2027 : dom_sid_str_buf(¤t_ace->trustee,
2028 : &buf));
2029 0 : TALLOC_FREE(current_ace);
2030 0 : return false;
2031 : }
2032 : }
2033 :
2034 : /* handles the talloc_free of current_ace if not added for some reason */
2035 476099 : if (!add_current_ace_to_acl(fsp, psa, &file_ace, &dir_ace,
2036 : &got_file_allow, &got_dir_allow,
2037 : &all_aces_are_inherit_only, current_ace)) {
2038 6 : free_canon_ace_list(file_ace);
2039 6 : free_canon_ace_list(dir_ace);
2040 6 : return false;
2041 : }
2042 : }
2043 :
2044 153060 : if (fsp->fsp_flags.is_directory && all_aces_are_inherit_only) {
2045 : /*
2046 : * Windows 2000 is doing one of these weird 'inherit acl'
2047 : * traverses to conserve NTFS ACL resources. Just pretend
2048 : * there was no DACL sent. JRA.
2049 : */
2050 :
2051 16 : DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
2052 16 : free_canon_ace_list(file_ace);
2053 16 : free_canon_ace_list(dir_ace);
2054 16 : file_ace = NULL;
2055 16 : dir_ace = NULL;
2056 : } else {
2057 : /*
2058 : * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in
2059 : * the file ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
2060 : * entries can be converted to *_OBJ. Don't do this for the default
2061 : * ACL, we will create them separately for this if needed inside
2062 : * ensure_canon_entry_valid_on_set().
2063 : */
2064 153044 : if (file_ace) {
2065 153015 : check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
2066 : }
2067 : }
2068 :
2069 153060 : *ppfile_ace = file_ace;
2070 153060 : *ppdir_ace = dir_ace;
2071 :
2072 153060 : return True;
2073 : }
2074 :
2075 : /****************************************************************************
2076 : ASCII art time again... JRA :-).
2077 :
2078 : We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
2079 : we insist the ACL is in canonical form (ie. all DENY entries precede ALLOW
2080 : entries). Secondly, the merge code has ensured that all duplicate SID entries for
2081 : allow or deny have been merged, so the same SID can only appear once in the deny
2082 : list or once in the allow list.
2083 :
2084 : We then process as follows :
2085 :
2086 : ---------------------------------------------------------------------------
2087 : First pass - look for a Everyone DENY entry.
2088 :
2089 : If it is deny all (rwx) trunate the list at this point.
2090 : Else, walk the list from this point and use the deny permissions of this
2091 : entry as a mask on all following allow entries. Finally, delete
2092 : the Everyone DENY entry (we have applied it to everything possible).
2093 :
2094 : In addition, in this pass we remove any DENY entries that have
2095 : no permissions (ie. they are a DENY nothing).
2096 : ---------------------------------------------------------------------------
2097 : Second pass - only deal with deny user entries.
2098 :
2099 : DENY user1 (perms XXX)
2100 :
2101 : new_perms = 0
2102 : for all following allow group entries where user1 is in group
2103 : new_perms |= group_perms;
2104 :
2105 : user1 entry perms = new_perms & ~ XXX;
2106 :
2107 : Convert the deny entry to an allow entry with the new perms and
2108 : push to the end of the list. Note if the user was in no groups
2109 : this maps to a specific allow nothing entry for this user.
2110 :
2111 : The common case from the NT ACL chooser (userX deny all) is
2112 : optimised so we don't do the group lookup - we just map to
2113 : an allow nothing entry.
2114 :
2115 : What we're doing here is inferring the allow permissions the
2116 : person setting the ACE on user1 wanted by looking at the allow
2117 : permissions on the groups the user is currently in. This will
2118 : be a snapshot, depending on group membership but is the best
2119 : we can do and has the advantage of failing closed rather than
2120 : open.
2121 : ---------------------------------------------------------------------------
2122 : Third pass - only deal with deny group entries.
2123 :
2124 : DENY group1 (perms XXX)
2125 :
2126 : for all following allow user entries where user is in group1
2127 : user entry perms = user entry perms & ~ XXX;
2128 :
2129 : If there is a group Everyone allow entry with permissions YYY,
2130 : convert the group1 entry to an allow entry and modify its
2131 : permissions to be :
2132 :
2133 : new_perms = YYY & ~ XXX
2134 :
2135 : and push to the end of the list.
2136 :
2137 : If there is no group Everyone allow entry then convert the
2138 : group1 entry to a allow nothing entry and push to the end of the list.
2139 :
2140 : Note that the common case from the NT ACL chooser (groupX deny all)
2141 : cannot be optimised here as we need to modify user entries who are
2142 : in the group to change them to a deny all also.
2143 :
2144 : What we're doing here is modifying the allow permissions of
2145 : user entries (which are more specific in POSIX ACLs) to mask
2146 : out the explicit deny set on the group they are in. This will
2147 : be a snapshot depending on current group membership but is the
2148 : best we can do and has the advantage of failing closed rather
2149 : than open.
2150 : ---------------------------------------------------------------------------
2151 : Fourth pass - cope with cumulative permissions.
2152 :
2153 : for all allow user entries, if there exists an allow group entry with
2154 : more permissive permissions, and the user is in that group, rewrite the
2155 : allow user permissions to contain both sets of permissions.
2156 :
2157 : Currently the code for this is #ifdef'ed out as these semantics make
2158 : no sense to me. JRA.
2159 : ---------------------------------------------------------------------------
2160 :
2161 : Note we *MUST* do the deny user pass first as this will convert deny user
2162 : entries into allow user entries which can then be processed by the deny
2163 : group pass.
2164 :
2165 : The above algorithm took a *lot* of thinking about - hence this
2166 : explanation :-). JRA.
2167 : ****************************************************************************/
2168 :
2169 : /****************************************************************************
2170 : Process a canon_ace list entries. This is very complex code. We need
2171 : to go through and remove the "deny" permissions from any allow entry that matches
2172 : the id of this entry. We have already refused any NT ACL that wasn't in correct
2173 : order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
2174 : we just remove it (to fail safe). We have already removed any duplicate ace
2175 : entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
2176 : allow entries.
2177 : ****************************************************************************/
2178 :
2179 306030 : static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
2180 : {
2181 306030 : canon_ace *ace_list = *pp_ace_list;
2182 306030 : canon_ace *curr_ace = NULL;
2183 306030 : canon_ace *curr_ace_next = NULL;
2184 :
2185 : /* Pass 1 above - look for an Everyone, deny entry. */
2186 :
2187 863017 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2188 2534 : canon_ace *allow_ace_p;
2189 :
2190 556987 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2191 :
2192 556987 : if (curr_ace->attr != DENY_ACE)
2193 556977 : continue;
2194 :
2195 10 : if (curr_ace->perms == (mode_t)0) {
2196 :
2197 : /* Deny nothing entry - delete. */
2198 :
2199 0 : DLIST_REMOVE(ace_list, curr_ace);
2200 0 : continue;
2201 : }
2202 :
2203 10 : if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
2204 10 : continue;
2205 :
2206 : /* JRATEST - assert. */
2207 0 : SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
2208 :
2209 0 : if (curr_ace->perms == ALL_ACE_PERMS) {
2210 :
2211 : /*
2212 : * Optimisation. This is a DENY_ALL to Everyone. Truncate the
2213 : * list at this point including this entry.
2214 : */
2215 :
2216 0 : canon_ace *prev_entry = DLIST_PREV(curr_ace);
2217 :
2218 0 : free_canon_ace_list( curr_ace );
2219 0 : if (prev_entry)
2220 0 : DLIST_REMOVE(ace_list, prev_entry);
2221 : else {
2222 : /* We deleted the entire list. */
2223 0 : ace_list = NULL;
2224 : }
2225 0 : break;
2226 : }
2227 :
2228 0 : for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2229 :
2230 : /*
2231 : * Only mask off allow entries.
2232 : */
2233 :
2234 0 : if (allow_ace_p->attr != ALLOW_ACE)
2235 0 : continue;
2236 :
2237 0 : allow_ace_p->perms &= ~curr_ace->perms;
2238 : }
2239 :
2240 : /*
2241 : * Now it's been applied, remove it.
2242 : */
2243 :
2244 0 : DLIST_REMOVE(ace_list, curr_ace);
2245 : }
2246 :
2247 : /* Pass 2 above - deal with deny user entries. */
2248 :
2249 863019 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2250 556989 : mode_t new_perms = (mode_t)0;
2251 2534 : canon_ace *allow_ace_p;
2252 :
2253 556989 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2254 :
2255 556989 : if (curr_ace->attr != DENY_ACE)
2256 556979 : continue;
2257 :
2258 10 : if (curr_ace->owner_type != UID_ACE)
2259 4 : continue;
2260 :
2261 6 : if (curr_ace->perms == ALL_ACE_PERMS) {
2262 :
2263 : /*
2264 : * Optimisation - this is a deny everything to this user.
2265 : * Convert to an allow nothing and push to the end of the list.
2266 : */
2267 :
2268 0 : curr_ace->attr = ALLOW_ACE;
2269 0 : curr_ace->perms = (mode_t)0;
2270 0 : DLIST_DEMOTE(ace_list, curr_ace);
2271 0 : continue;
2272 : }
2273 :
2274 12 : for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2275 :
2276 6 : if (allow_ace_p->attr != ALLOW_ACE)
2277 2 : continue;
2278 :
2279 : /* We process GID_ACE and WORLD_ACE entries only. */
2280 :
2281 4 : if (allow_ace_p->owner_type == UID_ACE)
2282 2 : continue;
2283 :
2284 2 : if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
2285 0 : new_perms |= allow_ace_p->perms;
2286 : }
2287 :
2288 : /*
2289 : * Convert to a allow entry, modify the perms and push to the end
2290 : * of the list.
2291 : */
2292 :
2293 6 : curr_ace->attr = ALLOW_ACE;
2294 6 : curr_ace->perms = (new_perms & ~curr_ace->perms);
2295 6 : DLIST_DEMOTE(ace_list, curr_ace);
2296 : }
2297 :
2298 : /* Pass 3 above - deal with deny group entries. */
2299 :
2300 863021 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2301 2534 : canon_ace *allow_ace_p;
2302 556991 : canon_ace *allow_everyone_p = NULL;
2303 :
2304 556991 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2305 :
2306 556991 : if (curr_ace->attr != DENY_ACE)
2307 556987 : continue;
2308 :
2309 4 : if (curr_ace->owner_type != GID_ACE)
2310 0 : continue;
2311 :
2312 12 : for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2313 :
2314 8 : if (allow_ace_p->attr != ALLOW_ACE)
2315 0 : continue;
2316 :
2317 : /* Store a pointer to the Everyone allow, if it exists. */
2318 8 : if (allow_ace_p->owner_type == WORLD_ACE)
2319 0 : allow_everyone_p = allow_ace_p;
2320 :
2321 : /* We process UID_ACE entries only. */
2322 :
2323 8 : if (allow_ace_p->owner_type != UID_ACE)
2324 2 : continue;
2325 :
2326 : /* Mask off the deny group perms. */
2327 :
2328 6 : if (uid_entry_in_group(conn, allow_ace_p, curr_ace))
2329 0 : allow_ace_p->perms &= ~curr_ace->perms;
2330 : }
2331 :
2332 : /*
2333 : * Convert the deny to an allow with the correct perms and
2334 : * push to the end of the list.
2335 : */
2336 :
2337 4 : curr_ace->attr = ALLOW_ACE;
2338 4 : if (allow_everyone_p)
2339 0 : curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
2340 : else
2341 4 : curr_ace->perms = (mode_t)0;
2342 4 : DLIST_DEMOTE(ace_list, curr_ace);
2343 : }
2344 :
2345 : /* Doing this fourth pass allows Windows semantics to be layered
2346 : * on top of POSIX semantics. I'm not sure if this is desirable.
2347 : * For example, in W2K ACLs there is no way to say, "Group X no
2348 : * access, user Y full access" if user Y is a member of group X.
2349 : * This seems completely broken semantics to me.... JRA.
2350 : */
2351 :
2352 : #if 0
2353 : /* Pass 4 above - deal with allow entries. */
2354 :
2355 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2356 : canon_ace *allow_ace_p;
2357 :
2358 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2359 :
2360 : if (curr_ace->attr != ALLOW_ACE)
2361 : continue;
2362 :
2363 : if (curr_ace->owner_type != UID_ACE)
2364 : continue;
2365 :
2366 : for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2367 :
2368 : if (allow_ace_p->attr != ALLOW_ACE)
2369 : continue;
2370 :
2371 : /* We process GID_ACE entries only. */
2372 :
2373 : if (allow_ace_p->owner_type != GID_ACE)
2374 : continue;
2375 :
2376 : /* OR in the group perms. */
2377 :
2378 : if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
2379 : curr_ace->perms |= allow_ace_p->perms;
2380 : }
2381 : }
2382 : #endif
2383 :
2384 306030 : *pp_ace_list = ace_list;
2385 306030 : }
2386 :
2387 : /****************************************************************************
2388 : Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
2389 : succeeding.
2390 : ****************************************************************************/
2391 :
2392 157692 : static bool unpack_canon_ace(files_struct *fsp,
2393 : const SMB_STRUCT_STAT *pst,
2394 : struct dom_sid *pfile_owner_sid,
2395 : struct dom_sid *pfile_grp_sid,
2396 : canon_ace **ppfile_ace,
2397 : canon_ace **ppdir_ace,
2398 : uint32_t security_info_sent,
2399 : const struct security_descriptor *psd)
2400 : {
2401 157692 : canon_ace *file_ace = NULL;
2402 157692 : canon_ace *dir_ace = NULL;
2403 452 : bool ok;
2404 :
2405 157692 : *ppfile_ace = NULL;
2406 157692 : *ppdir_ace = NULL;
2407 :
2408 157692 : if(security_info_sent == 0) {
2409 8 : DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
2410 8 : return False;
2411 : }
2412 :
2413 : /*
2414 : * If no DACL then this is a chown only security descriptor.
2415 : */
2416 :
2417 157684 : if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
2418 2086 : return True;
2419 :
2420 : /*
2421 : * Now go through the DACL and create the canon_ace lists.
2422 : */
2423 :
2424 155598 : if (!create_canon_ace_lists(fsp, pst, pfile_owner_sid, pfile_grp_sid,
2425 155146 : &file_ace, &dir_ace, psd->dacl)) {
2426 2498 : return False;
2427 : }
2428 :
2429 153060 : if ((file_ace == NULL) && (dir_ace == NULL)) {
2430 : /* W2K traverse DACL set - ignore. */
2431 45 : return True;
2432 : }
2433 :
2434 : /*
2435 : * Go through the canon_ace list and merge entries
2436 : * belonging to identical users of identical allow or deny type.
2437 : * We can do this as all deny entries come first, followed by
2438 : * all allow entries (we have mandated this before accepting this acl).
2439 : */
2440 :
2441 153015 : print_canon_ace_list( "file ace - before merge", file_ace);
2442 153015 : merge_aces( &file_ace, false);
2443 :
2444 153015 : print_canon_ace_list( "dir ace - before merge", dir_ace);
2445 153015 : merge_aces( &dir_ace, true);
2446 :
2447 : /*
2448 : * NT ACLs are order dependent. Go through the acl lists and
2449 : * process DENY entries by masking the allow entries.
2450 : */
2451 :
2452 153015 : print_canon_ace_list( "file ace - before deny", file_ace);
2453 153015 : process_deny_list(fsp->conn, &file_ace);
2454 :
2455 153015 : print_canon_ace_list( "dir ace - before deny", dir_ace);
2456 153015 : process_deny_list(fsp->conn, &dir_ace);
2457 :
2458 : /*
2459 : * A well formed POSIX file or default ACL has at least 3 entries, a
2460 : * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
2461 : * and optionally a mask entry. Ensure this is the case.
2462 : */
2463 :
2464 153015 : print_canon_ace_list( "file ace - before valid", file_ace);
2465 :
2466 153427 : ok = ensure_canon_entry_valid_on_set(
2467 152603 : fsp->conn,
2468 : &file_ace,
2469 : false,
2470 153015 : fsp->conn->params,
2471 153015 : fsp->fsp_flags.is_directory,
2472 : pfile_owner_sid,
2473 : pfile_grp_sid,
2474 : pst);
2475 153015 : if (!ok) {
2476 0 : free_canon_ace_list(file_ace);
2477 0 : free_canon_ace_list(dir_ace);
2478 0 : return False;
2479 : }
2480 :
2481 153015 : print_canon_ace_list( "dir ace - before valid", dir_ace);
2482 :
2483 153015 : if (dir_ace != NULL) {
2484 11204 : ok = ensure_canon_entry_valid_on_set(
2485 10958 : fsp->conn,
2486 : &dir_ace,
2487 : true,
2488 11081 : fsp->conn->params,
2489 11081 : fsp->fsp_flags.is_directory,
2490 : pfile_owner_sid,
2491 : pfile_grp_sid,
2492 : pst);
2493 11081 : if (!ok) {
2494 0 : free_canon_ace_list(file_ace);
2495 0 : free_canon_ace_list(dir_ace);
2496 0 : return False;
2497 : }
2498 : }
2499 :
2500 153015 : print_canon_ace_list( "file ace - return", file_ace);
2501 153015 : print_canon_ace_list( "dir ace - return", dir_ace);
2502 :
2503 153015 : *ppfile_ace = file_ace;
2504 153015 : *ppdir_ace = dir_ace;
2505 153015 : return True;
2506 :
2507 : }
2508 :
2509 : /******************************************************************************
2510 : When returning permissions, try and fit NT display
2511 : semantics if possible. Note the the canon_entries here must have been malloced.
2512 : The list format should be - first entry = owner, followed by group and other user
2513 : entries, last entry = other.
2514 :
2515 : Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2516 : are not ordered, and match on the most specific entry rather than walking a list,
2517 : then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2518 :
2519 : Entry 0: owner : deny all except read and write.
2520 : Entry 1: owner : allow read and write.
2521 : Entry 2: group : deny all except read.
2522 : Entry 3: group : allow read.
2523 : Entry 4: Everyone : allow read.
2524 :
2525 : But NT cannot display this in their ACL editor !
2526 : ********************************************************************************/
2527 :
2528 432723 : static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
2529 : {
2530 432723 : canon_ace *l_head = *pp_list_head;
2531 432723 : canon_ace *owner_ace = NULL;
2532 432723 : canon_ace *other_ace = NULL;
2533 432723 : canon_ace *ace = NULL;
2534 :
2535 2098162 : for (ace = l_head; ace; ace = ace->next) {
2536 1665439 : if (ace->type == SMB_ACL_USER_OBJ)
2537 430932 : owner_ace = ace;
2538 1232716 : else if (ace->type == SMB_ACL_OTHER) {
2539 : /* Last ace - this is "other" */
2540 432723 : other_ace = ace;
2541 : }
2542 : }
2543 :
2544 432723 : if (!owner_ace || !other_ace) {
2545 0 : DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2546 : filename ));
2547 0 : return;
2548 : }
2549 :
2550 : /*
2551 : * The POSIX algorithm applies to owner first, and other last,
2552 : * so ensure they are arranged in this order.
2553 : */
2554 :
2555 432723 : if (owner_ace) {
2556 432723 : DLIST_PROMOTE(l_head, owner_ace);
2557 : }
2558 :
2559 432723 : if (other_ace) {
2560 432723 : DLIST_DEMOTE(l_head, other_ace);
2561 : }
2562 :
2563 : /* We have probably changed the head of the list. */
2564 :
2565 432723 : *pp_list_head = l_head;
2566 : }
2567 :
2568 : /****************************************************************************
2569 : Create a linked list of canonical ACE entries.
2570 : ****************************************************************************/
2571 :
2572 432723 : static canon_ace *canonicalise_acl(struct connection_struct *conn,
2573 : const char *fname, SMB_ACL_T posix_acl,
2574 : const SMB_STRUCT_STAT *psbuf,
2575 : const struct dom_sid *powner, const struct dom_sid *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2576 : {
2577 432723 : mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2578 432723 : canon_ace *l_head = NULL;
2579 432723 : canon_ace *ace = NULL;
2580 432723 : canon_ace *next_ace = NULL;
2581 432723 : int entry_id = SMB_ACL_FIRST_ENTRY;
2582 432723 : bool is_default_acl = (the_acl_type == SMB_ACL_TYPE_DEFAULT);
2583 1791 : SMB_ACL_ENTRY_T entry;
2584 1791 : size_t ace_count;
2585 :
2586 1696240 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2587 4452 : SMB_ACL_TAG_T tagtype;
2588 4452 : SMB_ACL_PERMSET_T permset;
2589 4452 : struct dom_sid sid;
2590 4452 : struct unixid unix_ug;
2591 4452 : enum ace_owner owner_type;
2592 :
2593 1263517 : entry_id = SMB_ACL_NEXT_ENTRY;
2594 :
2595 1263517 : if (sys_acl_get_tag_type(entry, &tagtype) == -1)
2596 169320 : continue;
2597 :
2598 1263517 : if (sys_acl_get_permset(entry, &permset) == -1)
2599 0 : continue;
2600 :
2601 : /* Decide which SID to use based on the ACL type. */
2602 1263517 : switch(tagtype) {
2603 242309 : case SMB_ACL_USER_OBJ:
2604 : /* Get the SID from the owner. */
2605 242309 : sid_copy(&sid, powner);
2606 242309 : unix_ug.type = ID_TYPE_UID;
2607 242309 : unix_ug.id = psbuf->st_ex_uid;
2608 242309 : owner_type = UID_ACE;
2609 242309 : break;
2610 123671 : case SMB_ACL_USER:
2611 : {
2612 123671 : uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2613 123671 : if (puid == NULL) {
2614 0 : DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2615 0 : continue;
2616 : }
2617 123671 : uid_to_sid( &sid, *puid);
2618 123671 : unix_ug.type = ID_TYPE_UID;
2619 123671 : unix_ug.id = *puid;
2620 123671 : owner_type = UID_ACE;
2621 123671 : break;
2622 : }
2623 242309 : case SMB_ACL_GROUP_OBJ:
2624 : /* Get the SID from the owning group. */
2625 242309 : sid_copy(&sid, pgroup);
2626 242309 : unix_ug.type = ID_TYPE_GID;
2627 242309 : unix_ug.id = psbuf->st_ex_gid;
2628 242309 : owner_type = GID_ACE;
2629 242309 : break;
2630 243599 : case SMB_ACL_GROUP:
2631 : {
2632 243599 : gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
2633 243599 : if (pgid == NULL) {
2634 0 : DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2635 0 : continue;
2636 : }
2637 243599 : gid_to_sid( &sid, *pgid);
2638 243599 : unix_ug.type = ID_TYPE_GID;
2639 243599 : unix_ug.id = *pgid;
2640 243599 : owner_type = GID_ACE;
2641 243599 : break;
2642 : }
2643 169320 : case SMB_ACL_MASK:
2644 169320 : acl_mask = convert_permset_to_mode_t(permset);
2645 169320 : continue; /* Don't count the mask as an entry. */
2646 242309 : case SMB_ACL_OTHER:
2647 : /* Use the Everyone SID */
2648 242309 : sid = global_sid_World;
2649 242309 : unix_ug.type = ID_TYPE_NOT_SPECIFIED;
2650 242309 : unix_ug.id = -1;
2651 242309 : owner_type = WORLD_ACE;
2652 242309 : break;
2653 0 : default:
2654 0 : DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2655 0 : continue;
2656 : }
2657 :
2658 : /*
2659 : * Add this entry to the list.
2660 : */
2661 :
2662 1094197 : if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
2663 0 : goto fail;
2664 :
2665 2188394 : *ace = (canon_ace) {
2666 : .type = tagtype,
2667 1094197 : .perms = convert_permset_to_mode_t(permset),
2668 : .attr = ALLOW_ACE,
2669 : .trustee = sid,
2670 : .unix_ug = unix_ug,
2671 : .owner_type = owner_type
2672 : };
2673 1094197 : ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
2674 :
2675 1094197 : DLIST_ADD(l_head, ace);
2676 : }
2677 :
2678 : /*
2679 : * This next call will ensure we have at least a user/group/world set.
2680 : */
2681 :
2682 432723 : if (!ensure_canon_entry_valid_on_get(conn, &l_head,
2683 : powner, pgroup,
2684 : psbuf))
2685 0 : goto fail;
2686 :
2687 : /*
2688 : * Now go through the list, masking the permissions with the
2689 : * acl_mask. Ensure all DENY Entries are at the start of the list.
2690 : */
2691 :
2692 432723 : DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", is_default_acl ? "Default" : "Access"));
2693 :
2694 2098162 : for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
2695 1665439 : next_ace = ace->next;
2696 :
2697 : /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2698 1665439 : if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2699 799993 : ace->perms &= acl_mask;
2700 :
2701 1665439 : if (ace->perms == 0) {
2702 26507 : DLIST_PROMOTE(l_head, ace);
2703 : }
2704 :
2705 1665439 : if( DEBUGLVL( 10 ) ) {
2706 0 : print_canon_ace(ace, ace_count);
2707 : }
2708 : }
2709 :
2710 432723 : arrange_posix_perms(fname,&l_head );
2711 :
2712 432723 : print_canon_ace_list( "canonicalise_acl: ace entries after arrange", l_head );
2713 :
2714 432723 : return l_head;
2715 :
2716 0 : fail:
2717 :
2718 0 : free_canon_ace_list(l_head);
2719 0 : return NULL;
2720 : }
2721 :
2722 : /****************************************************************************
2723 : Check if the current user group list contains a given group.
2724 : ****************************************************************************/
2725 :
2726 0 : bool current_user_in_group(connection_struct *conn, gid_t gid)
2727 : {
2728 0 : uint32_t i;
2729 0 : const struct security_unix_token *utok = get_current_utok(conn);
2730 :
2731 0 : for (i = 0; i < utok->ngroups; i++) {
2732 0 : if (utok->groups[i] == gid) {
2733 0 : return True;
2734 : }
2735 : }
2736 :
2737 0 : return False;
2738 : }
2739 :
2740 : /****************************************************************************
2741 : Should we override a deny ? Check 'acl group control' and 'dos filemode'.
2742 : ****************************************************************************/
2743 :
2744 0 : static bool acl_group_override_fsp(files_struct *fsp)
2745 : {
2746 0 : if ((errno != EPERM) && (errno != EACCES)) {
2747 0 : return false;
2748 : }
2749 :
2750 : /* file primary group == user primary or supplementary group */
2751 0 : if (lp_acl_group_control(SNUM(fsp->conn)) &&
2752 0 : current_user_in_group(fsp->conn, fsp->fsp_name->st.st_ex_gid)) {
2753 0 : return true;
2754 : }
2755 :
2756 : /* user has writeable permission */
2757 0 : if (lp_dos_filemode(SNUM(fsp->conn)) && can_write_to_fsp(fsp)) {
2758 0 : return true;
2759 : }
2760 :
2761 0 : return false;
2762 : }
2763 :
2764 : /****************************************************************************
2765 : Attempt to apply an ACL to a file or directory.
2766 : ****************************************************************************/
2767 :
2768 164096 : static bool set_canon_ace_list(files_struct *fsp,
2769 : canon_ace *the_ace,
2770 : bool default_ace,
2771 : const SMB_STRUCT_STAT *psbuf,
2772 : bool *pacl_set_support)
2773 : {
2774 164096 : bool ret = False;
2775 164096 : SMB_ACL_T the_acl = sys_acl_init(talloc_tos());
2776 535 : canon_ace *p_ace;
2777 535 : int i;
2778 535 : SMB_ACL_ENTRY_T mask_entry;
2779 164096 : bool got_mask_entry = False;
2780 535 : SMB_ACL_PERMSET_T mask_permset;
2781 164096 : SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2782 164096 : bool needs_mask = False;
2783 535 : int sret;
2784 :
2785 : /* Use the psbuf that was passed in. */
2786 164096 : if (psbuf != &fsp->fsp_name->st) {
2787 0 : fsp->fsp_name->st = *psbuf;
2788 : }
2789 :
2790 : #if defined(POSIX_ACL_NEEDS_MASK)
2791 : /* HP-UX always wants to have a mask (called "class" there). */
2792 : needs_mask = True;
2793 : #endif
2794 :
2795 164096 : if (the_acl == NULL) {
2796 0 : DEBUG(0, ("sys_acl_init failed to allocate an ACL\n"));
2797 0 : return false;
2798 : }
2799 :
2800 164096 : if( DEBUGLVL( 10 )) {
2801 0 : dbgtext("set_canon_ace_list: setting ACL:\n");
2802 0 : for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2803 0 : print_canon_ace( p_ace, i);
2804 : }
2805 : }
2806 :
2807 1004406 : for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2808 3497 : SMB_ACL_ENTRY_T the_entry;
2809 3497 : SMB_ACL_PERMSET_T the_permset;
2810 :
2811 : /*
2812 : * ACLs only "need" an ACL_MASK entry if there are any named user or
2813 : * named group entries. But if there is an ACL_MASK entry, it applies
2814 : * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2815 : * so that it doesn't deny (i.e., mask off) any permissions.
2816 : */
2817 :
2818 840310 : if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2819 348022 : needs_mask = True;
2820 : }
2821 :
2822 : /*
2823 : * Get the entry for this ACE.
2824 : */
2825 :
2826 840310 : if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
2827 0 : DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2828 : i, strerror(errno) ));
2829 0 : goto fail;
2830 : }
2831 :
2832 840310 : if (p_ace->type == SMB_ACL_MASK) {
2833 0 : mask_entry = the_entry;
2834 0 : got_mask_entry = True;
2835 : }
2836 :
2837 : /*
2838 : * Ok - we now know the ACL calls should be working, don't
2839 : * allow fallback to chmod.
2840 : */
2841 :
2842 840310 : *pacl_set_support = True;
2843 :
2844 : /*
2845 : * Initialise the entry from the canon_ace.
2846 : */
2847 :
2848 : /*
2849 : * First tell the entry what type of ACE this is.
2850 : */
2851 :
2852 840310 : if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
2853 0 : DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2854 : i, strerror(errno) ));
2855 0 : goto fail;
2856 : }
2857 :
2858 : /*
2859 : * Only set the qualifier (user or group id) if the entry is a user
2860 : * or group id ACE.
2861 : */
2862 :
2863 840310 : if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2864 348022 : if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.id) == -1) {
2865 0 : DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2866 : i, strerror(errno) ));
2867 0 : goto fail;
2868 : }
2869 : }
2870 :
2871 : /*
2872 : * Convert the mode_t perms in the canon_ace to a POSIX permset.
2873 : */
2874 :
2875 840310 : if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
2876 0 : DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2877 : i, strerror(errno) ));
2878 0 : goto fail;
2879 : }
2880 :
2881 840310 : if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
2882 0 : DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2883 : (unsigned int)p_ace->perms, i, strerror(errno) ));
2884 0 : goto fail;
2885 : }
2886 :
2887 : /*
2888 : * ..and apply them to the entry.
2889 : */
2890 :
2891 840310 : if (sys_acl_set_permset(the_entry, the_permset) == -1) {
2892 0 : DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2893 : i, strerror(errno) ));
2894 0 : goto fail;
2895 : }
2896 :
2897 840310 : if( DEBUGLVL( 10 ))
2898 0 : print_canon_ace( p_ace, i);
2899 :
2900 : }
2901 :
2902 164096 : if (needs_mask && !got_mask_entry) {
2903 164096 : if (sys_acl_create_entry(&the_acl, &mask_entry) == -1) {
2904 0 : DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2905 0 : goto fail;
2906 : }
2907 :
2908 164096 : if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
2909 0 : DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2910 0 : goto fail;
2911 : }
2912 :
2913 164096 : if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
2914 0 : DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2915 0 : goto fail;
2916 : }
2917 :
2918 164096 : if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2919 0 : DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2920 0 : goto fail;
2921 : }
2922 :
2923 164096 : if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
2924 0 : DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2925 0 : goto fail;
2926 : }
2927 : }
2928 :
2929 : /*
2930 : * Finally apply it to the file or directory.
2931 : */
2932 164096 : sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl_type, the_acl);
2933 164096 : if (sret == -1) {
2934 : /*
2935 : * Some systems allow all the above calls and only fail with no ACL support
2936 : * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2937 : */
2938 0 : if (no_acl_syscall_error(errno)) {
2939 0 : *pacl_set_support = false;
2940 : }
2941 :
2942 0 : if (acl_group_override_fsp(fsp)) {
2943 0 : DBG_DEBUG("acl group control on and current user in "
2944 : "file [%s] primary group.\n",
2945 : fsp_str_dbg(fsp));
2946 :
2947 0 : become_root();
2948 0 : sret = SMB_VFS_SYS_ACL_SET_FD(fsp,
2949 : the_acl_type,
2950 : the_acl);
2951 0 : unbecome_root();
2952 0 : if (sret == 0) {
2953 0 : ret = true;
2954 : }
2955 : }
2956 :
2957 0 : if (ret == false) {
2958 0 : DBG_WARNING("sys_acl_set_file on file [%s]: (%s)\n",
2959 : fsp_str_dbg(fsp), strerror(errno));
2960 0 : goto fail;
2961 : }
2962 : }
2963 :
2964 163561 : ret = True;
2965 :
2966 164096 : fail:
2967 :
2968 164096 : if (the_acl != NULL) {
2969 164096 : TALLOC_FREE(the_acl);
2970 : }
2971 :
2972 163561 : return ret;
2973 : }
2974 :
2975 : /****************************************************************************
2976 :
2977 : ****************************************************************************/
2978 :
2979 90674 : SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2980 : {
2981 1075 : SMB_ACL_ENTRY_T entry;
2982 :
2983 90674 : if (!the_acl)
2984 48188 : return NULL;
2985 41547 : if (sys_acl_get_entry(the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2986 29442 : TALLOC_FREE(the_acl);
2987 29442 : return NULL;
2988 : }
2989 11969 : return the_acl;
2990 : }
2991 :
2992 : /****************************************************************************
2993 : Convert a canon_ace to a generic 3 element permission - if possible.
2994 : ****************************************************************************/
2995 :
2996 : #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2997 :
2998 0 : static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2999 : {
3000 0 : size_t ace_count = count_canon_ace_list(file_ace_list);
3001 0 : canon_ace *ace_p;
3002 0 : canon_ace *owner_ace = NULL;
3003 0 : canon_ace *group_ace = NULL;
3004 0 : canon_ace *other_ace = NULL;
3005 :
3006 0 : if (ace_count > 5) {
3007 0 : DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
3008 : "entries for file %s to convert to posix perms.\n",
3009 : fsp_str_dbg(fsp)));
3010 0 : return False;
3011 : }
3012 :
3013 0 : for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
3014 0 : if (ace_p->owner_type == UID_ACE)
3015 0 : owner_ace = ace_p;
3016 0 : else if (ace_p->owner_type == GID_ACE)
3017 0 : group_ace = ace_p;
3018 0 : else if (ace_p->owner_type == WORLD_ACE)
3019 0 : other_ace = ace_p;
3020 : }
3021 :
3022 0 : if (!owner_ace || !group_ace || !other_ace) {
3023 0 : DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get "
3024 : "standard entries for file %s.\n", fsp_str_dbg(fsp)));
3025 0 : return False;
3026 : }
3027 :
3028 : /*
3029 : * Ensure all ACE entries are owner, group or other.
3030 : * We can't set if there are any other SIDs.
3031 : */
3032 0 : for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
3033 0 : if (ace_p == owner_ace || ace_p == group_ace ||
3034 : ace_p == other_ace) {
3035 0 : continue;
3036 : }
3037 0 : if (ace_p->owner_type == UID_ACE) {
3038 0 : if (ace_p->unix_ug.id != owner_ace->unix_ug.id) {
3039 0 : DEBUG(3,("Invalid uid %u in ACE for file %s.\n",
3040 : (unsigned int)ace_p->unix_ug.id,
3041 : fsp_str_dbg(fsp)));
3042 0 : return false;
3043 : }
3044 0 : } else if (ace_p->owner_type == GID_ACE) {
3045 0 : if (ace_p->unix_ug.id != group_ace->unix_ug.id) {
3046 0 : DEBUG(3,("Invalid gid %u in ACE for file %s.\n",
3047 : (unsigned int)ace_p->unix_ug.id,
3048 : fsp_str_dbg(fsp)));
3049 0 : return false;
3050 : }
3051 : } else {
3052 : /*
3053 : * There should be no duplicate WORLD_ACE entries.
3054 : */
3055 :
3056 0 : DEBUG(3,("Invalid type %u, uid %u in "
3057 : "ACE for file %s.\n",
3058 : (unsigned int)ace_p->owner_type,
3059 : (unsigned int)ace_p->unix_ug.id,
3060 : fsp_str_dbg(fsp)));
3061 0 : return false;
3062 : }
3063 : }
3064 :
3065 0 : *posix_perms = (mode_t)0;
3066 :
3067 0 : *posix_perms |= owner_ace->perms;
3068 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
3069 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
3070 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
3071 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
3072 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
3073 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
3074 :
3075 : /* The owner must have at least read access. */
3076 :
3077 0 : *posix_perms |= S_IRUSR;
3078 0 : if (fsp->fsp_flags.is_directory)
3079 0 : *posix_perms |= (S_IWUSR|S_IXUSR);
3080 :
3081 0 : DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
3082 : "to perm=0%o for file %s.\n", (int)owner_ace->perms,
3083 : (int)group_ace->perms, (int)other_ace->perms,
3084 : (int)*posix_perms, fsp_str_dbg(fsp)));
3085 :
3086 0 : return True;
3087 : }
3088 :
3089 : /****************************************************************************
3090 : Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
3091 : a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
3092 : with CI|OI set so it is inherited and also applies to the directory.
3093 : Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
3094 : ****************************************************************************/
3095 :
3096 420626 : static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_aces)
3097 : {
3098 1655 : size_t i, j;
3099 :
3100 2040641 : for (i = 0; i < num_aces; i++) {
3101 4471412 : for (j = i+1; j < num_aces; j++) {
3102 2853488 : uint32_t i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3103 2853488 : uint32_t j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3104 2853488 : bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3105 2853488 : bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3106 :
3107 : /* We know the lower number ACE's are file entries. */
3108 2853488 : if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
3109 2839084 : (nt_ace_list[i].size == nt_ace_list[j].size) &&
3110 1263466 : (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
3111 767059 : dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
3112 373295 : (i_inh == j_inh) &&
3113 366682 : (i_flags_ni == 0) &&
3114 : (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
3115 : SEC_ACE_FLAG_CONTAINER_INHERIT|
3116 : SEC_ACE_FLAG_INHERIT_ONLY))) {
3117 : /*
3118 : * W2K wants to have access allowed zero access ACE's
3119 : * at the end of the list. If the mask is zero, merge
3120 : * the non-inherited ACE onto the inherited ACE.
3121 : */
3122 :
3123 47515 : if (nt_ace_list[i].access_mask == 0) {
3124 2091 : nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3125 : (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3126 2091 : ARRAY_DEL_ELEMENT(nt_ace_list, i, num_aces);
3127 :
3128 2091 : DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
3129 : (unsigned int)i, (unsigned int)j ));
3130 :
3131 : /*
3132 : * If we remove the i'th element, we
3133 : * should decrement i so that we don't
3134 : * skip over the succeeding element.
3135 : */
3136 2091 : i--;
3137 2091 : num_aces--;
3138 2091 : break;
3139 : } else {
3140 : /*
3141 : * These are identical except for the flags.
3142 : * Merge the inherited ACE onto the non-inherited ACE.
3143 : */
3144 :
3145 45424 : nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3146 : (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3147 45424 : ARRAY_DEL_ELEMENT(nt_ace_list, j, num_aces);
3148 :
3149 45424 : DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
3150 : (unsigned int)j, (unsigned int)i ));
3151 :
3152 : /*
3153 : * If we remove the j'th element, we
3154 : * should decrement j and continue
3155 : * around the loop, so as not to skip
3156 : * subsequent elements.
3157 : */
3158 45424 : j--;
3159 45424 : num_aces--;
3160 : }
3161 : }
3162 : }
3163 : }
3164 :
3165 420626 : return num_aces;
3166 : }
3167 :
3168 :
3169 : /****************************************************************************
3170 : Reply to query a security descriptor from an fsp. If it succeeds it allocates
3171 : the space for the return elements and returns the size needed to return the
3172 : security descriptor. This should be the only external function needed for
3173 : the UNIX style get ACL.
3174 : ****************************************************************************/
3175 :
3176 420626 : static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
3177 : const char *name,
3178 : const SMB_STRUCT_STAT *sbuf,
3179 : struct pai_val *pal,
3180 : SMB_ACL_T posix_acl,
3181 : SMB_ACL_T def_acl,
3182 : uint32_t security_info,
3183 : TALLOC_CTX *mem_ctx,
3184 : struct security_descriptor **ppdesc)
3185 : {
3186 1655 : struct dom_sid owner_sid;
3187 1655 : struct dom_sid group_sid;
3188 420626 : size_t sd_size = 0;
3189 420626 : struct security_acl *psa = NULL;
3190 420626 : size_t num_acls = 0;
3191 420626 : size_t num_def_acls = 0;
3192 420626 : size_t num_aces = 0;
3193 420626 : canon_ace *file_ace = NULL;
3194 420626 : canon_ace *dir_ace = NULL;
3195 420626 : struct security_ace *nt_ace_list = NULL;
3196 420626 : struct security_descriptor *psd = NULL;
3197 :
3198 : /*
3199 : * Get the owner, group and world SIDs.
3200 : */
3201 :
3202 420626 : create_file_sids(sbuf, &owner_sid, &group_sid);
3203 :
3204 420626 : if (security_info & SECINFO_DACL) {
3205 :
3206 : /*
3207 : * In the optimum case Creator Owner and Creator Group would be used for
3208 : * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
3209 : * would lead to usability problems under Windows: The Creator entries
3210 : * are only available in browse lists of directories and not for files;
3211 : * additionally the identity of the owning group couldn't be determined.
3212 : * We therefore use those identities only for Default ACLs.
3213 : */
3214 :
3215 : /* Create the canon_ace lists. */
3216 420626 : file_ace = canonicalise_acl(conn, name, posix_acl, sbuf,
3217 : &owner_sid, &group_sid, pal,
3218 : SMB_ACL_TYPE_ACCESS);
3219 :
3220 : /* We must have *some* ACLS. */
3221 :
3222 422281 : if (count_canon_ace_list(file_ace) == 0) {
3223 0 : DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
3224 0 : goto done;
3225 : }
3226 :
3227 420626 : if (S_ISDIR(sbuf->st_ex_mode) && def_acl) {
3228 12097 : dir_ace = canonicalise_acl(conn, name, def_acl,
3229 : sbuf,
3230 : &global_sid_Creator_Owner,
3231 : &global_sid_Creator_Group,
3232 : pal, SMB_ACL_TYPE_DEFAULT);
3233 : }
3234 :
3235 : /*
3236 : * Create the NT ACE list from the canonical ace lists.
3237 : */
3238 :
3239 : {
3240 1655 : canon_ace *ace;
3241 1655 : enum security_ace_type nt_acl_type;
3242 :
3243 423429 : num_acls = count_canon_ace_list(file_ace);
3244 420626 : num_def_acls = count_canon_ace_list(dir_ace);
3245 :
3246 420626 : nt_ace_list = talloc_zero_array(
3247 : talloc_tos(), struct security_ace,
3248 : num_acls + num_def_acls);
3249 :
3250 420626 : if (nt_ace_list == NULL) {
3251 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
3252 0 : goto done;
3253 : }
3254 :
3255 : /*
3256 : * Create the NT ACE list from the canonical ace lists.
3257 : */
3258 :
3259 2013326 : for (ace = file_ace; ace != NULL; ace = ace->next) {
3260 1592700 : uint32_t acc = map_canon_ace_perms(SNUM(conn),
3261 : &nt_acl_type,
3262 : ace->perms,
3263 1592700 : S_ISDIR(sbuf->st_ex_mode));
3264 1592700 : init_sec_ace(&nt_ace_list[num_aces++],
3265 1592700 : &ace->trustee,
3266 : nt_acl_type,
3267 : acc,
3268 1592700 : ace->ace_flags);
3269 : }
3270 :
3271 493365 : for (ace = dir_ace; ace != NULL; ace = ace->next) {
3272 72739 : uint32_t acc = map_canon_ace_perms(SNUM(conn),
3273 : &nt_acl_type,
3274 : ace->perms,
3275 72739 : S_ISDIR(sbuf->st_ex_mode));
3276 72739 : init_sec_ace(&nt_ace_list[num_aces++],
3277 72739 : &ace->trustee,
3278 : nt_acl_type,
3279 : acc,
3280 72739 : ace->ace_flags |
3281 : SEC_ACE_FLAG_OBJECT_INHERIT|
3282 : SEC_ACE_FLAG_CONTAINER_INHERIT|
3283 : SEC_ACE_FLAG_INHERIT_ONLY);
3284 : }
3285 :
3286 : /*
3287 : * Merge POSIX default ACLs and normal ACLs into one NT ACE.
3288 : * Win2K needs this to get the inheritance correct when replacing ACLs
3289 : * on a directory tree. Based on work by Jim @ IBM.
3290 : */
3291 :
3292 420626 : num_aces = merge_default_aces(nt_ace_list, num_aces);
3293 : }
3294 :
3295 420626 : if (num_aces) {
3296 420626 : if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
3297 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
3298 0 : goto done;
3299 : }
3300 : }
3301 : } /* security_info & SECINFO_DACL */
3302 :
3303 839597 : psd = make_standard_sec_desc(mem_ctx,
3304 420626 : (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
3305 420626 : (security_info & SECINFO_GROUP) ? &group_sid : NULL,
3306 : psa,
3307 : &sd_size);
3308 :
3309 420626 : if(!psd) {
3310 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
3311 0 : sd_size = 0;
3312 0 : goto done;
3313 : }
3314 :
3315 : /*
3316 : * Windows 2000: The DACL_PROTECTED flag in the security
3317 : * descriptor marks the ACL as non-inheriting, i.e., no
3318 : * ACEs from higher level directories propagate to this
3319 : * ACL. In the POSIX ACL model permissions are only
3320 : * inherited at file create time, so ACLs never contain
3321 : * any ACEs that are inherited dynamically. The DACL_PROTECTED
3322 : * flag doesn't seem to bother Windows NT.
3323 : * Always set this if map acl inherit is turned off.
3324 : */
3325 420626 : if (pal == NULL || !lp_map_acl_inherit(SNUM(conn))) {
3326 420626 : psd->type |= SEC_DESC_DACL_PROTECTED;
3327 : } else {
3328 0 : psd->type |= pal->sd_type;
3329 : }
3330 :
3331 420626 : if (psd->dacl) {
3332 420626 : dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
3333 : }
3334 :
3335 420626 : *ppdesc = psd;
3336 :
3337 420626 : done:
3338 :
3339 420626 : if (posix_acl) {
3340 230212 : TALLOC_FREE(posix_acl);
3341 : }
3342 420626 : if (def_acl) {
3343 12097 : TALLOC_FREE(def_acl);
3344 : }
3345 420626 : free_canon_ace_list(file_ace);
3346 420626 : free_canon_ace_list(dir_ace);
3347 420626 : free_inherited_info(pal);
3348 420626 : TALLOC_FREE(nt_ace_list);
3349 :
3350 420626 : return NT_STATUS_OK;
3351 : }
3352 :
3353 420626 : NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
3354 : TALLOC_CTX *mem_ctx,
3355 : struct security_descriptor **ppdesc)
3356 : {
3357 1655 : SMB_STRUCT_STAT sbuf;
3358 420626 : SMB_ACL_T posix_acl = NULL;
3359 420626 : SMB_ACL_T def_acl = NULL;
3360 1655 : struct pai_val *pal;
3361 420626 : TALLOC_CTX *frame = talloc_stackframe();
3362 1655 : NTSTATUS status;
3363 :
3364 420626 : *ppdesc = NULL;
3365 :
3366 420626 : DEBUG(10,("posix_fget_nt_acl: called for file %s\n",
3367 : fsp_str_dbg(fsp)));
3368 :
3369 : /* Get the stat struct for the owner info. */
3370 420626 : if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
3371 0 : TALLOC_FREE(frame);
3372 0 : return map_nt_error_from_unix(errno);
3373 : }
3374 :
3375 : /* Get the ACL from the fd. */
3376 420626 : posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3377 : SMB_ACL_TYPE_ACCESS,
3378 : frame);
3379 :
3380 : /* If it's a directory get the default POSIX ACL. */
3381 420626 : if(fsp->fsp_flags.is_directory) {
3382 90654 : def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3383 : SMB_ACL_TYPE_DEFAULT,
3384 : frame);
3385 90654 : def_acl = free_empty_sys_acl(fsp->conn, def_acl);
3386 : }
3387 :
3388 420626 : pal = fload_inherited_info(fsp);
3389 :
3390 420626 : status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
3391 : &sbuf, pal, posix_acl, def_acl,
3392 : security_info, mem_ctx, ppdesc);
3393 420626 : TALLOC_FREE(frame);
3394 420626 : return status;
3395 : }
3396 :
3397 : /****************************************************************************
3398 : Try to chown a file. We will be able to chown it under the following conditions.
3399 :
3400 : 1) If we have root privileges, then it will just work.
3401 : 2) If we have SeRestorePrivilege we can change the user + group to any other user.
3402 : 3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
3403 : 4) If we have write permission to the file and dos_filemodes is set
3404 : then allow chown to the currently authenticated user.
3405 : ****************************************************************************/
3406 :
3407 150421 : static NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
3408 : {
3409 445 : NTSTATUS status;
3410 445 : int ret;
3411 :
3412 150421 : if(!CAN_WRITE(fsp->conn)) {
3413 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3414 : }
3415 :
3416 : /* Case (1). */
3417 150421 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
3418 150421 : if (ret == 0) {
3419 90160 : return NT_STATUS_OK;
3420 : }
3421 :
3422 : /* Case (2) / (3) */
3423 60261 : if (lp_enable_privileges()) {
3424 60261 : bool has_take_ownership_priv = security_token_has_privilege(
3425 60261 : get_current_nttok(fsp->conn),
3426 : SEC_PRIV_TAKE_OWNERSHIP);
3427 60261 : bool has_restore_priv = security_token_has_privilege(
3428 60261 : get_current_nttok(fsp->conn),
3429 : SEC_PRIV_RESTORE);
3430 :
3431 60261 : if (has_restore_priv) {
3432 : ; /* Case (2) */
3433 1698 : } else if (has_take_ownership_priv) {
3434 : /* Case (3) */
3435 0 : if (uid == get_current_uid(fsp->conn)) {
3436 0 : gid = (gid_t)-1;
3437 : } else {
3438 0 : has_take_ownership_priv = false;
3439 : }
3440 : }
3441 :
3442 60261 : if (has_take_ownership_priv || has_restore_priv) {
3443 58563 : status = NT_STATUS_OK;
3444 58563 : become_root();
3445 58563 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
3446 58563 : if (ret != 0) {
3447 0 : status = map_nt_error_from_unix(errno);
3448 : }
3449 58563 : unbecome_root();
3450 58563 : return status;
3451 : }
3452 : }
3453 :
3454 : /* Case (4). */
3455 : /* If "dos filemode" isn't set, we're done. */
3456 1698 : if (!lp_dos_filemode(SNUM(fsp->conn))) {
3457 0 : return NT_STATUS_ACCESS_DENIED;
3458 : }
3459 : /*
3460 : * If we have a writable handle, obviously we
3461 : * can write to the file.
3462 : */
3463 1698 : if (!fsp->fsp_flags.can_write) {
3464 : /*
3465 : * If we don't have a writable handle, we
3466 : * need to read the ACL on the file to
3467 : * see if we can write to it.
3468 : */
3469 802 : if (!can_write_to_fsp(fsp)) {
3470 0 : return NT_STATUS_ACCESS_DENIED;
3471 : }
3472 : }
3473 :
3474 : /* only allow chown to the current user. This is more secure,
3475 : and also copes with the case where the SID in a take ownership ACL is
3476 : a local SID on the users workstation
3477 : */
3478 1698 : if (uid != get_current_uid(fsp->conn)) {
3479 2 : return NT_STATUS_INVALID_OWNER;
3480 : }
3481 :
3482 1696 : status = NT_STATUS_OK;
3483 1696 : become_root();
3484 : /* Keep the current file gid the same. */
3485 1696 : ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
3486 1696 : if (ret != 0) {
3487 0 : status = map_nt_error_from_unix(errno);
3488 : }
3489 1696 : unbecome_root();
3490 :
3491 1696 : return status;
3492 : }
3493 :
3494 : /*
3495 : * Check whether a chown is needed and if so, attempt the chown
3496 : * A returned error indicates that the chown failed.
3497 : * NT_STATUS_OK with did_chown == false indicates that the chown was skipped.
3498 : * NT_STATUS_OK with did_chown == true indicates that the chown succeeded
3499 : */
3500 162706 : NTSTATUS chown_if_needed(files_struct *fsp, uint32_t security_info_sent,
3501 : const struct security_descriptor *psd,
3502 : bool *did_chown)
3503 : {
3504 452 : NTSTATUS status;
3505 162706 : uid_t uid = (uid_t)-1;
3506 162706 : gid_t gid = (gid_t)-1;
3507 :
3508 162706 : status = unpack_nt_owners(fsp->conn, &uid, &gid, security_info_sent, psd);
3509 162706 : if (!NT_STATUS_IS_OK(status)) {
3510 0 : return status;
3511 : }
3512 :
3513 162706 : if (((uid == (uid_t)-1) || (fsp->fsp_name->st.st_ex_uid == uid)) &&
3514 101848 : ((gid == (gid_t)-1) || (fsp->fsp_name->st.st_ex_gid == gid))) {
3515 : /*
3516 : * Skip chown
3517 : */
3518 12285 : *did_chown = false;
3519 12285 : return NT_STATUS_OK;
3520 : }
3521 :
3522 150421 : DBG_NOTICE("chown %s. uid = %u, gid = %u.\n",
3523 : fsp_str_dbg(fsp), (unsigned int) uid, (unsigned int)gid);
3524 :
3525 150421 : status = try_chown(fsp, uid, gid);
3526 150421 : if (!NT_STATUS_IS_OK(status)) {
3527 2 : DBG_INFO("chown %s, %u, %u failed. Error = %s.\n",
3528 : fsp_str_dbg(fsp), (unsigned int) uid,
3529 : (unsigned int)gid, nt_errstr(status));
3530 2 : return status;
3531 : }
3532 :
3533 : /*
3534 : * Recheck the current state of the file, which may have changed.
3535 : * (owner and suid/sgid bits, for instance)
3536 : */
3537 :
3538 150419 : status = vfs_stat_fsp(fsp);
3539 150419 : if (!NT_STATUS_IS_OK(status)) {
3540 0 : return status;
3541 : }
3542 :
3543 150419 : *did_chown = true;
3544 150419 : return NT_STATUS_OK;
3545 : }
3546 :
3547 : /****************************************************************************
3548 : Reply to set a security descriptor on an fsp. security_info_sent is the
3549 : description of the following NT ACL.
3550 : This should be the only external function needed for the UNIX style set ACL.
3551 : We make a copy of psd_orig as internal functions modify the elements inside
3552 : it, even though it's a const pointer.
3553 : ****************************************************************************/
3554 :
3555 157694 : NTSTATUS set_nt_acl(files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd_orig)
3556 : {
3557 157694 : connection_struct *conn = fsp->conn;
3558 452 : struct dom_sid file_owner_sid;
3559 452 : struct dom_sid file_grp_sid;
3560 157694 : canon_ace *file_ace_list = NULL;
3561 157694 : canon_ace *dir_ace_list = NULL;
3562 157694 : bool acl_perms = False;
3563 157694 : mode_t orig_mode = (mode_t)0;
3564 452 : NTSTATUS status;
3565 157694 : bool set_acl_as_root = false;
3566 157694 : bool acl_set_support = false;
3567 157694 : bool ret = false;
3568 157694 : struct security_descriptor *psd = NULL;
3569 :
3570 157694 : DEBUG(10,("set_nt_acl: called for file %s\n",
3571 : fsp_str_dbg(fsp)));
3572 :
3573 157694 : if (!CAN_WRITE(conn)) {
3574 0 : DEBUG(10,("set acl rejected on read-only share\n"));
3575 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3576 : }
3577 :
3578 157694 : if (psd_orig == NULL) {
3579 0 : return NT_STATUS_INVALID_PARAMETER;
3580 : }
3581 :
3582 : /*
3583 : * MS NFS mode, here's the deal: the client merely wants to
3584 : * modify the mode, but roundtripping get_acl/set/acl would
3585 : * add additional POSIX ACEs. So in case we get a request
3586 : * containing a MS NFS mode SID, we do nothing here.
3587 : */
3588 157694 : if (security_descriptor_with_ms_nfs(psd_orig)) {
3589 0 : return NT_STATUS_OK;
3590 : }
3591 :
3592 157694 : psd = security_descriptor_copy(talloc_tos(), psd_orig);
3593 157694 : if (psd == NULL) {
3594 0 : return NT_STATUS_NO_MEMORY;
3595 : }
3596 :
3597 : /*
3598 : * Get the current state of the file.
3599 : */
3600 :
3601 157694 : status = vfs_stat_fsp(fsp);
3602 157694 : if (!NT_STATUS_IS_OK(status)) {
3603 0 : return status;
3604 : }
3605 :
3606 : /* Save the original element we check against. */
3607 157694 : orig_mode = fsp->fsp_name->st.st_ex_mode;
3608 :
3609 : /*
3610 : * Unpack the user/group/world id's.
3611 : */
3612 :
3613 : /* POSIX can't cope with missing owner/group. */
3614 157694 : if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
3615 0 : security_info_sent &= ~SECINFO_OWNER;
3616 : }
3617 157694 : if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
3618 0 : security_info_sent &= ~SECINFO_GROUP;
3619 : }
3620 :
3621 : /* If UNIX owner is inherited and Windows isn't, then
3622 : * setting the UNIX owner based on Windows owner conflicts
3623 : * with the inheritance rule
3624 : */
3625 157694 : if (lp_inherit_owner(SNUM(conn)) == INHERIT_OWNER_UNIX_ONLY) {
3626 16 : security_info_sent &= ~SECINFO_OWNER;
3627 : }
3628 :
3629 : /*
3630 : * Do we need to chown ? If so this must be done first as the incoming
3631 : * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
3632 : * Noticed by Simo.
3633 : *
3634 : * If we successfully chowned, we know we must be able to set
3635 : * the acl, so do it as root (set_acl_as_root).
3636 : */
3637 157694 : status = chown_if_needed(fsp, security_info_sent, psd, &set_acl_as_root);
3638 157694 : if (!NT_STATUS_IS_OK(status)) {
3639 2 : return status;
3640 : }
3641 :
3642 157692 : create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
3643 :
3644 157692 : if((security_info_sent & SECINFO_DACL) &&
3645 155598 : (psd->type & SEC_DESC_DACL_PRESENT) &&
3646 155598 : (psd->dacl == NULL)) {
3647 0 : struct security_ace ace[3];
3648 :
3649 : /* We can't have NULL DACL in POSIX.
3650 : Use owner/group/Everyone -> full access. */
3651 :
3652 20 : init_sec_ace(&ace[0],
3653 : &file_owner_sid,
3654 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3655 : GENERIC_ALL_ACCESS,
3656 : 0);
3657 20 : init_sec_ace(&ace[1],
3658 : &file_grp_sid,
3659 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3660 : GENERIC_ALL_ACCESS,
3661 : 0);
3662 20 : init_sec_ace(&ace[2],
3663 : &global_sid_World,
3664 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3665 : GENERIC_ALL_ACCESS,
3666 : 0);
3667 20 : psd->dacl = make_sec_acl(talloc_tos(),
3668 : NT4_ACL_REVISION,
3669 : 3,
3670 : ace);
3671 20 : if (psd->dacl == NULL) {
3672 0 : return NT_STATUS_NO_MEMORY;
3673 : }
3674 20 : security_acl_map_generic(psd->dacl, &file_generic_mapping);
3675 : }
3676 :
3677 157692 : acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
3678 : &file_grp_sid, &file_ace_list,
3679 : &dir_ace_list, security_info_sent, psd);
3680 :
3681 : /* Ignore W2K traverse DACL set. */
3682 157692 : if (!file_ace_list && !dir_ace_list) {
3683 4677 : return NT_STATUS_OK;
3684 : }
3685 :
3686 153015 : if (!acl_perms) {
3687 0 : DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3688 0 : free_canon_ace_list(file_ace_list);
3689 0 : free_canon_ace_list(dir_ace_list);
3690 0 : return NT_STATUS_ACCESS_DENIED;
3691 : }
3692 :
3693 : /*
3694 : * Only change security if we got a DACL.
3695 : */
3696 :
3697 153015 : if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
3698 0 : free_canon_ace_list(file_ace_list);
3699 0 : free_canon_ace_list(dir_ace_list);
3700 0 : return NT_STATUS_OK;
3701 : }
3702 :
3703 : /*
3704 : * Try using the POSIX ACL set first. Fall back to chmod if
3705 : * we have no ACL support on this filesystem.
3706 : */
3707 :
3708 153015 : if (acl_perms && file_ace_list) {
3709 153015 : if (set_acl_as_root) {
3710 146367 : become_root();
3711 : }
3712 153427 : ret = set_canon_ace_list(fsp, file_ace_list, false,
3713 153015 : &fsp->fsp_name->st, &acl_set_support);
3714 153015 : if (set_acl_as_root) {
3715 146367 : unbecome_root();
3716 : }
3717 153015 : if (acl_set_support && ret == false) {
3718 0 : DEBUG(3,("set_nt_acl: failed to set file acl on file "
3719 : "%s (%s).\n", fsp_str_dbg(fsp),
3720 : strerror(errno)));
3721 0 : free_canon_ace_list(file_ace_list);
3722 0 : free_canon_ace_list(dir_ace_list);
3723 0 : return map_nt_error_from_unix(errno);
3724 : }
3725 : }
3726 :
3727 153015 : if (acl_perms && acl_set_support && fsp->fsp_flags.is_directory) {
3728 11402 : if (dir_ace_list) {
3729 11081 : if (set_acl_as_root) {
3730 9673 : become_root();
3731 : }
3732 11204 : ret = set_canon_ace_list(fsp, dir_ace_list, true,
3733 11081 : &fsp->fsp_name->st,
3734 : &acl_set_support);
3735 11081 : if (set_acl_as_root) {
3736 9673 : unbecome_root();
3737 : }
3738 11081 : if (ret == false) {
3739 0 : DEBUG(3,("set_nt_acl: failed to set default "
3740 : "acl on directory %s (%s).\n",
3741 : fsp_str_dbg(fsp), strerror(errno)));
3742 0 : free_canon_ace_list(file_ace_list);
3743 0 : free_canon_ace_list(dir_ace_list);
3744 0 : return map_nt_error_from_unix(errno);
3745 : }
3746 : } else {
3747 321 : int sret = -1;
3748 :
3749 : /*
3750 : * No default ACL - delete one if it exists.
3751 : */
3752 :
3753 321 : if (set_acl_as_root) {
3754 79 : become_root();
3755 : }
3756 321 : sret = SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
3757 321 : if (set_acl_as_root) {
3758 79 : unbecome_root();
3759 : }
3760 321 : if (sret == -1) {
3761 0 : if (acl_group_override_fsp(fsp)) {
3762 0 : DEBUG(5,("set_nt_acl: acl group "
3763 : "control on and current user "
3764 : "in file %s primary group. "
3765 : "Override delete_def_acl\n",
3766 : fsp_str_dbg(fsp)));
3767 :
3768 0 : become_root();
3769 0 : sret =
3770 0 : SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
3771 0 : unbecome_root();
3772 : }
3773 :
3774 0 : if (sret == -1) {
3775 0 : DBG_NOTICE("sys_acl_delete_def_fd for "
3776 : "directory %s failed (%s)\n",
3777 : fsp_str_dbg(fsp),
3778 : strerror(errno));
3779 0 : free_canon_ace_list(file_ace_list);
3780 0 : free_canon_ace_list(dir_ace_list);
3781 0 : return map_nt_error_from_unix(errno);
3782 : }
3783 : }
3784 : }
3785 : }
3786 :
3787 153015 : if (acl_set_support) {
3788 153015 : if (set_acl_as_root) {
3789 146367 : become_root();
3790 : }
3791 153015 : store_inheritance_attributes(fsp,
3792 : file_ace_list,
3793 : dir_ace_list,
3794 153015 : psd->type);
3795 153015 : if (set_acl_as_root) {
3796 146367 : unbecome_root();
3797 : }
3798 : }
3799 :
3800 : /*
3801 : * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3802 : */
3803 :
3804 153015 : if(!acl_set_support && acl_perms) {
3805 0 : mode_t posix_perms;
3806 :
3807 0 : if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3808 0 : free_canon_ace_list(file_ace_list);
3809 0 : free_canon_ace_list(dir_ace_list);
3810 0 : DEBUG(3,("set_nt_acl: failed to convert file acl to "
3811 : "posix permissions for file %s.\n",
3812 : fsp_str_dbg(fsp)));
3813 0 : return NT_STATUS_ACCESS_DENIED;
3814 : }
3815 :
3816 0 : if (orig_mode != posix_perms) {
3817 0 : int sret = -1;
3818 :
3819 0 : DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3820 : fsp_str_dbg(fsp), (unsigned int)posix_perms));
3821 :
3822 0 : if (set_acl_as_root) {
3823 0 : become_root();
3824 : }
3825 0 : sret = SMB_VFS_FCHMOD(fsp, posix_perms);
3826 0 : if (set_acl_as_root) {
3827 0 : unbecome_root();
3828 : }
3829 0 : if(sret == -1) {
3830 0 : if (acl_group_override_fsp(fsp)) {
3831 0 : DEBUG(5,("set_nt_acl: acl group "
3832 : "control on and current user "
3833 : "in file %s primary group. "
3834 : "Override chmod\n",
3835 : fsp_str_dbg(fsp)));
3836 :
3837 0 : become_root();
3838 0 : sret = SMB_VFS_FCHMOD(fsp, posix_perms);
3839 0 : unbecome_root();
3840 : }
3841 :
3842 0 : if (sret == -1) {
3843 0 : DEBUG(3,("set_nt_acl: chmod %s, 0%o "
3844 : "failed. Error = %s.\n",
3845 : fsp_str_dbg(fsp),
3846 : (unsigned int)posix_perms,
3847 : strerror(errno)));
3848 0 : free_canon_ace_list(file_ace_list);
3849 0 : free_canon_ace_list(dir_ace_list);
3850 0 : return map_nt_error_from_unix(errno);
3851 : }
3852 : }
3853 : }
3854 : }
3855 :
3856 153015 : free_canon_ace_list(file_ace_list);
3857 153015 : free_canon_ace_list(dir_ace_list);
3858 :
3859 : /* Ensure the stat struct in the fsp is correct. */
3860 153015 : status = vfs_stat_fsp(fsp);
3861 :
3862 153015 : return NT_STATUS_OK;
3863 : }
3864 :
3865 : /****************************************************************************
3866 : Get the actual group bits stored on a file with an ACL. Has no effect if
3867 : the file has no ACL. Needed in dosmode code where the stat() will return
3868 : the mask bits, not the real group bits, for a file with an ACL.
3869 : ****************************************************************************/
3870 :
3871 175340 : int get_acl_group_bits(connection_struct *conn,
3872 : struct files_struct *fsp,
3873 : mode_t *mode )
3874 : {
3875 175340 : int entry_id = SMB_ACL_FIRST_ENTRY;
3876 463 : SMB_ACL_ENTRY_T entry;
3877 463 : SMB_ACL_T posix_acl;
3878 175340 : int result = -1;
3879 :
3880 175340 : posix_acl = SMB_VFS_SYS_ACL_GET_FD(metadata_fsp(fsp),
3881 : SMB_ACL_TYPE_ACCESS,
3882 : talloc_tos());
3883 175340 : if (posix_acl == (SMB_ACL_T)NULL)
3884 147765 : return -1;
3885 :
3886 64197 : while (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
3887 472 : SMB_ACL_TAG_T tagtype;
3888 472 : SMB_ACL_PERMSET_T permset;
3889 :
3890 64197 : entry_id = SMB_ACL_NEXT_ENTRY;
3891 :
3892 64197 : if (sys_acl_get_tag_type(entry, &tagtype) ==-1)
3893 27112 : break;
3894 :
3895 64197 : if (tagtype == SMB_ACL_GROUP_OBJ) {
3896 27230 : if (sys_acl_get_permset(entry, &permset) == -1) {
3897 0 : break;
3898 : } else {
3899 27230 : *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3900 27230 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRGRP : 0);
3901 27230 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3902 27230 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3903 27230 : result = 0;
3904 27230 : break;
3905 : }
3906 : }
3907 : }
3908 27230 : TALLOC_FREE(posix_acl);
3909 27230 : return result;
3910 : }
3911 :
3912 : /****************************************************************************
3913 : Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3914 : and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3915 : ****************************************************************************/
3916 :
3917 0 : static int chmod_acl_internals(SMB_ACL_T posix_acl, mode_t mode)
3918 : {
3919 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
3920 0 : SMB_ACL_ENTRY_T entry;
3921 0 : int num_entries = 0;
3922 :
3923 0 : while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
3924 0 : SMB_ACL_TAG_T tagtype;
3925 0 : SMB_ACL_PERMSET_T permset;
3926 0 : mode_t perms;
3927 :
3928 0 : entry_id = SMB_ACL_NEXT_ENTRY;
3929 :
3930 0 : if (sys_acl_get_tag_type(entry, &tagtype) == -1)
3931 0 : return -1;
3932 :
3933 0 : if (sys_acl_get_permset(entry, &permset) == -1)
3934 0 : return -1;
3935 :
3936 0 : num_entries++;
3937 :
3938 0 : switch(tagtype) {
3939 0 : case SMB_ACL_USER_OBJ:
3940 0 : perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3941 0 : break;
3942 0 : case SMB_ACL_GROUP_OBJ:
3943 0 : perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3944 0 : break;
3945 0 : case SMB_ACL_MASK:
3946 : /*
3947 : * FIXME: The ACL_MASK entry permissions should really be set to
3948 : * the union of the permissions of all ACL_USER,
3949 : * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3950 : * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3951 : */
3952 0 : perms = S_IRUSR|S_IWUSR|S_IXUSR;
3953 0 : break;
3954 0 : case SMB_ACL_OTHER:
3955 0 : perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3956 0 : break;
3957 0 : default:
3958 0 : continue;
3959 : }
3960 :
3961 0 : if (map_acl_perms_to_permset(perms, &permset) == -1)
3962 0 : return -1;
3963 :
3964 0 : if (sys_acl_set_permset(entry, permset) == -1)
3965 0 : return -1;
3966 : }
3967 :
3968 : /*
3969 : * If this is a simple 3 element ACL or no elements then it's a standard
3970 : * UNIX permission set. Just use chmod...
3971 : */
3972 :
3973 0 : if ((num_entries == 3) || (num_entries == 0))
3974 0 : return -1;
3975 :
3976 0 : return 0;
3977 : }
3978 :
3979 : /****************************************************************************
3980 : Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3981 : GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3982 : resulting ACL on TO. Note that name is in UNIX character set.
3983 : ****************************************************************************/
3984 :
3985 0 : static int copy_access_posix_acl(struct files_struct *from,
3986 : struct files_struct *to,
3987 : mode_t mode)
3988 : {
3989 0 : SMB_ACL_T posix_acl = NULL;
3990 0 : int ret = -1;
3991 :
3992 0 : posix_acl = SMB_VFS_SYS_ACL_GET_FD(
3993 : from, SMB_ACL_TYPE_ACCESS, talloc_tos());
3994 0 : if (posix_acl == NULL) {
3995 0 : return -1;
3996 : }
3997 :
3998 0 : ret = chmod_acl_internals(posix_acl, mode);
3999 0 : if (ret == -1) {
4000 0 : goto done;
4001 : }
4002 :
4003 0 : ret = SMB_VFS_SYS_ACL_SET_FD(to, SMB_ACL_TYPE_ACCESS, posix_acl);
4004 :
4005 0 : done:
4006 :
4007 0 : TALLOC_FREE(posix_acl);
4008 0 : return ret;
4009 : }
4010 :
4011 : /****************************************************************************
4012 : Check for an existing default POSIX ACL on a directory.
4013 : ****************************************************************************/
4014 :
4015 0 : static bool directory_has_default_posix_acl(struct files_struct *dirfsp)
4016 : {
4017 0 : SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FD(
4018 : dirfsp, SMB_ACL_TYPE_DEFAULT, talloc_tos());
4019 0 : bool has_acl = False;
4020 0 : SMB_ACL_ENTRY_T entry;
4021 :
4022 0 : if (def_acl != NULL && (sys_acl_get_entry(def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
4023 0 : has_acl = True;
4024 : }
4025 :
4026 0 : if (def_acl) {
4027 0 : TALLOC_FREE(def_acl);
4028 : }
4029 0 : return has_acl;
4030 : }
4031 :
4032 : /****************************************************************************
4033 : If the parent directory has no default ACL but it does have an Access ACL,
4034 : inherit this Access ACL to file name.
4035 : ****************************************************************************/
4036 :
4037 0 : int inherit_access_posix_acl(connection_struct *conn,
4038 : struct files_struct *inherit_from_dirfsp,
4039 : const struct smb_filename *smb_fname,
4040 : mode_t mode)
4041 : {
4042 0 : int ret;
4043 :
4044 0 : if (directory_has_default_posix_acl(inherit_from_dirfsp))
4045 0 : return 0;
4046 :
4047 0 : ret = copy_access_posix_acl(
4048 0 : inherit_from_dirfsp, smb_fname->fsp, mode);
4049 0 : return ret;
4050 : }
4051 :
4052 : /****************************************************************************
4053 : Map from wire type to permset.
4054 : ****************************************************************************/
4055 :
4056 20 : static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
4057 : {
4058 20 : if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
4059 0 : return False;
4060 : }
4061 :
4062 20 : if (sys_acl_clear_perms(*p_permset) == -1) {
4063 0 : return False;
4064 : }
4065 :
4066 20 : if (wire_perm & SMB_POSIX_ACL_READ) {
4067 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1) {
4068 0 : return False;
4069 : }
4070 : }
4071 20 : if (wire_perm & SMB_POSIX_ACL_WRITE) {
4072 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1) {
4073 0 : return False;
4074 : }
4075 : }
4076 20 : if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
4077 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1) {
4078 0 : return False;
4079 : }
4080 : }
4081 20 : return True;
4082 : }
4083 :
4084 : /****************************************************************************
4085 : Map from wire type to tagtype.
4086 : ****************************************************************************/
4087 :
4088 20 : static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
4089 : {
4090 20 : switch (wire_tt) {
4091 4 : case SMB_POSIX_ACL_USER_OBJ:
4092 4 : *p_tt = SMB_ACL_USER_OBJ;
4093 4 : break;
4094 4 : case SMB_POSIX_ACL_USER:
4095 4 : *p_tt = SMB_ACL_USER;
4096 4 : break;
4097 4 : case SMB_POSIX_ACL_GROUP_OBJ:
4098 4 : *p_tt = SMB_ACL_GROUP_OBJ;
4099 4 : break;
4100 0 : case SMB_POSIX_ACL_GROUP:
4101 0 : *p_tt = SMB_ACL_GROUP;
4102 0 : break;
4103 4 : case SMB_POSIX_ACL_MASK:
4104 4 : *p_tt = SMB_ACL_MASK;
4105 4 : break;
4106 4 : case SMB_POSIX_ACL_OTHER:
4107 4 : *p_tt = SMB_ACL_OTHER;
4108 4 : break;
4109 0 : default:
4110 0 : return False;
4111 : }
4112 20 : return True;
4113 : }
4114 :
4115 : /****************************************************************************
4116 : Create a new POSIX acl from wire permissions.
4117 : FIXME ! How does the share mask/mode fit into this.... ?
4118 : ****************************************************************************/
4119 :
4120 4 : static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn,
4121 : uint16_t num_acls,
4122 : const char *pdata,
4123 : TALLOC_CTX *mem_ctx)
4124 : {
4125 0 : unsigned int i;
4126 4 : SMB_ACL_T the_acl = sys_acl_init(mem_ctx);
4127 :
4128 4 : if (the_acl == NULL) {
4129 0 : return NULL;
4130 : }
4131 :
4132 24 : for (i = 0; i < num_acls; i++) {
4133 0 : SMB_ACL_ENTRY_T the_entry;
4134 0 : SMB_ACL_PERMSET_T the_permset;
4135 0 : SMB_ACL_TAG_T tag_type;
4136 :
4137 20 : if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
4138 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
4139 : i, strerror(errno) ));
4140 0 : goto fail;
4141 : }
4142 :
4143 20 : if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
4144 0 : DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
4145 : CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
4146 0 : goto fail;
4147 : }
4148 :
4149 20 : if (sys_acl_set_tag_type(the_entry, tag_type) == -1) {
4150 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
4151 : i, strerror(errno) ));
4152 0 : goto fail;
4153 : }
4154 :
4155 : /* Get the permset pointer from the new ACL entry. */
4156 20 : if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
4157 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
4158 : i, strerror(errno) ));
4159 0 : goto fail;
4160 : }
4161 :
4162 : /* Map from wire to permissions. */
4163 20 : if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
4164 0 : DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
4165 : CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
4166 0 : goto fail;
4167 : }
4168 :
4169 : /* Now apply to the new ACL entry. */
4170 20 : if (sys_acl_set_permset(the_entry, the_permset) == -1) {
4171 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
4172 : i, strerror(errno) ));
4173 0 : goto fail;
4174 : }
4175 :
4176 20 : if (tag_type == SMB_ACL_USER) {
4177 4 : uint32_t uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4178 4 : uid_t uid = (uid_t)uidval;
4179 4 : if (sys_acl_set_qualifier(the_entry,(void *)&uid) == -1) {
4180 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
4181 : (unsigned int)uid, i, strerror(errno) ));
4182 0 : goto fail;
4183 : }
4184 : }
4185 :
4186 20 : if (tag_type == SMB_ACL_GROUP) {
4187 0 : uint32_t gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4188 0 : gid_t gid = (uid_t)gidval;
4189 0 : if (sys_acl_set_qualifier(the_entry,(void *)&gid) == -1) {
4190 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
4191 : (unsigned int)gid, i, strerror(errno) ));
4192 0 : goto fail;
4193 : }
4194 : }
4195 : }
4196 :
4197 4 : return the_acl;
4198 :
4199 0 : fail:
4200 :
4201 0 : if (the_acl != NULL) {
4202 0 : TALLOC_FREE(the_acl);
4203 : }
4204 0 : return NULL;
4205 : }
4206 :
4207 : /****************************************************************************
4208 : Calls from UNIX extensions - Default POSIX ACL set.
4209 : If num_def_acls == 0 and not a directory just return. If it is a directory
4210 : and num_def_acls == 0 then remove the default acl. Else set the default acl
4211 : on the directory.
4212 : ****************************************************************************/
4213 :
4214 4 : NTSTATUS set_unix_posix_default_acl(connection_struct *conn,
4215 : files_struct *fsp,
4216 : uint16_t num_def_acls,
4217 : const char *pdata)
4218 : {
4219 4 : SMB_ACL_T def_acl = NULL;
4220 0 : NTSTATUS status;
4221 0 : int ret;
4222 :
4223 4 : if (!fsp->fsp_flags.is_directory) {
4224 0 : return NT_STATUS_INVALID_HANDLE;
4225 : }
4226 :
4227 4 : if (!num_def_acls) {
4228 : /* Remove the default ACL. */
4229 0 : ret = SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
4230 0 : if (ret == -1) {
4231 0 : status = map_nt_error_from_unix(errno);
4232 0 : DBG_INFO("acl_delete_def_fd failed on "
4233 : "directory %s (%s)\n",
4234 : fsp_str_dbg(fsp),
4235 : strerror(errno));
4236 0 : return status;
4237 : }
4238 0 : return NT_STATUS_OK;
4239 : }
4240 :
4241 4 : def_acl = create_posix_acl_from_wire(conn,
4242 : num_def_acls,
4243 : pdata,
4244 : talloc_tos());
4245 4 : if (def_acl == NULL) {
4246 0 : return map_nt_error_from_unix(errno);
4247 : }
4248 :
4249 4 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp,
4250 : SMB_ACL_TYPE_DEFAULT,
4251 : def_acl);
4252 4 : if (ret == -1) {
4253 0 : status = map_nt_error_from_unix(errno);
4254 0 : DBG_INFO("acl_set_file failed on directory %s (%s)\n",
4255 : fsp_str_dbg(fsp),
4256 : strerror(errno));
4257 0 : TALLOC_FREE(def_acl);
4258 0 : return status;
4259 : }
4260 :
4261 4 : DBG_DEBUG("set default acl for file %s\n",
4262 : fsp_str_dbg(fsp));
4263 4 : TALLOC_FREE(def_acl);
4264 4 : return NT_STATUS_OK;
4265 : }
4266 :
4267 : /****************************************************************************
4268 : Remove an ACL from a file. As we don't have acl_delete_entry() available
4269 : we must read the current acl and copy all entries except MASK, USER and GROUP
4270 : to a new acl, then set that. This (at least on Linux) causes any ACL to be
4271 : removed.
4272 : FIXME ! How does the share mask/mode fit into this.... ?
4273 : ****************************************************************************/
4274 :
4275 0 : static NTSTATUS remove_posix_acl(connection_struct *conn,
4276 : files_struct *fsp)
4277 : {
4278 0 : SMB_ACL_T file_acl = NULL;
4279 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
4280 0 : SMB_ACL_ENTRY_T entry;
4281 : /* Create a new ACL with only 3 entries, u/g/w. */
4282 0 : SMB_ACL_T new_file_acl = NULL;
4283 0 : SMB_ACL_ENTRY_T user_ent = NULL;
4284 0 : SMB_ACL_ENTRY_T group_ent = NULL;
4285 0 : SMB_ACL_ENTRY_T other_ent = NULL;
4286 0 : NTSTATUS status;
4287 0 : int ret;
4288 :
4289 0 : new_file_acl = sys_acl_init(talloc_tos());
4290 0 : if (new_file_acl == NULL) {
4291 0 : status = map_nt_error_from_unix(errno);
4292 0 : DBG_INFO("failed to init new ACL with 3 entries "
4293 : "for file %s %s.\n",
4294 : fsp_str_dbg(fsp),
4295 : strerror(errno));
4296 0 : goto done;
4297 : }
4298 :
4299 : /* Now create the u/g/w entries. */
4300 0 : ret = sys_acl_create_entry(&new_file_acl, &user_ent);
4301 0 : if (ret == -1) {
4302 0 : status = map_nt_error_from_unix(errno);
4303 0 : DBG_INFO("Failed to create user entry for file %s. (%s)\n",
4304 : fsp_str_dbg(fsp),
4305 : strerror(errno));
4306 0 : goto done;
4307 : }
4308 0 : ret = sys_acl_set_tag_type(user_ent, SMB_ACL_USER_OBJ);
4309 0 : if (ret == -1) {
4310 0 : status = map_nt_error_from_unix(errno);
4311 0 : DBG_INFO("Failed to set user entry for file %s. (%s)\n",
4312 : fsp_str_dbg(fsp),
4313 : strerror(errno));
4314 0 : goto done;
4315 : }
4316 :
4317 0 : ret = sys_acl_create_entry(&new_file_acl, &group_ent);
4318 0 : if (ret == -1) {
4319 0 : status = map_nt_error_from_unix(errno);
4320 0 : DBG_INFO("Failed to create group entry for file %s. (%s)\n",
4321 : fsp_str_dbg(fsp),
4322 : strerror(errno));
4323 0 : goto done;
4324 : }
4325 0 : ret = sys_acl_set_tag_type(group_ent, SMB_ACL_GROUP_OBJ);
4326 0 : if (ret == -1) {
4327 0 : status = map_nt_error_from_unix(errno);
4328 0 : DBG_INFO("Failed to set group entry for file %s. (%s)\n",
4329 : fsp_str_dbg(fsp),
4330 : strerror(errno));
4331 0 : goto done;
4332 : }
4333 :
4334 0 : ret = sys_acl_create_entry(&new_file_acl, &other_ent);
4335 0 : if (ret == -1) {
4336 0 : status = map_nt_error_from_unix(errno);
4337 0 : DBG_INFO("Failed to create other entry for file %s. (%s)\n",
4338 : fsp_str_dbg(fsp),
4339 : strerror(errno));
4340 0 : goto done;
4341 : }
4342 0 : ret = sys_acl_set_tag_type(other_ent, SMB_ACL_OTHER);
4343 0 : if (ret == -1) {
4344 0 : status = map_nt_error_from_unix(errno);
4345 0 : DBG_INFO("Failed to set other entry for file %s. (%s)\n",
4346 : fsp_str_dbg(fsp),
4347 : strerror(errno));
4348 0 : goto done;
4349 : }
4350 :
4351 : /* Get the current file ACL. */
4352 0 : file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
4353 : SMB_ACL_TYPE_ACCESS,
4354 : talloc_tos());
4355 :
4356 0 : if (file_acl == NULL) {
4357 0 : status = map_nt_error_from_unix(errno);
4358 : /* This is only returned if an error occurred. Even for a file with
4359 : no acl a u/g/w acl should be returned. */
4360 0 : DBG_INFO("failed to get ACL from file %s (%s).\n",
4361 : fsp_str_dbg(fsp),
4362 : strerror(errno));
4363 0 : goto done;
4364 : }
4365 :
4366 0 : while ( sys_acl_get_entry(file_acl, entry_id, &entry) == 1) {
4367 0 : SMB_ACL_TAG_T tagtype;
4368 0 : SMB_ACL_PERMSET_T permset;
4369 :
4370 0 : entry_id = SMB_ACL_NEXT_ENTRY;
4371 :
4372 0 : ret = sys_acl_get_tag_type(entry, &tagtype);
4373 0 : if (ret == -1) {
4374 0 : status = map_nt_error_from_unix(errno);
4375 0 : DBG_INFO("failed to get tagtype from ACL "
4376 : "on file %s (%s).\n",
4377 : fsp_str_dbg(fsp),
4378 : strerror(errno));
4379 0 : goto done;
4380 : }
4381 :
4382 0 : ret = sys_acl_get_permset(entry, &permset);
4383 0 : if (ret == -1) {
4384 0 : status = map_nt_error_from_unix(errno);
4385 0 : DBG_INFO("failed to get permset from ACL "
4386 : "on file %s (%s).\n",
4387 : fsp_str_dbg(fsp),
4388 : strerror(errno));
4389 0 : goto done;
4390 : }
4391 :
4392 0 : if (tagtype == SMB_ACL_USER_OBJ) {
4393 0 : ret = sys_acl_set_permset(user_ent, permset);
4394 0 : if (ret == -1) {
4395 0 : status = map_nt_error_from_unix(errno);
4396 0 : DBG_INFO("failed to set permset from ACL "
4397 : "on file %s (%s).\n",
4398 : fsp_str_dbg(fsp),
4399 : strerror(errno));
4400 0 : goto done;
4401 : }
4402 0 : } else if (tagtype == SMB_ACL_GROUP_OBJ) {
4403 0 : ret = sys_acl_set_permset(group_ent, permset);
4404 0 : if (ret == -1) {
4405 0 : status = map_nt_error_from_unix(errno);
4406 0 : DBG_INFO("failed to set permset from ACL "
4407 : "on file %s (%s).\n",
4408 : fsp_str_dbg(fsp),
4409 : strerror(errno));
4410 0 : goto done;
4411 : }
4412 0 : } else if (tagtype == SMB_ACL_OTHER) {
4413 0 : ret = sys_acl_set_permset(other_ent, permset);
4414 0 : if (ret == -1) {
4415 0 : status = map_nt_error_from_unix(errno);
4416 0 : DBG_INFO("failed to set permset from ACL "
4417 : "on file %s (%s).\n",
4418 : fsp_str_dbg(fsp),
4419 : strerror(errno));
4420 0 : goto done;
4421 : }
4422 : }
4423 : }
4424 :
4425 : /* Set the new empty file ACL. */
4426 0 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp, SMB_ACL_TYPE_ACCESS, new_file_acl);
4427 0 : if (ret == -1) {
4428 0 : status = map_nt_error_from_unix(errno);
4429 0 : DBG_INFO("acl_set_file failed on %s (%s)\n",
4430 : fsp_str_dbg(fsp),
4431 : strerror(errno));
4432 0 : goto done;
4433 : }
4434 :
4435 0 : status = NT_STATUS_OK;
4436 :
4437 0 : done:
4438 :
4439 0 : TALLOC_FREE(file_acl);
4440 0 : TALLOC_FREE(new_file_acl);
4441 0 : return status;
4442 : }
4443 :
4444 : /****************************************************************************
4445 : Calls from UNIX extensions - POSIX ACL set.
4446 : If num_def_acls == 0 then read/modify/write acl after removing all entries
4447 : except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
4448 : ****************************************************************************/
4449 :
4450 0 : NTSTATUS set_unix_posix_acl(connection_struct *conn,
4451 : files_struct *fsp,
4452 : uint16_t num_acls,
4453 : const char *pdata)
4454 : {
4455 0 : SMB_ACL_T file_acl = NULL;
4456 0 : int ret;
4457 0 : NTSTATUS status;
4458 :
4459 0 : if (!num_acls) {
4460 : /* Remove the ACL from the file. */
4461 0 : return remove_posix_acl(conn, fsp);
4462 : }
4463 :
4464 0 : file_acl = create_posix_acl_from_wire(conn,
4465 : num_acls,
4466 : pdata,
4467 : talloc_tos());
4468 0 : if (file_acl == NULL) {
4469 0 : return map_nt_error_from_unix(errno);
4470 : }
4471 :
4472 0 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp, SMB_ACL_TYPE_ACCESS, file_acl);
4473 0 : if (ret == -1) {
4474 0 : status = map_nt_error_from_unix(errno);
4475 0 : DBG_INFO("acl_set_file failed on %s (%s)\n",
4476 : fsp_str_dbg(fsp),
4477 : strerror(errno));
4478 0 : TALLOC_FREE(file_acl);
4479 0 : return status;
4480 : }
4481 :
4482 0 : DBG_DEBUG("set acl for file %s\n",
4483 : fsp_str_dbg(fsp));
4484 :
4485 0 : TALLOC_FREE(file_acl);
4486 0 : return NT_STATUS_OK;
4487 : }
4488 :
4489 0 : int posix_sys_acl_blob_get_file(vfs_handle_struct *handle,
4490 : const struct smb_filename *smb_fname_in,
4491 : TALLOC_CTX *mem_ctx,
4492 : char **blob_description,
4493 : DATA_BLOB *blob)
4494 : {
4495 0 : int ret;
4496 0 : TALLOC_CTX *frame = talloc_stackframe();
4497 : /* Initialise this to zero, in a portable way */
4498 0 : struct smb_acl_wrapper acl_wrapper = {
4499 : 0
4500 : };
4501 0 : struct smb_filename *smb_fname = cp_smb_filename_nostream(frame,
4502 : smb_fname_in);
4503 0 : if (smb_fname == NULL) {
4504 0 : TALLOC_FREE(frame);
4505 0 : errno = ENOMEM;
4506 0 : return -1;
4507 : }
4508 :
4509 0 : ret = smb_vfs_call_stat(handle, smb_fname);
4510 0 : if (ret == -1) {
4511 0 : TALLOC_FREE(frame);
4512 0 : return -1;
4513 : }
4514 :
4515 0 : acl_wrapper.owner = smb_fname->st.st_ex_uid;
4516 0 : acl_wrapper.group = smb_fname->st.st_ex_gid;
4517 0 : acl_wrapper.mode = smb_fname->st.st_ex_mode;
4518 :
4519 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4520 : &acl_wrapper,
4521 : (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4522 0 : errno = EINVAL;
4523 0 : TALLOC_FREE(frame);
4524 0 : return -1;
4525 : }
4526 :
4527 0 : *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4528 0 : if (!*blob_description) {
4529 0 : errno = EINVAL;
4530 0 : TALLOC_FREE(frame);
4531 0 : return -1;
4532 : }
4533 :
4534 0 : TALLOC_FREE(frame);
4535 0 : return 0;
4536 : }
4537 :
4538 913158 : int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
4539 : files_struct *fsp,
4540 : TALLOC_CTX *mem_ctx,
4541 : char **blob_description,
4542 : DATA_BLOB *blob)
4543 : {
4544 1524 : SMB_STRUCT_STAT sbuf;
4545 1524 : TALLOC_CTX *frame;
4546 913158 : struct smb_acl_wrapper acl_wrapper = { 0 };
4547 1524 : int ret;
4548 :
4549 913158 : frame = talloc_stackframe();
4550 :
4551 913158 : acl_wrapper.access_acl = smb_vfs_call_sys_acl_get_fd(handle,
4552 : fsp,
4553 : SMB_ACL_TYPE_ACCESS,
4554 : frame);
4555 :
4556 913158 : if (fsp->fsp_flags.is_directory) {
4557 468581 : acl_wrapper.default_acl = smb_vfs_call_sys_acl_get_fd(handle,
4558 : fsp,
4559 : SMB_ACL_TYPE_DEFAULT,
4560 : frame);
4561 : }
4562 :
4563 913158 : ret = smb_vfs_call_fstat(handle, fsp, &sbuf);
4564 913158 : if (ret == -1) {
4565 0 : TALLOC_FREE(frame);
4566 0 : return -1;
4567 : }
4568 :
4569 913158 : acl_wrapper.owner = sbuf.st_ex_uid;
4570 913158 : acl_wrapper.group = sbuf.st_ex_gid;
4571 913158 : acl_wrapper.mode = sbuf.st_ex_mode;
4572 :
4573 913158 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4574 : &acl_wrapper,
4575 : (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4576 0 : errno = EINVAL;
4577 0 : TALLOC_FREE(frame);
4578 0 : return -1;
4579 : }
4580 :
4581 913158 : *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4582 913158 : if (!*blob_description) {
4583 0 : errno = EINVAL;
4584 0 : TALLOC_FREE(frame);
4585 0 : return -1;
4586 : }
4587 :
4588 913158 : TALLOC_FREE(frame);
4589 911634 : return 0;
4590 : }
4591 :
4592 172 : static NTSTATUS make_default_acl_posix(TALLOC_CTX *ctx,
4593 : const char *name,
4594 : const SMB_STRUCT_STAT *psbuf,
4595 : struct security_descriptor **ppdesc)
4596 : {
4597 0 : struct dom_sid owner_sid, group_sid;
4598 172 : size_t size = 0;
4599 0 : struct security_ace aces[4];
4600 172 : uint32_t access_mask = 0;
4601 172 : mode_t mode = psbuf->st_ex_mode;
4602 172 : struct security_acl *new_dacl = NULL;
4603 172 : int idx = 0;
4604 :
4605 172 : DBG_DEBUG("file %s mode = 0%o\n",name, (int)mode);
4606 :
4607 172 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4608 172 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4609 :
4610 : /*
4611 : We provide up to 4 ACEs
4612 : - Owner
4613 : - Group
4614 : - Everyone
4615 : - NT System
4616 : */
4617 :
4618 172 : if (mode & S_IRUSR) {
4619 172 : if (mode & S_IWUSR) {
4620 172 : access_mask |= SEC_RIGHTS_FILE_ALL;
4621 : } else {
4622 0 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4623 : }
4624 : }
4625 172 : if (mode & S_IWUSR) {
4626 172 : access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4627 : }
4628 :
4629 172 : init_sec_ace(&aces[idx],
4630 : &owner_sid,
4631 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4632 : access_mask,
4633 : 0);
4634 172 : idx++;
4635 :
4636 172 : access_mask = 0;
4637 172 : if (mode & S_IRGRP) {
4638 172 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4639 : }
4640 172 : if (mode & S_IWGRP) {
4641 : /* note that delete is not granted - this matches posix behaviour */
4642 172 : access_mask |= SEC_RIGHTS_FILE_WRITE;
4643 : }
4644 172 : if (access_mask) {
4645 172 : init_sec_ace(&aces[idx],
4646 : &group_sid,
4647 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4648 : access_mask,
4649 : 0);
4650 172 : idx++;
4651 : }
4652 :
4653 172 : access_mask = 0;
4654 172 : if (mode & S_IROTH) {
4655 172 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4656 : }
4657 172 : if (mode & S_IWOTH) {
4658 172 : access_mask |= SEC_RIGHTS_FILE_WRITE;
4659 : }
4660 172 : if (access_mask) {
4661 172 : init_sec_ace(&aces[idx],
4662 : &global_sid_World,
4663 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4664 : access_mask,
4665 : 0);
4666 172 : idx++;
4667 : }
4668 :
4669 172 : init_sec_ace(&aces[idx],
4670 : &global_sid_System,
4671 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4672 : SEC_RIGHTS_FILE_ALL,
4673 : 0);
4674 172 : idx++;
4675 :
4676 172 : new_dacl = make_sec_acl(ctx,
4677 : NT4_ACL_REVISION,
4678 : idx,
4679 : aces);
4680 :
4681 172 : if (!new_dacl) {
4682 0 : return NT_STATUS_NO_MEMORY;
4683 : }
4684 :
4685 172 : *ppdesc = make_sec_desc(ctx,
4686 : SECURITY_DESCRIPTOR_REVISION_1,
4687 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4688 : &owner_sid,
4689 : &group_sid,
4690 : NULL,
4691 : new_dacl,
4692 : &size);
4693 172 : if (!*ppdesc) {
4694 0 : return NT_STATUS_NO_MEMORY;
4695 : }
4696 172 : return NT_STATUS_OK;
4697 : }
4698 :
4699 114 : static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
4700 : const char *name,
4701 : const SMB_STRUCT_STAT *psbuf,
4702 : struct security_descriptor **ppdesc)
4703 : {
4704 0 : struct dom_sid owner_sid, group_sid;
4705 114 : size_t size = 0;
4706 0 : struct security_ace aces[4];
4707 114 : uint32_t access_mask = 0;
4708 114 : mode_t mode = psbuf->st_ex_mode;
4709 114 : struct security_acl *new_dacl = NULL;
4710 114 : int idx = 0;
4711 :
4712 114 : DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
4713 :
4714 114 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4715 114 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4716 :
4717 : /*
4718 : * We provide 2 ACEs:
4719 : * - Owner
4720 : * - NT System
4721 : */
4722 :
4723 114 : if (mode & S_IRUSR) {
4724 114 : if (mode & S_IWUSR) {
4725 114 : access_mask |= SEC_RIGHTS_FILE_ALL;
4726 : } else {
4727 0 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4728 : }
4729 : }
4730 114 : if (mode & S_IWUSR) {
4731 114 : access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4732 : }
4733 :
4734 114 : init_sec_ace(&aces[idx],
4735 : &owner_sid,
4736 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4737 : access_mask,
4738 : 0);
4739 114 : idx++;
4740 :
4741 114 : init_sec_ace(&aces[idx],
4742 : &global_sid_System,
4743 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4744 : SEC_RIGHTS_FILE_ALL,
4745 : 0);
4746 114 : idx++;
4747 :
4748 114 : new_dacl = make_sec_acl(ctx,
4749 : NT4_ACL_REVISION,
4750 : idx,
4751 : aces);
4752 :
4753 114 : if (!new_dacl) {
4754 0 : return NT_STATUS_NO_MEMORY;
4755 : }
4756 :
4757 114 : *ppdesc = make_sec_desc(ctx,
4758 : SECURITY_DESCRIPTOR_REVISION_1,
4759 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4760 : &owner_sid,
4761 : &group_sid,
4762 : NULL,
4763 : new_dacl,
4764 : &size);
4765 114 : if (!*ppdesc) {
4766 0 : return NT_STATUS_NO_MEMORY;
4767 : }
4768 114 : return NT_STATUS_OK;
4769 : }
4770 :
4771 3220 : static NTSTATUS make_default_acl_everyone(TALLOC_CTX *ctx,
4772 : const char *name,
4773 : const SMB_STRUCT_STAT *psbuf,
4774 : struct security_descriptor **ppdesc)
4775 : {
4776 0 : struct dom_sid owner_sid, group_sid;
4777 3220 : size_t size = 0;
4778 0 : struct security_ace aces[1];
4779 3220 : mode_t mode = psbuf->st_ex_mode;
4780 3220 : struct security_acl *new_dacl = NULL;
4781 3220 : int idx = 0;
4782 :
4783 3220 : DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
4784 :
4785 3220 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4786 3220 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4787 :
4788 : /*
4789 : * We provide one ACEs: full access for everyone
4790 : */
4791 :
4792 3220 : init_sec_ace(&aces[idx],
4793 : &global_sid_World,
4794 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4795 : SEC_RIGHTS_FILE_ALL,
4796 : 0);
4797 3220 : idx++;
4798 :
4799 3220 : new_dacl = make_sec_acl(ctx,
4800 : NT4_ACL_REVISION,
4801 : idx,
4802 : aces);
4803 :
4804 3220 : if (!new_dacl) {
4805 0 : return NT_STATUS_NO_MEMORY;
4806 : }
4807 :
4808 3220 : *ppdesc = make_sec_desc(ctx,
4809 : SECURITY_DESCRIPTOR_REVISION_1,
4810 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4811 : &owner_sid,
4812 : &group_sid,
4813 : NULL,
4814 : new_dacl,
4815 : &size);
4816 3220 : if (!*ppdesc) {
4817 0 : return NT_STATUS_NO_MEMORY;
4818 : }
4819 3220 : return NT_STATUS_OK;
4820 : }
4821 :
4822 : static const struct enum_list default_acl_style_list[] = {
4823 : {DEFAULT_ACL_POSIX, "posix"},
4824 : {DEFAULT_ACL_WINDOWS, "windows"},
4825 : {DEFAULT_ACL_EVERYONE, "everyone"},
4826 : };
4827 :
4828 53654 : const struct enum_list *get_default_acl_style_list(void)
4829 : {
4830 53654 : return default_acl_style_list;
4831 : }
4832 :
4833 3506 : NTSTATUS make_default_filesystem_acl(
4834 : TALLOC_CTX *ctx,
4835 : enum default_acl_style acl_style,
4836 : const char *name,
4837 : const SMB_STRUCT_STAT *psbuf,
4838 : struct security_descriptor **ppdesc)
4839 : {
4840 0 : NTSTATUS status;
4841 :
4842 3506 : switch (acl_style) {
4843 172 : case DEFAULT_ACL_POSIX:
4844 172 : status = make_default_acl_posix(ctx, name, psbuf, ppdesc);
4845 172 : break;
4846 :
4847 114 : case DEFAULT_ACL_WINDOWS:
4848 114 : status = make_default_acl_windows(ctx, name, psbuf, ppdesc);
4849 114 : break;
4850 :
4851 3220 : case DEFAULT_ACL_EVERYONE:
4852 3220 : status = make_default_acl_everyone(ctx, name, psbuf, ppdesc);
4853 3220 : break;
4854 :
4855 0 : default:
4856 0 : DBG_ERR("unknown acl style %d\n", acl_style);
4857 0 : status = NT_STATUS_INTERNAL_ERROR;
4858 0 : break;
4859 : }
4860 :
4861 3506 : return status;
4862 : }
|