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 : 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 149785 : 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 : int ret;
264 : size_t store_size;
265 : char *pai_buf;
266 :
267 149785 : if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
268 149785 : 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 431543 : static void free_inherited_info(struct pai_val *pal)
293 : {
294 431543 : if (pal) {
295 : 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 431543 : }
307 :
308 : /************************************************************************
309 : Get any stored ACE flags.
310 : ************************************************************************/
311 :
312 1171164 : static uint16_t get_pai_flags(struct pai_val *pal, canon_ace *ace_entry, bool default_ace)
313 : {
314 : struct pai_entry *paie;
315 :
316 1171164 : if (!pal) {
317 1167938 : 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 : uint16_t num_entries;
336 : 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 : uint16_t num_entries;
368 : 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 : 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 : 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 : 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 : 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 431543 : static struct pai_val *fload_inherited_info(files_struct *fsp)
606 : {
607 : char *pai_buf;
608 431543 : size_t pai_buf_size = 1024;
609 431543 : struct pai_val *paiv = NULL;
610 : ssize_t ret;
611 :
612 431543 : if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
613 430555 : 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 : 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 1441128 : static size_t count_canon_ace_list( canon_ace *l_head )
674 : {
675 1443426 : size_t count = 0;
676 : canon_ace *ace;
677 :
678 5320628 : for (ace = l_head; ace; ace = ace->next)
679 3877202 : count++;
680 :
681 1441128 : return count;
682 : }
683 :
684 : /****************************************************************************
685 : Free a linked list of canonical ACE entries.
686 : ****************************************************************************/
687 :
688 1162708 : static void free_canon_ace_list( canon_ace *l_head )
689 : {
690 : canon_ace *list, *next;
691 :
692 3741572 : for (list = l_head; list; list = next) {
693 2578864 : next = list->next;
694 2578864 : DLIST_REMOVE(l_head, list);
695 2578864 : TALLOC_FREE(list);
696 : }
697 1162708 : }
698 :
699 : /****************************************************************************
700 : Function to duplicate a canon_ace entry.
701 : ****************************************************************************/
702 :
703 36554 : static canon_ace *dup_canon_ace( canon_ace *src_ace)
704 : {
705 36554 : canon_ace *dst_ace = talloc(talloc_tos(), canon_ace);
706 :
707 36554 : if (dst_ace == NULL)
708 0 : return NULL;
709 :
710 36554 : *dst_ace = *src_ace;
711 36554 : dst_ace->prev = dst_ace->next = NULL;
712 36554 : 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 : 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 1642091 : static void print_canon_ace_list(const char *name, canon_ace *ace_list)
763 : {
764 1642091 : int count = 0;
765 :
766 1642091 : 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 1642091 : }
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 1336998 : static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
778 : {
779 1336998 : mode_t ret = 0;
780 :
781 1336998 : ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
782 1336998 : ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
783 1336998 : ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
784 :
785 1336998 : 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 547890 : mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
793 : {
794 547890 : mode_t ret = 0;
795 :
796 547890 : if (mode & r_mask)
797 547624 : ret |= S_IRUSR;
798 547890 : if (mode & w_mask)
799 258997 : ret |= S_IWUSR;
800 547890 : if (mode & x_mask)
801 534854 : ret |= S_IXUSR;
802 :
803 547890 : 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 1024252 : int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
812 : {
813 1024252 : if (sys_acl_clear_perms(*p_permset) == -1)
814 0 : return -1;
815 1024252 : if (mode & S_IRUSR) {
816 996052 : if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
817 0 : return -1;
818 : }
819 1024252 : if (mode & S_IWUSR) {
820 519309 : if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
821 0 : return -1;
822 : }
823 1024252 : if (mode & S_IXUSR) {
824 990640 : if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
825 0 : return -1;
826 : }
827 1020100 : return 0;
828 : }
829 :
830 : /****************************************************************************
831 : Function to create owner and group SIDs from a SMB_STRUCT_STAT.
832 : ****************************************************************************/
833 :
834 582165 : static void create_file_sids(const SMB_STRUCT_STAT *psbuf,
835 : struct dom_sid *powner_sid,
836 : struct dom_sid *pgroup_sid)
837 : {
838 583475 : uid_to_sid( powner_sid, psbuf->st_ex_uid );
839 583475 : gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
840 582165 : }
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 299570 : static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
849 : {
850 299570 : canon_ace *l_head = *pp_list_head;
851 : canon_ace *curr_ace_outer;
852 : 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 879133 : for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
860 : canon_ace *curr_ace;
861 : canon_ace *curr_ace_next;
862 :
863 578919 : curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
864 :
865 1504866 : for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
866 923234 : bool can_merge = false;
867 :
868 923234 : 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 923234 : if (!dir_acl) {
879 1379630 : can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
880 774668 : curr_ace->owner_type == curr_ace_outer->owner_type &&
881 3320 : (curr_ace->attr == curr_ace_outer->attr));
882 : } else {
883 281671 : can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
884 20598 : curr_ace->owner_type == curr_ace_outer->owner_type &&
885 160884 : (curr_ace->type == curr_ace_outer->type) &&
886 1840 : (curr_ace->attr == curr_ace_outer->attr));
887 : }
888 :
889 923234 : if (can_merge) {
890 5152 : 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 5152 : curr_ace_outer->perms |= curr_ace->perms;
904 5152 : curr_ace_outer->ace_flags |= curr_ace->ace_flags;
905 5152 : DLIST_REMOVE(l_head, curr_ace);
906 5152 : TALLOC_FREE(curr_ace);
907 5152 : 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 878489 : for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
919 : canon_ace *curr_ace;
920 : canon_ace *curr_ace_next;
921 :
922 578919 : curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
923 :
924 1497000 : for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
925 :
926 915376 : 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 968916 : if (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
934 91575 : (curr_ace->owner_type == curr_ace_outer->owner_type) &&
935 1658 : (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 guarenteed 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 299570 : *pp_list_head = l_head;
979 299570 : }
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 1862118 : 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 1862118 : uint32_t nt_mask = 0;
993 :
994 1862118 : *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
995 :
996 1862118 : if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
997 1384785 : if (directory_ace) {
998 252413 : nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
999 : } else {
1000 500735 : nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS);
1001 : }
1002 1106416 : } 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 32399 : nt_mask = 0;
1013 : } else {
1014 1073797 : if (directory_ace) {
1015 179823 : nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
1016 179823 : nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
1017 179823 : nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
1018 : } else {
1019 893974 : nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
1020 893974 : nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
1021 893974 : nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
1022 : }
1023 : }
1024 :
1025 1862118 : if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
1026 791441 : nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
1027 : }
1028 :
1029 1862118 : DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
1030 : (unsigned int)perms, (unsigned int)nt_mask ));
1031 :
1032 1862118 : 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 547865 : static mode_t map_nt_perms( uint32_t *mask, int type)
1044 : {
1045 549883 : mode_t mode = 0;
1046 :
1047 547865 : switch(type) {
1048 547865 : case S_IRUSR:
1049 549883 : if((*mask) & GENERIC_ALL_ACCESS)
1050 0 : mode = S_IRUSR|S_IWUSR|S_IXUSR;
1051 : else {
1052 549883 : mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
1053 549883 : mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
1054 549883 : mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
1055 : }
1056 547865 : 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 547865 : return mode;
1078 : }
1079 :
1080 : /****************************************************************************
1081 : Unpack a struct security_descriptor into a UNIX owner and group.
1082 : ****************************************************************************/
1083 :
1084 156946 : NTSTATUS unpack_nt_owners(struct connection_struct *conn,
1085 : uid_t *puser, gid_t *pgrp,
1086 : uint32_t security_info_sent, const struct
1087 : security_descriptor *psd)
1088 : {
1089 156946 : *puser = (uid_t)-1;
1090 156946 : *pgrp = (gid_t)-1;
1091 :
1092 156946 : 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 156938 : 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 156938 : if (security_info_sent & SECINFO_OWNER) {
1109 148269 : if (!sid_to_uid(psd->owner_sid, puser)) {
1110 554 : if (lp_force_unknown_acl_user(SNUM(conn))) {
1111 : /* this allows take ownership to work
1112 : * reasonably */
1113 554 : *puser = get_current_uid(conn);
1114 : } else {
1115 : 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 148269 : 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 156938 : if (security_info_sent & SECINFO_GROUP) {
1133 145795 : if (!sid_to_gid(psd->group_sid, pgrp)) {
1134 2 : if (lp_force_unknown_acl_user(SNUM(conn))) {
1135 : /* this allows take group ownership to work
1136 : * reasonably */
1137 2 : *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 145795 : DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
1145 : (unsigned int)*pgrp));
1146 : }
1147 :
1148 156938 : DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
1149 :
1150 156938 : return NT_STATUS_OK;
1151 : }
1152 :
1153 :
1154 576198 : static void trim_ace_perms(canon_ace *pace)
1155 : {
1156 578911 : pace->perms = pace->perms & (S_IXUSR|S_IWUSR|S_IRUSR);
1157 576198 : }
1158 :
1159 161469 : static void ensure_minimal_owner_ace_perms(const bool is_directory,
1160 : canon_ace *pace)
1161 : {
1162 161941 : pace->perms |= S_IRUSR;
1163 161941 : if (is_directory) {
1164 24633 : pace->perms |= (S_IWUSR|S_IXUSR);
1165 : }
1166 161469 : }
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 8277 : static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, canon_ace *group_ace )
1174 : {
1175 8277 : bool is_sid = false;
1176 8277 : bool has_sid = false;
1177 8277 : struct security_token *security_token = NULL;
1178 :
1179 : /* "Everyone" always matches every uid. */
1180 :
1181 8277 : if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
1182 0 : return True;
1183 :
1184 8277 : security_token = conn->session_info->security_token;
1185 : /* security_token should not be NULL */
1186 8277 : SMB_ASSERT(security_token);
1187 8277 : is_sid = security_token_is_sid(security_token,
1188 8277 : &uid_ace->trustee);
1189 8277 : if (is_sid) {
1190 5830 : has_sid = security_token_has_sid(security_token,
1191 5390 : &group_ace->trustee);
1192 :
1193 5830 : if (has_sid) {
1194 2728 : 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 5329 : if (uid_ace->unix_ug.id == get_current_uid(conn)) {
1203 570 : const struct security_unix_token *curr_utok = NULL;
1204 : size_t i;
1205 :
1206 570 : if (group_ace->unix_ug.id == get_current_gid(conn)) {
1207 0 : return True;
1208 : }
1209 :
1210 570 : curr_utok = get_current_utok(conn);
1211 584 : for (i=0; i < curr_utok->ngroups; i++) {
1212 14 : 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 5329 : 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 443811 : 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 : canon_ace *pace;
1242 443811 : bool got_user = false;
1243 443811 : bool got_group = false;
1244 443811 : bool got_other = false;
1245 :
1246 1614975 : for (pace = *pp_ace; pace; pace = pace->next) {
1247 1171164 : if (pace->type == SMB_ACL_USER_OBJ) {
1248 261580 : got_user = true;
1249 909150 : } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1250 261580 : got_group = true;
1251 647136 : } else if (pace->type == SMB_ACL_OTHER) {
1252 262014 : got_other = true;
1253 : }
1254 : }
1255 :
1256 443811 : if (!got_user) {
1257 181797 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1258 0 : DEBUG(0,("malloc fail.\n"));
1259 0 : return false;
1260 : }
1261 :
1262 181797 : ZERO_STRUCTP(pace);
1263 181797 : pace->type = SMB_ACL_USER_OBJ;
1264 181797 : pace->owner_type = UID_ACE;
1265 181797 : pace->unix_ug.type = ID_TYPE_UID;
1266 181797 : pace->unix_ug.id = pst->st_ex_uid;
1267 181797 : pace->trustee = *pfile_owner_sid;
1268 181797 : pace->attr = ALLOW_ACE;
1269 181797 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1270 181797 : DLIST_ADD(*pp_ace, pace);
1271 : }
1272 :
1273 443811 : if (!got_group) {
1274 181797 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1275 0 : DEBUG(0,("malloc fail.\n"));
1276 0 : return false;
1277 : }
1278 :
1279 181797 : ZERO_STRUCTP(pace);
1280 181797 : pace->type = SMB_ACL_GROUP_OBJ;
1281 181797 : pace->owner_type = GID_ACE;
1282 181797 : pace->unix_ug.type = ID_TYPE_GID;
1283 181797 : pace->unix_ug.id = pst->st_ex_gid;
1284 181797 : pace->trustee = *pfile_grp_sid;
1285 181797 : pace->attr = ALLOW_ACE;
1286 181797 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1287 181797 : DLIST_ADD(*pp_ace, pace);
1288 : }
1289 :
1290 443811 : if (!got_other) {
1291 181797 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1292 0 : DEBUG(0,("malloc fail.\n"));
1293 0 : return false;
1294 : }
1295 :
1296 181797 : ZERO_STRUCTP(pace);
1297 181797 : pace->type = SMB_ACL_OTHER;
1298 181797 : pace->owner_type = WORLD_ACE;
1299 181797 : pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1300 181797 : pace->unix_ug.id = -1;
1301 181797 : pace->trustee = global_sid_World;
1302 181797 : pace->attr = ALLOW_ACE;
1303 181797 : pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
1304 181797 : DLIST_ADD(*pp_ace, pace);
1305 : }
1306 :
1307 442690 : 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 161941 : 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 : canon_ace *pace;
1329 161941 : canon_ace *pace_user = NULL;
1330 161941 : canon_ace *pace_group = NULL;
1331 161941 : canon_ace *pace_other = NULL;
1332 161941 : bool got_duplicate_user = false;
1333 161941 : bool got_duplicate_group = false;
1334 :
1335 740852 : for (pace = *pp_ace; pace; pace = pace->next) {
1336 578911 : trim_ace_perms(pace);
1337 578911 : if (pace->type == SMB_ACL_USER_OBJ) {
1338 159114 : ensure_minimal_owner_ace_perms(is_directory, pace);
1339 159114 : pace_user = pace;
1340 419445 : } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1341 152036 : pace_group = pace;
1342 267022 : } else if (pace->type == SMB_ACL_OTHER) {
1343 151606 : pace_other = pace;
1344 : }
1345 : }
1346 :
1347 161941 : if (!pace_user) {
1348 : canon_ace *pace_iter;
1349 :
1350 2475 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1351 0 : DEBUG(0,("talloc fail.\n"));
1352 0 : return false;
1353 : }
1354 :
1355 2475 : ZERO_STRUCTP(pace);
1356 2475 : pace->type = SMB_ACL_USER_OBJ;
1357 2475 : pace->owner_type = UID_ACE;
1358 2475 : pace->unix_ug.type = ID_TYPE_UID;
1359 2475 : pace->unix_ug.id = pst->st_ex_uid;
1360 2475 : pace->trustee = *pfile_owner_sid;
1361 2475 : pace->attr = ALLOW_ACE;
1362 : /* Start with existing user permissions, principle of least
1363 : surprises for the user. */
1364 2475 : 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 19539 : for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1373 22543 : if (pace_iter->type == SMB_ACL_USER &&
1374 8240 : pace_iter->unix_ug.id == pace->unix_ug.id) {
1375 415 : pace->perms |= pace_iter->perms;
1376 16649 : } else if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1377 8582 : if (dom_sid_equal(&pace->trustee, &pace_iter->trustee)) {
1378 313 : pace->perms |= pace_iter->perms;
1379 8269 : } else if (uid_entry_in_group(conn, pace, pace_iter)) {
1380 3344 : pace->perms |= pace_iter->perms;
1381 : }
1382 : }
1383 : }
1384 :
1385 2475 : 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 2475 : ensure_minimal_owner_ace_perms(is_directory, pace);
1396 :
1397 2475 : DLIST_ADD(*pp_ace, pace);
1398 2355 : pace_user = pace;
1399 : }
1400 :
1401 161941 : if (!pace_group) {
1402 9518 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1403 0 : DEBUG(0,("talloc fail.\n"));
1404 0 : return false;
1405 : }
1406 :
1407 9518 : ZERO_STRUCTP(pace);
1408 9518 : pace->type = SMB_ACL_GROUP_OBJ;
1409 9518 : pace->owner_type = GID_ACE;
1410 9518 : pace->unix_ug.type = ID_TYPE_GID;
1411 9518 : pace->unix_ug.id = pst->st_ex_gid;
1412 9518 : pace->trustee = *pfile_grp_sid;
1413 9518 : pace->attr = ALLOW_ACE;
1414 :
1415 : /* If we only got an "everyone" perm, just use that. */
1416 9518 : if (pace_other) {
1417 1116 : pace->perms = pace_other->perms;
1418 : } else {
1419 8402 : pace->perms = 0;
1420 : }
1421 :
1422 9518 : DLIST_ADD(*pp_ace, pace);
1423 9433 : pace_group = pace;
1424 : }
1425 :
1426 161941 : if (!pace_other) {
1427 10335 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1428 0 : DEBUG(0,("talloc fail.\n"));
1429 0 : return false;
1430 : }
1431 :
1432 10335 : ZERO_STRUCTP(pace);
1433 10335 : pace->type = SMB_ACL_OTHER;
1434 10335 : pace->owner_type = WORLD_ACE;
1435 10335 : pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1436 10335 : pace->unix_ug.id = -1;
1437 10335 : pace->trustee = global_sid_World;
1438 10335 : pace->attr = ALLOW_ACE;
1439 10335 : pace->perms = 0;
1440 :
1441 10335 : DLIST_ADD(*pp_ace, pace);
1442 10145 : 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 763180 : for (pace = *pp_ace; pace; pace = pace->next) {
1455 622778 : if (pace->type == SMB_ACL_USER &&
1456 28961 : pace->unix_ug.id == pace_user->unix_ug.id) {
1457 : /* Already got one. */
1458 2026 : got_duplicate_user = true;
1459 649947 : } else if (pace->type == SMB_ACL_GROUP &&
1460 86455 : pace->unix_ug.id == pace_group->unix_ug.id) {
1461 : /* Already got one. */
1462 1506 : got_duplicate_group = true;
1463 597592 : } else if ((pace->type == SMB_ACL_GROUP)
1464 84864 : && (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 58541 : 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 161941 : if (!got_duplicate_user && !got_duplicate_group
1476 100843 : && dom_sid_equal(&pace_group->trustee,
1477 100843 : &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 967 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1484 0 : DEBUG(0,("talloc fail.\n"));
1485 0 : return false;
1486 : }
1487 :
1488 967 : ZERO_STRUCTP(pace);
1489 967 : pace->type = SMB_ACL_GROUP;;
1490 967 : pace->owner_type = GID_ACE;
1491 967 : pace->unix_ug.type = ID_TYPE_GID;
1492 967 : pace->unix_ug.id = pace_group->unix_ug.id;
1493 967 : pace->trustee = pace_group->trustee;
1494 967 : pace->attr = pace_group->attr;
1495 967 : pace->perms = pace_group->perms;
1496 :
1497 967 : DLIST_ADD(*pp_ace, pace);
1498 :
1499 : /* We're done here, make sure the
1500 : statements below are not executed. */
1501 927 : got_duplicate_user = true;
1502 927 : got_duplicate_group = true;
1503 : }
1504 :
1505 161941 : if (!got_duplicate_user) {
1506 : /* Add a duplicate SMB_ACL_USER entry. */
1507 100690 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1508 0 : DEBUG(0,("talloc fail.\n"));
1509 0 : return false;
1510 : }
1511 :
1512 100690 : ZERO_STRUCTP(pace);
1513 100690 : pace->type = SMB_ACL_USER;;
1514 100690 : pace->owner_type = UID_ACE;
1515 100690 : pace->unix_ug.type = ID_TYPE_UID;
1516 100690 : pace->unix_ug.id = pace_user->unix_ug.id;
1517 100690 : pace->trustee = pace_user->trustee;
1518 100690 : pace->attr = pace_user->attr;
1519 100690 : pace->perms = pace_user->perms;
1520 :
1521 100690 : DLIST_ADD(*pp_ace, pace);
1522 :
1523 100505 : got_duplicate_user = true;
1524 : }
1525 :
1526 161941 : if (!got_duplicate_group) {
1527 : /* Add a duplicate SMB_ACL_GROUP entry. */
1528 159383 : if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1529 0 : DEBUG(0,("talloc fail.\n"));
1530 0 : return false;
1531 : }
1532 :
1533 159383 : ZERO_STRUCTP(pace);
1534 159383 : pace->type = SMB_ACL_GROUP;;
1535 159383 : pace->owner_type = GID_ACE;
1536 159383 : pace->unix_ug.type = ID_TYPE_GID;
1537 159383 : pace->unix_ug.id = pace_group->unix_ug.id;
1538 159383 : pace->trustee = pace_group->trustee;
1539 159383 : pace->attr = pace_group->attr;
1540 159383 : pace->perms = pace_group->perms;
1541 :
1542 159383 : DLIST_ADD(*pp_ace, pace);
1543 :
1544 159036 : got_duplicate_group = true;
1545 : }
1546 :
1547 161469 : 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 149785 : static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
1558 : {
1559 : bool got_user_obj, got_group_obj;
1560 : canon_ace *current_ace;
1561 : int i, entries;
1562 :
1563 149785 : entries = count_canon_ace_list(ace);
1564 149785 : got_user_obj = False;
1565 149785 : got_group_obj = False;
1566 :
1567 677021 : for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1568 527236 : if (current_ace->type == SMB_ACL_USER_OBJ)
1569 149621 : got_user_obj = True;
1570 377318 : else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1571 144118 : got_group_obj = True;
1572 : }
1573 149785 : if (got_user_obj && got_group_obj) {
1574 142145 : DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1575 141888 : return;
1576 : }
1577 :
1578 43281 : for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1579 39530 : if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1580 3824 : 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 48056 : if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1585 12350 : 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 7640 : if (!got_user_obj)
1591 1222 : DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1592 7640 : if (!got_group_obj)
1593 6634 : DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1594 : }
1595 :
1596 549883 : 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 551901 : current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
1609 549883 : current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1610 :
1611 : /* Store the ace_flag. */
1612 549883 : 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 549883 : 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 81348 : 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 56835 : canon_ace *current_dir_ace = current_ace;
1631 56835 : 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 56835 : if (current_ace->attr == ALLOW_ACE)
1639 56835 : *got_dir_allow = True;
1640 :
1641 56835 : 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 56835 : 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 56835 : if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1662 36554 : canon_ace *dup_ace = dup_canon_ace(current_ace);
1663 :
1664 36554 : 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 36554 : 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 36554 : 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 20121 : 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 56835 : 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 24851 : if (dom_sid_equal(¤t_dir_ace->trustee,
1704 : &global_sid_Creator_Owner)) {
1705 10903 : current_dir_ace->type = SMB_ACL_USER_OBJ;
1706 : } else {
1707 13948 : current_dir_ace->type = SMB_ACL_USER;
1708 : }
1709 : }
1710 :
1711 56835 : 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 22468 : if (dom_sid_equal(¤t_dir_ace->trustee,
1719 : &global_sid_Creator_Group)) {
1720 9272 : current_dir_ace->type = SMB_ACL_GROUP_OBJ;
1721 : } else {
1722 13196 : 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 549883 : if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1733 527266 : 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 527266 : if (current_ace->attr == ALLOW_ACE)
1741 527238 : *got_file_allow = True;
1742 :
1743 527266 : 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 527256 : 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 527256 : *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 527256 : current_ace = NULL;
1761 : }
1762 :
1763 : /*
1764 : * Free if ACE was not added.
1765 : */
1766 :
1767 548025 : TALLOC_FREE(current_ace);
1768 547855 : return true;
1769 : }
1770 :
1771 : /****************************************************************************
1772 : Unpack a struct security_descriptor into two canonical ace lists.
1773 : ****************************************************************************/
1774 :
1775 149840 : 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 149840 : bool all_aces_are_inherit_only = (fsp->fsp_flags.is_directory);
1784 149840 : canon_ace *file_ace = NULL;
1785 149840 : canon_ace *dir_ace = NULL;
1786 149840 : canon_ace *current_ace = NULL;
1787 149840 : bool got_dir_allow = False;
1788 149840 : bool got_file_allow = False;
1789 : uint32_t i, j;
1790 :
1791 149840 : *ppfile_ace = NULL;
1792 149840 : *ppdir_ace = NULL;
1793 :
1794 : /*
1795 : * Convert the incoming ACL into a more regular form.
1796 : */
1797 :
1798 623935 : for(i = 0; i < dacl->num_aces; i++) {
1799 474095 : struct security_ace *psa = &dacl->aces[i];
1800 :
1801 474095 : if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1802 0 : DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1803 0 : 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 623935 : for(i = 0; i < dacl->num_aces; i++) {
1816 474095 : struct security_ace *psa1 = &dacl->aces[i];
1817 :
1818 1042996 : for (j = i + 1; j < dacl->num_aces; j++) {
1819 568901 : struct security_ace *psa2 = &dacl->aces[j];
1820 :
1821 568901 : if (psa1->access_mask != psa2->access_mask)
1822 362632 : continue;
1823 :
1824 206269 : if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
1825 202052 : continue;
1826 :
1827 : /*
1828 : * Ok - permission bits and SIDs are equal.
1829 : * Check if flags were re-written.
1830 : */
1831 :
1832 4217 : if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1833 :
1834 1134 : psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1835 1134 : psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1836 :
1837 3083 : } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1838 :
1839 6 : psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1840 6 : psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1841 :
1842 : }
1843 : }
1844 : }
1845 :
1846 623595 : for(i = 0; i < dacl->num_aces; i++) {
1847 474087 : struct security_ace *psa = &dacl->aces[i];
1848 :
1849 : /*
1850 : * Create a canon_ace entry representing this NT DACL ACE.
1851 : */
1852 :
1853 474087 : 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 474087 : ZERO_STRUCTP(current_ace);
1861 :
1862 474087 : 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 474087 : if( dom_sid_equal(¤t_ace->trustee, &global_sid_World)) {
1871 143390 : current_ace->owner_type = WORLD_ACE;
1872 143390 : current_ace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1873 143390 : current_ace->unix_ug.id = -1;
1874 143390 : current_ace->type = SMB_ACL_OTHER;
1875 330697 : } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
1876 12235 : current_ace->owner_type = UID_ACE;
1877 12235 : current_ace->unix_ug.type = ID_TYPE_UID;
1878 12235 : current_ace->unix_ug.id = pst->st_ex_uid;
1879 12235 : 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 12235 : psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1888 :
1889 318462 : } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
1890 10240 : current_ace->owner_type = GID_ACE;
1891 10240 : current_ace->unix_ug.type = ID_TYPE_GID;
1892 10240 : current_ace->unix_ug.id = pst->st_ex_gid;
1893 10240 : 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 10240 : psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1901 :
1902 : } else {
1903 : struct unixid unixid;
1904 :
1905 308222 : if (!sids_to_unixids(¤t_ace->trustee, 1, &unixid)) {
1906 : 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 308222 : 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 76024 : current_ace->owner_type = UID_ACE;
1926 76024 : current_ace->unix_ug.type = ID_TYPE_UID;
1927 76024 : current_ace->unix_ug.id = unixid.id;
1928 76024 : current_ace->type =
1929 76024 : (unixid.id == pst->st_ex_uid) ?
1930 76024 : 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 76024 : 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 76020 : 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 76020 : ZERO_STRUCTP(current_ace);
1961 :
1962 76020 : sid_copy(¤t_ace->trustee, &psa->trustee);
1963 :
1964 76020 : current_ace->unix_ug.type = ID_TYPE_GID;
1965 76020 : current_ace->unix_ug.id = unixid.id;
1966 76020 : current_ace->owner_type = GID_ACE;
1967 : /* If it's the primary group, this is a
1968 : group_obj, not a group. */
1969 76020 : if (current_ace->unix_ug.id == pst->st_ex_gid) {
1970 3030 : current_ace->type = SMB_ACL_GROUP_OBJ;
1971 : } else {
1972 72990 : current_ace->type = SMB_ACL_GROUP;
1973 : }
1974 :
1975 232198 : } else if (unixid.type == ID_TYPE_UID) {
1976 89802 : current_ace->owner_type = UID_ACE;
1977 89802 : current_ace->unix_ug.type = ID_TYPE_UID;
1978 89802 : current_ace->unix_ug.id = unixid.id;
1979 : /* If it's the owning user, this is a user_obj,
1980 : not a user. */
1981 89802 : if (current_ace->unix_ug.id == pst->st_ex_uid) {
1982 89778 : current_ace->type = SMB_ACL_USER_OBJ;
1983 : } else {
1984 24 : current_ace->type = SMB_ACL_USER;
1985 : }
1986 142396 : } else if (unixid.type == ID_TYPE_GID) {
1987 142172 : current_ace->unix_ug.type = ID_TYPE_GID;
1988 142172 : current_ace->unix_ug.id = unixid.id;
1989 142172 : current_ace->owner_type = GID_ACE;
1990 : /* If it's the primary group, this is a
1991 : group_obj, not a group. */
1992 142172 : if (current_ace->unix_ug.id == pst->st_ex_gid) {
1993 141088 : current_ace->type = SMB_ACL_GROUP_OBJ;
1994 : } else {
1995 1084 : current_ace->type = SMB_ACL_GROUP;
1996 : }
1997 : } else {
1998 : struct dom_sid_buf buf;
1999 : /*
2000 : * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
2001 : */
2002 :
2003 224 : 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 232 : continue;
2011 : }
2012 :
2013 216 : if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
2014 216 : DBG_DEBUG("ignoring unknown or "
2015 : "foreign SID %s\n",
2016 : dom_sid_str_buf(
2017 : &psa->trustee,
2018 : &buf));
2019 216 : TALLOC_FREE(current_ace);
2020 216 : 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 473859 : 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 149830 : 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 149814 : if (file_ace) {
2065 149785 : check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
2066 : }
2067 : }
2068 :
2069 149830 : *ppfile_ace = file_ace;
2070 149830 : *ppdir_ace = dir_ace;
2071 :
2072 149508 : 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 preceede 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 choser (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 choser (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 : explaination :-). 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 299570 : static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
2180 : {
2181 299570 : canon_ace *ace_list = *pp_ace_list;
2182 299570 : canon_ace *curr_ace = NULL;
2183 299570 : canon_ace *curr_ace_next = NULL;
2184 :
2185 : /* Pass 1 above - look for an Everyone, deny entry. */
2186 :
2187 879125 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2188 : canon_ace *allow_ace_p;
2189 :
2190 578911 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2191 :
2192 578911 : if (curr_ace->attr != DENY_ACE)
2193 578901 : 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 879127 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2250 578913 : mode_t new_perms = (mode_t)0;
2251 : canon_ace *allow_ace_p;
2252 :
2253 578913 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2254 :
2255 578913 : if (curr_ace->attr != DENY_ACE)
2256 578903 : 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 878485 : for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2301 : canon_ace *allow_ace_p;
2302 578915 : canon_ace *allow_everyone_p = NULL;
2303 :
2304 578915 : curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2305 :
2306 578915 : if (curr_ace->attr != DENY_ACE)
2307 578911 : 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 299570 : *pp_ace_list = ace_list;
2385 299570 : }
2386 :
2387 : /****************************************************************************
2388 : Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
2389 : succeeding.
2390 : ****************************************************************************/
2391 :
2392 151932 : 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 151932 : canon_ace *file_ace = NULL;
2402 151932 : canon_ace *dir_ace = NULL;
2403 : bool ok;
2404 :
2405 151932 : *ppfile_ace = NULL;
2406 151932 : *ppdir_ace = NULL;
2407 :
2408 151932 : 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 151924 : if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
2418 2084 : return True;
2419 :
2420 : /*
2421 : * Now go through the DACL and create the canon_ace lists.
2422 : */
2423 :
2424 149840 : if (!create_canon_ace_lists(fsp, pst, pfile_owner_sid, pfile_grp_sid,
2425 149518 : &file_ace, &dir_ace, psd->dacl)) {
2426 10 : return False;
2427 : }
2428 :
2429 149830 : 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 149785 : print_canon_ace_list( "file ace - before merge", file_ace);
2442 149785 : merge_aces( &file_ace, false);
2443 :
2444 149785 : print_canon_ace_list( "dir ace - before merge", dir_ace);
2445 149785 : 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 149785 : print_canon_ace_list( "file ace - before deny", file_ace);
2453 149785 : process_deny_list(fsp->conn, &file_ace);
2454 :
2455 149785 : print_canon_ace_list( "dir ace - before deny", dir_ace);
2456 149785 : 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 149785 : print_canon_ace_list( "file ace - before valid", file_ace);
2465 :
2466 270340 : ok = ensure_canon_entry_valid_on_set(
2467 149463 : fsp->conn,
2468 : &file_ace,
2469 : false,
2470 149785 : fsp->conn->params,
2471 149785 : fsp->fsp_flags.is_directory,
2472 : pfile_owner_sid,
2473 : pfile_grp_sid,
2474 : pst);
2475 149785 : 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 149785 : print_canon_ace_list( "dir ace - before valid", dir_ace);
2482 :
2483 149785 : if (dir_ace != NULL) {
2484 21953 : ok = ensure_canon_entry_valid_on_set(
2485 12006 : fsp->conn,
2486 : &dir_ace,
2487 : true,
2488 12156 : fsp->conn->params,
2489 12156 : fsp->fsp_flags.is_directory,
2490 : pfile_owner_sid,
2491 : pfile_grp_sid,
2492 : pst);
2493 12156 : 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 149785 : print_canon_ace_list( "file ace - return", file_ace);
2501 149785 : print_canon_ace_list( "dir ace - return", dir_ace);
2502 :
2503 149785 : *ppfile_ace = file_ace;
2504 149785 : *ppdir_ace = dir_ace;
2505 149463 : 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 443811 : static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
2529 : {
2530 443811 : canon_ace *l_head = *pp_list_head;
2531 443811 : canon_ace *owner_ace = NULL;
2532 443811 : canon_ace *other_ace = NULL;
2533 443811 : canon_ace *ace = NULL;
2534 :
2535 2160366 : for (ace = l_head; ace; ace = ace->next) {
2536 1716555 : if (ace->type == SMB_ACL_USER_OBJ)
2537 442690 : owner_ace = ace;
2538 1272744 : else if (ace->type == SMB_ACL_OTHER) {
2539 : /* Last ace - this is "other" */
2540 443811 : other_ace = ace;
2541 : }
2542 : }
2543 :
2544 443811 : 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 443811 : if (owner_ace) {
2556 443811 : DLIST_PROMOTE(l_head, owner_ace);
2557 : }
2558 :
2559 443811 : if (other_ace) {
2560 443811 : DLIST_DEMOTE(l_head, other_ace);
2561 : }
2562 :
2563 : /* We have probably changed the head of the list. */
2564 :
2565 443811 : *pp_list_head = l_head;
2566 : }
2567 :
2568 : /****************************************************************************
2569 : Create a linked list of canonical ACE entries.
2570 : ****************************************************************************/
2571 :
2572 443811 : 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 443811 : mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2578 443811 : canon_ace *l_head = NULL;
2579 443811 : canon_ace *ace = NULL;
2580 443811 : canon_ace *next_ace = NULL;
2581 443811 : int entry_id = SMB_ACL_FIRST_ENTRY;
2582 443811 : bool is_default_acl = (the_acl_type == SMB_ACL_TYPE_DEFAULT);
2583 : SMB_ACL_ENTRY_T entry;
2584 : size_t ace_count;
2585 :
2586 2157195 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2587 : SMB_ACL_TAG_T tagtype;
2588 : SMB_ACL_PERMSET_T permset;
2589 : struct dom_sid sid;
2590 : struct unixid unix_ug;
2591 : enum ace_owner owner_type;
2592 :
2593 1336998 : entry_id = SMB_ACL_NEXT_ENTRY;
2594 :
2595 1336998 : if (sys_acl_get_tag_type(entry, &tagtype) == -1)
2596 165834 : continue;
2597 :
2598 1336998 : if (sys_acl_get_permset(entry, &permset) == -1)
2599 0 : continue;
2600 :
2601 : /* Decide which SID to use based on the ACL type. */
2602 1336998 : switch(tagtype) {
2603 262014 : case SMB_ACL_USER_OBJ:
2604 : /* Get the SID from the owner. */
2605 262014 : sid_copy(&sid, powner);
2606 262014 : unix_ug.type = ID_TYPE_UID;
2607 262014 : unix_ug.id = psbuf->st_ex_uid;
2608 262014 : owner_type = UID_ACE;
2609 261580 : break;
2610 132355 : case SMB_ACL_USER:
2611 : {
2612 132355 : uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2613 132355 : if (puid == NULL) {
2614 0 : DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2615 0 : continue;
2616 : }
2617 132355 : uid_to_sid( &sid, *puid);
2618 132355 : unix_ug.type = ID_TYPE_UID;
2619 132355 : unix_ug.id = *puid;
2620 132355 : owner_type = UID_ACE;
2621 131602 : break;
2622 : }
2623 262014 : case SMB_ACL_GROUP_OBJ:
2624 : /* Get the SID from the owning group. */
2625 262014 : sid_copy(&sid, pgroup);
2626 262014 : unix_ug.type = ID_TYPE_GID;
2627 262014 : unix_ug.id = psbuf->st_ex_gid;
2628 262014 : owner_type = GID_ACE;
2629 261580 : break;
2630 252767 : case SMB_ACL_GROUP:
2631 : {
2632 252767 : gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
2633 252767 : if (pgid == NULL) {
2634 0 : DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2635 0 : continue;
2636 : }
2637 252767 : gid_to_sid( &sid, *pgid);
2638 252767 : unix_ug.type = ID_TYPE_GID;
2639 252767 : unix_ug.id = *pgid;
2640 252767 : owner_type = GID_ACE;
2641 251596 : break;
2642 : }
2643 165834 : case SMB_ACL_MASK:
2644 165834 : acl_mask = convert_permset_to_mode_t(permset);
2645 165834 : continue; /* Don't count the mask as an entry. */
2646 262014 : case SMB_ACL_OTHER:
2647 : /* Use the Everyone SID */
2648 262014 : sid = global_sid_World;
2649 262014 : unix_ug.type = ID_TYPE_NOT_SPECIFIED;
2650 262014 : unix_ug.id = -1;
2651 262014 : owner_type = WORLD_ACE;
2652 261580 : 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 1171164 : if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
2663 0 : goto fail;
2664 :
2665 2342328 : *ace = (canon_ace) {
2666 : .type = tagtype,
2667 1171164 : .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 1171164 : ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
2674 :
2675 1171164 : 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 443811 : 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 443811 : DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", is_default_acl ? "Default" : "Access"));
2693 :
2694 2160366 : for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
2695 1716555 : next_ace = ace->next;
2696 :
2697 : /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2698 1716555 : if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2699 828933 : ace->perms &= acl_mask;
2700 :
2701 1716555 : if (ace->perms == 0) {
2702 32619 : DLIST_PROMOTE(l_head, ace);
2703 : }
2704 :
2705 1716555 : if( DEBUGLVL( 10 ) ) {
2706 0 : print_canon_ace(ace, ace_count);
2707 : }
2708 : }
2709 :
2710 443811 : arrange_posix_perms(fname,&l_head );
2711 :
2712 443811 : print_canon_ace_list( "canonicalise_acl: ace entries after arrange", l_head );
2713 :
2714 443811 : 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 : 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 161941 : 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 161941 : bool ret = False;
2775 161941 : SMB_ACL_T the_acl = sys_acl_init(talloc_tos());
2776 : canon_ace *p_ace;
2777 : int i;
2778 : SMB_ACL_ENTRY_T mask_entry;
2779 161941 : bool got_mask_entry = False;
2780 : SMB_ACL_PERMSET_T mask_permset;
2781 161941 : SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2782 161941 : bool needs_mask = False;
2783 161941 : mode_t mask_perms = 0;
2784 : int sret;
2785 :
2786 : /* Use the psbuf that was passed in. */
2787 161941 : if (psbuf != &fsp->fsp_name->st) {
2788 0 : fsp->fsp_name->st = *psbuf;
2789 : }
2790 :
2791 : #if defined(POSIX_ACL_NEEDS_MASK)
2792 : /* HP-UX always wants to have a mask (called "class" there). */
2793 : needs_mask = True;
2794 : #endif
2795 :
2796 161941 : if (the_acl == NULL) {
2797 0 : DEBUG(0, ("sys_acl_init failed to allocate an ACL\n"));
2798 0 : return false;
2799 : }
2800 :
2801 161941 : if( DEBUGLVL( 10 )) {
2802 0 : dbgtext("set_canon_ace_list: setting ACL:\n");
2803 0 : for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2804 0 : print_canon_ace( p_ace, i);
2805 : }
2806 : }
2807 :
2808 1844854 : for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2809 : SMB_ACL_ENTRY_T the_entry;
2810 : SMB_ACL_PERMSET_T the_permset;
2811 :
2812 : /*
2813 : * ACLs only "need" an ACL_MASK entry if there are any named user or
2814 : * named group entries. But if there is an ACL_MASK entry, it applies
2815 : * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2816 : * so that it doesn't deny (i.e., mask off) any permissions.
2817 : */
2818 :
2819 862279 : if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2820 374192 : needs_mask = True;
2821 374192 : mask_perms |= p_ace->perms;
2822 484407 : } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2823 161469 : mask_perms |= p_ace->perms;
2824 : }
2825 :
2826 : /*
2827 : * Get the entry for this ACE.
2828 : */
2829 :
2830 862279 : if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
2831 0 : DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2832 : i, strerror(errno) ));
2833 0 : goto fail;
2834 : }
2835 :
2836 862279 : if (p_ace->type == SMB_ACL_MASK) {
2837 0 : mask_entry = the_entry;
2838 0 : got_mask_entry = True;
2839 : }
2840 :
2841 : /*
2842 : * Ok - we now know the ACL calls should be working, don't
2843 : * allow fallback to chmod.
2844 : */
2845 :
2846 862279 : *pacl_set_support = True;
2847 :
2848 : /*
2849 : * Initialise the entry from the canon_ace.
2850 : */
2851 :
2852 : /*
2853 : * First tell the entry what type of ACE this is.
2854 : */
2855 :
2856 862279 : if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
2857 0 : DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2858 : i, strerror(errno) ));
2859 0 : goto fail;
2860 : }
2861 :
2862 : /*
2863 : * Only set the qualifier (user or group id) if the entry is a user
2864 : * or group id ACE.
2865 : */
2866 :
2867 862279 : if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2868 376456 : if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.id) == -1) {
2869 0 : DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2870 : i, strerror(errno) ));
2871 0 : goto fail;
2872 : }
2873 : }
2874 :
2875 : /*
2876 : * Convert the mode_t perms in the canon_ace to a POSIX permset.
2877 : */
2878 :
2879 862279 : if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
2880 0 : DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2881 : i, strerror(errno) ));
2882 0 : goto fail;
2883 : }
2884 :
2885 862279 : if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
2886 0 : DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2887 : (unsigned int)p_ace->perms, i, strerror(errno) ));
2888 0 : goto fail;
2889 : }
2890 :
2891 : /*
2892 : * ..and apply them to the entry.
2893 : */
2894 :
2895 862279 : if (sys_acl_set_permset(the_entry, the_permset) == -1) {
2896 0 : DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2897 : i, strerror(errno) ));
2898 0 : goto fail;
2899 : }
2900 :
2901 862279 : if( DEBUGLVL( 10 ))
2902 0 : print_canon_ace( p_ace, i);
2903 :
2904 : }
2905 :
2906 161941 : if (needs_mask && !got_mask_entry) {
2907 161941 : if (sys_acl_create_entry(&the_acl, &mask_entry) == -1) {
2908 0 : DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2909 0 : goto fail;
2910 : }
2911 :
2912 161941 : if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
2913 0 : DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2914 0 : goto fail;
2915 : }
2916 :
2917 161941 : if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
2918 0 : DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2919 0 : goto fail;
2920 : }
2921 :
2922 161941 : if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2923 0 : DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2924 0 : goto fail;
2925 : }
2926 :
2927 161941 : if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
2928 0 : DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2929 0 : goto fail;
2930 : }
2931 : }
2932 :
2933 : /*
2934 : * Finally apply it to the file or directory.
2935 : */
2936 161941 : sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl_type, the_acl);
2937 161941 : if (sret == -1) {
2938 : /*
2939 : * Some systems allow all the above calls and only fail with no ACL support
2940 : * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2941 : */
2942 0 : if (no_acl_syscall_error(errno)) {
2943 0 : *pacl_set_support = false;
2944 : }
2945 :
2946 0 : if (acl_group_override_fsp(fsp)) {
2947 0 : DBG_DEBUG("acl group control on and current user in "
2948 : "file [%s] primary group.\n",
2949 : fsp_str_dbg(fsp));
2950 :
2951 0 : become_root();
2952 0 : sret = SMB_VFS_SYS_ACL_SET_FD(fsp,
2953 : the_acl_type,
2954 : the_acl);
2955 0 : unbecome_root();
2956 0 : if (sret == 0) {
2957 0 : ret = true;
2958 : }
2959 : }
2960 :
2961 0 : if (ret == false) {
2962 0 : DBG_WARNING("sys_acl_set_file on file [%s]: (%s)\n",
2963 : fsp_str_dbg(fsp), strerror(errno));
2964 0 : goto fail;
2965 : }
2966 : }
2967 :
2968 161469 : ret = True;
2969 :
2970 161941 : fail:
2971 :
2972 161941 : if (the_acl != NULL) {
2973 161941 : TALLOC_FREE(the_acl);
2974 : }
2975 :
2976 161469 : return ret;
2977 : }
2978 :
2979 : /****************************************************************************
2980 :
2981 : ****************************************************************************/
2982 :
2983 105970 : SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2984 : {
2985 : SMB_ACL_ENTRY_T entry;
2986 :
2987 105970 : if (!the_acl)
2988 43664 : return NULL;
2989 61782 : if (sys_acl_get_entry(the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2990 49506 : TALLOC_FREE(the_acl);
2991 49506 : return NULL;
2992 : }
2993 12143 : return the_acl;
2994 : }
2995 :
2996 : /****************************************************************************
2997 : Convert a canon_ace to a generic 3 element permission - if possible.
2998 : ****************************************************************************/
2999 :
3000 : #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
3001 :
3002 0 : static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
3003 : {
3004 0 : size_t ace_count = count_canon_ace_list(file_ace_list);
3005 : canon_ace *ace_p;
3006 0 : canon_ace *owner_ace = NULL;
3007 0 : canon_ace *group_ace = NULL;
3008 0 : canon_ace *other_ace = NULL;
3009 :
3010 0 : if (ace_count > 5) {
3011 0 : DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
3012 : "entries for file %s to convert to posix perms.\n",
3013 : fsp_str_dbg(fsp)));
3014 0 : return False;
3015 : }
3016 :
3017 0 : for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
3018 0 : if (ace_p->owner_type == UID_ACE)
3019 0 : owner_ace = ace_p;
3020 0 : else if (ace_p->owner_type == GID_ACE)
3021 0 : group_ace = ace_p;
3022 0 : else if (ace_p->owner_type == WORLD_ACE)
3023 0 : other_ace = ace_p;
3024 : }
3025 :
3026 0 : if (!owner_ace || !group_ace || !other_ace) {
3027 0 : DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get "
3028 : "standard entries for file %s.\n", fsp_str_dbg(fsp)));
3029 0 : return False;
3030 : }
3031 :
3032 : /*
3033 : * Ensure all ACE entries are owner, group or other.
3034 : * We can't set if there are any other SIDs.
3035 : */
3036 0 : for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
3037 0 : if (ace_p == owner_ace || ace_p == group_ace ||
3038 : ace_p == other_ace) {
3039 0 : continue;
3040 : }
3041 0 : if (ace_p->owner_type == UID_ACE) {
3042 0 : if (ace_p->unix_ug.id != owner_ace->unix_ug.id) {
3043 0 : DEBUG(3,("Invalid uid %u in ACE for file %s.\n",
3044 : (unsigned int)ace_p->unix_ug.id,
3045 : fsp_str_dbg(fsp)));
3046 0 : return false;
3047 : }
3048 0 : } else if (ace_p->owner_type == GID_ACE) {
3049 0 : if (ace_p->unix_ug.id != group_ace->unix_ug.id) {
3050 0 : DEBUG(3,("Invalid gid %u in ACE for file %s.\n",
3051 : (unsigned int)ace_p->unix_ug.id,
3052 : fsp_str_dbg(fsp)));
3053 0 : return false;
3054 : }
3055 : } else {
3056 : /*
3057 : * There should be no duplicate WORLD_ACE entries.
3058 : */
3059 :
3060 0 : DEBUG(3,("Invalid type %u, uid %u in "
3061 : "ACE for file %s.\n",
3062 : (unsigned int)ace_p->owner_type,
3063 : (unsigned int)ace_p->unix_ug.id,
3064 : fsp_str_dbg(fsp)));
3065 0 : return false;
3066 : }
3067 : }
3068 :
3069 0 : *posix_perms = (mode_t)0;
3070 :
3071 0 : *posix_perms |= owner_ace->perms;
3072 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
3073 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
3074 0 : *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
3075 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
3076 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
3077 0 : *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
3078 :
3079 : /* The owner must have at least read access. */
3080 :
3081 0 : *posix_perms |= S_IRUSR;
3082 0 : if (fsp->fsp_flags.is_directory)
3083 0 : *posix_perms |= (S_IWUSR|S_IXUSR);
3084 :
3085 0 : DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
3086 : "to perm=0%o for file %s.\n", (int)owner_ace->perms,
3087 : (int)group_ace->perms, (int)other_ace->perms,
3088 : (int)*posix_perms, fsp_str_dbg(fsp)));
3089 :
3090 0 : return True;
3091 : }
3092 :
3093 : /****************************************************************************
3094 : Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
3095 : a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
3096 : with CI|OI set so it is inherited and also applies to the directory.
3097 : Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
3098 : ****************************************************************************/
3099 :
3100 431543 : static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_aces)
3101 : {
3102 : size_t i, j;
3103 :
3104 2091336 : for (i = 0; i < num_aces; i++) {
3105 4526388 : for (j = i+1; j < num_aces; j++) {
3106 2925333 : uint32_t i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3107 2925333 : uint32_t j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3108 2925333 : bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3109 2925333 : bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3110 :
3111 : /* We know the lower number ACE's are file entries. */
3112 5322698 : if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
3113 3710461 : (nt_ace_list[i].size == nt_ace_list[j].size) &&
3114 1322506 : (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
3115 801340 : dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
3116 381110 : (i_inh == j_inh) &&
3117 381110 : (i_flags_ni == 0) &&
3118 : (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
3119 : SEC_ACE_FLAG_CONTAINER_INHERIT|
3120 : SEC_ACE_FLAG_INHERIT_ONLY))) {
3121 : /*
3122 : * W2K wants to have access allowed zero access ACE's
3123 : * at the end of the list. If the mask is zero, merge
3124 : * the non-inherited ACE onto the inherited ACE.
3125 : */
3126 :
3127 57750 : if (nt_ace_list[i].access_mask == 0) {
3128 3682 : nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3129 : (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3130 3682 : ARRAY_DEL_ELEMENT(nt_ace_list, i, num_aces);
3131 :
3132 3682 : DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
3133 : (unsigned int)i, (unsigned int)j ));
3134 : } else {
3135 : /*
3136 : * These are identical except for the flags.
3137 : * Merge the inherited ACE onto the non-inherited ACE.
3138 : */
3139 :
3140 54068 : nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3141 : (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3142 54068 : ARRAY_DEL_ELEMENT(nt_ace_list, j, num_aces);
3143 :
3144 54068 : DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
3145 : (unsigned int)j, (unsigned int)i ));
3146 : }
3147 57750 : num_aces--;
3148 57750 : break;
3149 : }
3150 : }
3151 : }
3152 :
3153 431543 : return num_aces;
3154 : }
3155 :
3156 :
3157 : /****************************************************************************
3158 : Reply to query a security descriptor from an fsp. If it succeeds it allocates
3159 : the space for the return elements and returns the size needed to return the
3160 : security descriptor. This should be the only external function needed for
3161 : the UNIX style get ACL.
3162 : ****************************************************************************/
3163 :
3164 431543 : static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
3165 : const char *name,
3166 : const SMB_STRUCT_STAT *sbuf,
3167 : struct pai_val *pal,
3168 : SMB_ACL_T posix_acl,
3169 : SMB_ACL_T def_acl,
3170 : uint32_t security_info,
3171 : TALLOC_CTX *mem_ctx,
3172 : struct security_descriptor **ppdesc)
3173 : {
3174 : struct dom_sid owner_sid;
3175 : struct dom_sid group_sid;
3176 431543 : size_t sd_size = 0;
3177 431543 : struct security_acl *psa = NULL;
3178 431543 : size_t num_acls = 0;
3179 431543 : size_t num_def_acls = 0;
3180 431543 : size_t num_aces = 0;
3181 431543 : canon_ace *file_ace = NULL;
3182 431543 : canon_ace *dir_ace = NULL;
3183 431543 : struct security_ace *nt_ace_list = NULL;
3184 431543 : struct security_descriptor *psd = NULL;
3185 :
3186 : /*
3187 : * Get the owner, group and world SIDs.
3188 : */
3189 :
3190 432531 : create_file_sids(sbuf, &owner_sid, &group_sid);
3191 :
3192 431543 : if (security_info & SECINFO_DACL) {
3193 :
3194 : /*
3195 : * In the optimum case Creator Owner and Creator Group would be used for
3196 : * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
3197 : * would lead to usability problems under Windows: The Creator entries
3198 : * are only available in browse lists of directories and not for files;
3199 : * additionally the identity of the owning group couldn't be determined.
3200 : * We therefore use those identities only for Default ACLs.
3201 : */
3202 :
3203 : /* Create the canon_ace lists. */
3204 431543 : file_ace = canonicalise_acl(conn, name, posix_acl, sbuf,
3205 : &owner_sid, &group_sid, pal,
3206 : SMB_ACL_TYPE_ACCESS);
3207 :
3208 : /* We must have *some* ACLS. */
3209 :
3210 431543 : if (count_canon_ace_list(file_ace) == 0) {
3211 0 : DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
3212 0 : goto done;
3213 : }
3214 :
3215 431543 : if (S_ISDIR(sbuf->st_ex_mode) && def_acl) {
3216 12268 : dir_ace = canonicalise_acl(conn, name, def_acl,
3217 : sbuf,
3218 : &global_sid_Creator_Owner,
3219 : &global_sid_Creator_Group,
3220 : pal, SMB_ACL_TYPE_DEFAULT);
3221 : }
3222 :
3223 : /*
3224 : * Create the NT ACE list from the canonical ace lists.
3225 : */
3226 :
3227 : {
3228 : canon_ace *ace;
3229 : enum security_ace_type nt_acl_type;
3230 :
3231 430555 : num_acls = count_canon_ace_list(file_ace);
3232 431543 : num_def_acls = count_canon_ace_list(dir_ace);
3233 :
3234 431543 : nt_ace_list = talloc_zero_array(
3235 : talloc_tos(), struct security_ace,
3236 : num_acls + num_def_acls);
3237 :
3238 431543 : if (nt_ace_list == NULL) {
3239 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
3240 0 : goto done;
3241 : }
3242 :
3243 : /*
3244 : * Create the NT ACE list from the canonical ace lists.
3245 : */
3246 :
3247 2063966 : for (ace = file_ace; ace != NULL; ace = ace->next) {
3248 1633411 : uint32_t acc = map_canon_ace_perms(SNUM(conn),
3249 : &nt_acl_type,
3250 : ace->perms,
3251 1633411 : S_ISDIR(sbuf->st_ex_mode));
3252 3007613 : init_sec_ace(&nt_ace_list[num_aces++],
3253 1633411 : &ace->trustee,
3254 : nt_acl_type,
3255 : acc,
3256 1633411 : ace->ace_flags);
3257 : }
3258 :
3259 513699 : for (ace = dir_ace; ace != NULL; ace = ace->next) {
3260 83144 : uint32_t acc = map_canon_ace_perms(SNUM(conn),
3261 : &nt_acl_type,
3262 : ace->perms,
3263 83144 : S_ISDIR(sbuf->st_ex_mode));
3264 148775 : init_sec_ace(&nt_ace_list[num_aces++],
3265 83144 : &ace->trustee,
3266 : nt_acl_type,
3267 : acc,
3268 83144 : ace->ace_flags |
3269 : SEC_ACE_FLAG_OBJECT_INHERIT|
3270 : SEC_ACE_FLAG_CONTAINER_INHERIT|
3271 : SEC_ACE_FLAG_INHERIT_ONLY);
3272 : }
3273 :
3274 : /*
3275 : * Merge POSIX default ACLs and normal ACLs into one NT ACE.
3276 : * Win2K needs this to get the inheritance correct when replacing ACLs
3277 : * on a directory tree. Based on work by Jim @ IBM.
3278 : */
3279 :
3280 431543 : num_aces = merge_default_aces(nt_ace_list, num_aces);
3281 : }
3282 :
3283 431543 : if (num_aces) {
3284 431543 : if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
3285 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
3286 0 : goto done;
3287 : }
3288 : }
3289 : } /* security_info & SECINFO_DACL */
3290 :
3291 863086 : psd = make_standard_sec_desc(mem_ctx,
3292 431543 : (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
3293 431543 : (security_info & SECINFO_GROUP) ? &group_sid : NULL,
3294 : psa,
3295 : &sd_size);
3296 :
3297 431543 : if(!psd) {
3298 0 : DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
3299 0 : sd_size = 0;
3300 0 : goto done;
3301 : }
3302 :
3303 : /*
3304 : * Windows 2000: The DACL_PROTECTED flag in the security
3305 : * descriptor marks the ACL as non-inheriting, i.e., no
3306 : * ACEs from higher level directories propagate to this
3307 : * ACL. In the POSIX ACL model permissions are only
3308 : * inherited at file create time, so ACLs never contain
3309 : * any ACEs that are inherited dynamically. The DACL_PROTECTED
3310 : * flag doesn't seem to bother Windows NT.
3311 : * Always set this if map acl inherit is turned off.
3312 : */
3313 431543 : if (pal == NULL || !lp_map_acl_inherit(SNUM(conn))) {
3314 431543 : psd->type |= SEC_DESC_DACL_PROTECTED;
3315 : } else {
3316 0 : psd->type |= pal->sd_type;
3317 : }
3318 :
3319 431543 : if (psd->dacl) {
3320 431543 : dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
3321 : }
3322 :
3323 431543 : *ppdesc = psd;
3324 :
3325 431543 : done:
3326 :
3327 431543 : if (posix_acl) {
3328 249746 : TALLOC_FREE(posix_acl);
3329 : }
3330 431543 : if (def_acl) {
3331 12268 : TALLOC_FREE(def_acl);
3332 : }
3333 431543 : free_canon_ace_list(file_ace);
3334 431543 : free_canon_ace_list(dir_ace);
3335 431543 : free_inherited_info(pal);
3336 431543 : TALLOC_FREE(nt_ace_list);
3337 :
3338 431543 : return NT_STATUS_OK;
3339 : }
3340 :
3341 431543 : NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
3342 : TALLOC_CTX *mem_ctx,
3343 : struct security_descriptor **ppdesc)
3344 : {
3345 : SMB_STRUCT_STAT sbuf;
3346 431543 : SMB_ACL_T posix_acl = NULL;
3347 431543 : SMB_ACL_T def_acl = NULL;
3348 : struct pai_val *pal;
3349 431543 : TALLOC_CTX *frame = talloc_stackframe();
3350 : NTSTATUS status;
3351 :
3352 431543 : *ppdesc = NULL;
3353 :
3354 431543 : DEBUG(10,("posix_fget_nt_acl: called for file %s\n",
3355 : fsp_str_dbg(fsp)));
3356 :
3357 : /* Get the stat struct for the owner info. */
3358 431543 : if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
3359 0 : TALLOC_FREE(frame);
3360 0 : return map_nt_error_from_unix(errno);
3361 : }
3362 :
3363 : /* Get the ACL from the fd. */
3364 431543 : posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3365 : SMB_ACL_TYPE_ACCESS,
3366 : frame);
3367 :
3368 : /* If it's a directory get the default POSIX ACL. */
3369 431543 : if(fsp->fsp_flags.is_directory) {
3370 105950 : def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3371 : SMB_ACL_TYPE_DEFAULT,
3372 : frame);
3373 105950 : def_acl = free_empty_sys_acl(fsp->conn, def_acl);
3374 : }
3375 :
3376 431543 : pal = fload_inherited_info(fsp);
3377 :
3378 431543 : status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
3379 : &sbuf, pal, posix_acl, def_acl,
3380 : security_info, mem_ctx, ppdesc);
3381 431543 : TALLOC_FREE(frame);
3382 431543 : return status;
3383 : }
3384 :
3385 : /****************************************************************************
3386 : Try to chown a file. We will be able to chown it under the following conditions.
3387 :
3388 : 1) If we have root privileges, then it will just work.
3389 : 2) If we have SeRestorePrivilege we can change the user + group to any other user.
3390 : 3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
3391 : 4) If we have write permission to the file and dos_filemodes is set
3392 : then allow chown to the currently authenticated user.
3393 : ****************************************************************************/
3394 :
3395 144993 : NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
3396 : {
3397 : NTSTATUS status;
3398 : int ret;
3399 :
3400 144993 : if(!CAN_WRITE(fsp->conn)) {
3401 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3402 : }
3403 :
3404 : /* Case (1). */
3405 144993 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
3406 144993 : if (ret == 0) {
3407 87393 : return NT_STATUS_OK;
3408 : }
3409 :
3410 : /* Case (2) / (3) */
3411 57600 : if (lp_enable_privileges()) {
3412 57600 : bool has_take_ownership_priv = security_token_has_privilege(
3413 57600 : get_current_nttok(fsp->conn),
3414 : SEC_PRIV_TAKE_OWNERSHIP);
3415 57600 : bool has_restore_priv = security_token_has_privilege(
3416 57600 : get_current_nttok(fsp->conn),
3417 : SEC_PRIV_RESTORE);
3418 :
3419 57600 : if (has_restore_priv) {
3420 : ; /* Case (2) */
3421 1248 : } else if (has_take_ownership_priv) {
3422 : /* Case (3) */
3423 0 : if (uid == get_current_uid(fsp->conn)) {
3424 0 : gid = (gid_t)-1;
3425 : } else {
3426 0 : has_take_ownership_priv = false;
3427 : }
3428 : }
3429 :
3430 57600 : if (has_take_ownership_priv || has_restore_priv) {
3431 56352 : status = NT_STATUS_OK;
3432 56352 : become_root();
3433 56352 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
3434 56352 : if (ret != 0) {
3435 0 : status = map_nt_error_from_unix(errno);
3436 : }
3437 56352 : unbecome_root();
3438 56352 : return status;
3439 : }
3440 : }
3441 :
3442 : /* Case (4). */
3443 : /* If "dos filemode" isn't set, we're done. */
3444 1248 : if (!lp_dos_filemode(SNUM(fsp->conn))) {
3445 0 : return NT_STATUS_ACCESS_DENIED;
3446 : }
3447 : /*
3448 : * If we have a writable handle, obviously we
3449 : * can write to the file.
3450 : */
3451 1248 : if (!fsp->fsp_flags.can_write) {
3452 : /*
3453 : * If we don't have a writable handle, we
3454 : * need to read the ACL on the file to
3455 : * see if we can write to it.
3456 : */
3457 380 : if (!can_write_to_fsp(fsp)) {
3458 0 : return NT_STATUS_ACCESS_DENIED;
3459 : }
3460 : }
3461 :
3462 : /* only allow chown to the current user. This is more secure,
3463 : and also copes with the case where the SID in a take ownership ACL is
3464 : a local SID on the users workstation
3465 : */
3466 1248 : if (uid != get_current_uid(fsp->conn)) {
3467 2 : return NT_STATUS_INVALID_OWNER;
3468 : }
3469 :
3470 1246 : status = NT_STATUS_OK;
3471 1246 : become_root();
3472 : /* Keep the current file gid the same. */
3473 1246 : ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
3474 1246 : if (ret != 0) {
3475 0 : status = map_nt_error_from_unix(errno);
3476 : }
3477 1246 : unbecome_root();
3478 :
3479 1246 : return status;
3480 : }
3481 :
3482 : /****************************************************************************
3483 : Reply to set a security descriptor on an fsp. security_info_sent is the
3484 : description of the following NT ACL.
3485 : This should be the only external function needed for the UNIX style set ACL.
3486 : We make a copy of psd_orig as internal functions modify the elements inside
3487 : it, even though it's a const pointer.
3488 : ****************************************************************************/
3489 :
3490 151934 : NTSTATUS set_nt_acl(files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd_orig)
3491 : {
3492 151934 : connection_struct *conn = fsp->conn;
3493 151934 : uid_t user = (uid_t)-1;
3494 151934 : gid_t grp = (gid_t)-1;
3495 : struct dom_sid file_owner_sid;
3496 : struct dom_sid file_grp_sid;
3497 151934 : canon_ace *file_ace_list = NULL;
3498 151934 : canon_ace *dir_ace_list = NULL;
3499 151934 : bool acl_perms = False;
3500 151934 : mode_t orig_mode = (mode_t)0;
3501 : NTSTATUS status;
3502 151934 : bool set_acl_as_root = false;
3503 151934 : bool acl_set_support = false;
3504 151934 : bool ret = false;
3505 151934 : struct security_descriptor *psd = NULL;
3506 :
3507 151934 : DEBUG(10,("set_nt_acl: called for file %s\n",
3508 : fsp_str_dbg(fsp)));
3509 :
3510 151934 : if (!CAN_WRITE(conn)) {
3511 0 : DEBUG(10,("set acl rejected on read-only share\n"));
3512 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
3513 : }
3514 :
3515 151934 : if (psd_orig == NULL) {
3516 0 : return NT_STATUS_INVALID_PARAMETER;
3517 : }
3518 :
3519 : /*
3520 : * MS NFS mode, here's the deal: the client merely wants to
3521 : * modify the mode, but roundtripping get_acl/set/acl would
3522 : * add additional POSIX ACEs. So in case we get a request
3523 : * containing a MS NFS mode SID, we do nothing here.
3524 : */
3525 151934 : if (security_descriptor_with_ms_nfs(psd_orig)) {
3526 0 : return NT_STATUS_OK;
3527 : }
3528 :
3529 151934 : psd = security_descriptor_copy(talloc_tos(), psd_orig);
3530 151934 : if (psd == NULL) {
3531 0 : return NT_STATUS_NO_MEMORY;
3532 : }
3533 :
3534 : /*
3535 : * Get the current state of the file.
3536 : */
3537 :
3538 151934 : status = vfs_stat_fsp(fsp);
3539 151934 : if (!NT_STATUS_IS_OK(status)) {
3540 0 : return status;
3541 : }
3542 :
3543 : /* Save the original element we check against. */
3544 151934 : orig_mode = fsp->fsp_name->st.st_ex_mode;
3545 :
3546 : /*
3547 : * Unpack the user/group/world id's.
3548 : */
3549 :
3550 : /* POSIX can't cope with missing owner/group. */
3551 151934 : if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
3552 0 : security_info_sent &= ~SECINFO_OWNER;
3553 : }
3554 151934 : if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
3555 0 : security_info_sent &= ~SECINFO_GROUP;
3556 : }
3557 :
3558 : /* If UNIX owner is inherited and Windows isn't, then
3559 : * setting the UNIX owner based on Windows owner conflicts
3560 : * with the inheritance rule
3561 : */
3562 151934 : if (lp_inherit_owner(SNUM(conn)) == INHERIT_OWNER_UNIX_ONLY) {
3563 16 : security_info_sent &= ~SECINFO_OWNER;
3564 : }
3565 :
3566 151934 : status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
3567 151934 : if (!NT_STATUS_IS_OK(status)) {
3568 0 : return status;
3569 : }
3570 :
3571 : /*
3572 : * Do we need to chown ? If so this must be done first as the incoming
3573 : * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
3574 : * Noticed by Simo.
3575 : */
3576 :
3577 243961 : if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) ||
3578 180933 : (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) {
3579 :
3580 144461 : DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3581 : fsp_str_dbg(fsp), (unsigned int)user,
3582 : (unsigned int)grp));
3583 :
3584 144461 : status = try_chown(fsp, user, grp);
3585 144461 : if(!NT_STATUS_IS_OK(status)) {
3586 2 : DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
3587 : "= %s.\n", fsp_str_dbg(fsp),
3588 : (unsigned int)user,
3589 : (unsigned int)grp,
3590 : nt_errstr(status)));
3591 2 : return status;
3592 : }
3593 :
3594 : /*
3595 : * Recheck the current state of the file, which may have changed.
3596 : * (suid/sgid bits, for instance)
3597 : */
3598 :
3599 144459 : status = vfs_stat_fsp(fsp);
3600 144459 : if (!NT_STATUS_IS_OK(status)) {
3601 0 : return status;
3602 : }
3603 :
3604 : /* Save the original element we check against. */
3605 144459 : orig_mode = fsp->fsp_name->st.st_ex_mode;
3606 :
3607 : /* If we successfully chowned, we know we must
3608 : * be able to set the acl, so do it as root.
3609 : */
3610 144459 : set_acl_as_root = true;
3611 : }
3612 :
3613 152254 : create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
3614 :
3615 272530 : if((security_info_sent & SECINFO_DACL) &&
3616 270438 : (psd->type & SEC_DESC_DACL_PRESENT) &&
3617 149840 : (psd->dacl == NULL)) {
3618 : struct security_ace ace[3];
3619 :
3620 : /* We can't have NULL DACL in POSIX.
3621 : Use owner/group/Everyone -> full access. */
3622 :
3623 20 : init_sec_ace(&ace[0],
3624 : &file_owner_sid,
3625 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3626 : GENERIC_ALL_ACCESS,
3627 : 0);
3628 20 : init_sec_ace(&ace[1],
3629 : &file_grp_sid,
3630 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3631 : GENERIC_ALL_ACCESS,
3632 : 0);
3633 20 : init_sec_ace(&ace[2],
3634 : &global_sid_World,
3635 : SEC_ACE_TYPE_ACCESS_ALLOWED,
3636 : GENERIC_ALL_ACCESS,
3637 : 0);
3638 20 : psd->dacl = make_sec_acl(talloc_tos(),
3639 : NT4_ACL_REVISION,
3640 : 3,
3641 : ace);
3642 20 : if (psd->dacl == NULL) {
3643 0 : return NT_STATUS_NO_MEMORY;
3644 : }
3645 20 : security_acl_map_generic(psd->dacl, &file_generic_mapping);
3646 : }
3647 :
3648 151932 : acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
3649 : &file_grp_sid, &file_ace_list,
3650 : &dir_ace_list, security_info_sent, psd);
3651 :
3652 : /* Ignore W2K traverse DACL set. */
3653 151932 : if (!file_ace_list && !dir_ace_list) {
3654 2147 : return NT_STATUS_OK;
3655 : }
3656 :
3657 149785 : if (!acl_perms) {
3658 0 : DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3659 0 : free_canon_ace_list(file_ace_list);
3660 0 : free_canon_ace_list(dir_ace_list);
3661 0 : return NT_STATUS_ACCESS_DENIED;
3662 : }
3663 :
3664 : /*
3665 : * Only change security if we got a DACL.
3666 : */
3667 :
3668 149785 : if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
3669 0 : free_canon_ace_list(file_ace_list);
3670 0 : free_canon_ace_list(dir_ace_list);
3671 0 : return NT_STATUS_OK;
3672 : }
3673 :
3674 : /*
3675 : * Try using the POSIX ACL set first. Fall back to chmod if
3676 : * we have no ACL support on this filesystem.
3677 : */
3678 :
3679 149785 : if (acl_perms && file_ace_list) {
3680 149785 : if (set_acl_as_root) {
3681 143383 : become_root();
3682 : }
3683 149785 : ret = set_canon_ace_list(fsp, file_ace_list, false,
3684 149785 : &fsp->fsp_name->st, &acl_set_support);
3685 149785 : if (set_acl_as_root) {
3686 143383 : unbecome_root();
3687 : }
3688 149785 : if (acl_set_support && ret == false) {
3689 0 : DEBUG(3,("set_nt_acl: failed to set file acl on file "
3690 : "%s (%s).\n", fsp_str_dbg(fsp),
3691 : strerror(errno)));
3692 0 : free_canon_ace_list(file_ace_list);
3693 0 : free_canon_ace_list(dir_ace_list);
3694 0 : return map_nt_error_from_unix(errno);
3695 : }
3696 : }
3697 :
3698 149785 : if (acl_perms && acl_set_support && fsp->fsp_flags.is_directory) {
3699 12477 : if (dir_ace_list) {
3700 12156 : if (set_acl_as_root) {
3701 10888 : become_root();
3702 : }
3703 12156 : ret = set_canon_ace_list(fsp, dir_ace_list, true,
3704 12156 : &fsp->fsp_name->st,
3705 : &acl_set_support);
3706 12156 : if (set_acl_as_root) {
3707 10888 : unbecome_root();
3708 : }
3709 12156 : if (ret == false) {
3710 0 : DEBUG(3,("set_nt_acl: failed to set default "
3711 : "acl on directory %s (%s).\n",
3712 : fsp_str_dbg(fsp), strerror(errno)));
3713 0 : free_canon_ace_list(file_ace_list);
3714 0 : free_canon_ace_list(dir_ace_list);
3715 0 : return map_nt_error_from_unix(errno);
3716 : }
3717 : } else {
3718 321 : int sret = -1;
3719 :
3720 : /*
3721 : * No default ACL - delete one if it exists.
3722 : */
3723 :
3724 321 : if (set_acl_as_root) {
3725 79 : become_root();
3726 : }
3727 321 : sret = SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
3728 321 : if (set_acl_as_root) {
3729 79 : unbecome_root();
3730 : }
3731 321 : if (sret == -1) {
3732 0 : if (acl_group_override_fsp(fsp)) {
3733 0 : DEBUG(5,("set_nt_acl: acl group "
3734 : "control on and current user "
3735 : "in file %s primary group. "
3736 : "Override delete_def_acl\n",
3737 : fsp_str_dbg(fsp)));
3738 :
3739 0 : become_root();
3740 0 : sret =
3741 0 : SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
3742 0 : unbecome_root();
3743 : }
3744 :
3745 0 : if (sret == -1) {
3746 0 : DBG_NOTICE("sys_acl_delete_def_fd for "
3747 : "directory %s failed (%s)\n",
3748 : fsp_str_dbg(fsp),
3749 : strerror(errno));
3750 0 : free_canon_ace_list(file_ace_list);
3751 0 : free_canon_ace_list(dir_ace_list);
3752 0 : return map_nt_error_from_unix(errno);
3753 : }
3754 : }
3755 : }
3756 : }
3757 :
3758 149785 : if (acl_set_support) {
3759 149785 : if (set_acl_as_root) {
3760 143383 : become_root();
3761 : }
3762 149785 : store_inheritance_attributes(fsp,
3763 : file_ace_list,
3764 : dir_ace_list,
3765 149785 : psd->type);
3766 149785 : if (set_acl_as_root) {
3767 143383 : unbecome_root();
3768 : }
3769 : }
3770 :
3771 : /*
3772 : * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3773 : */
3774 :
3775 149785 : if(!acl_set_support && acl_perms) {
3776 : mode_t posix_perms;
3777 :
3778 0 : if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3779 0 : free_canon_ace_list(file_ace_list);
3780 0 : free_canon_ace_list(dir_ace_list);
3781 0 : DEBUG(3,("set_nt_acl: failed to convert file acl to "
3782 : "posix permissions for file %s.\n",
3783 : fsp_str_dbg(fsp)));
3784 0 : return NT_STATUS_ACCESS_DENIED;
3785 : }
3786 :
3787 0 : if (orig_mode != posix_perms) {
3788 0 : int sret = -1;
3789 :
3790 0 : DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3791 : fsp_str_dbg(fsp), (unsigned int)posix_perms));
3792 :
3793 0 : if (set_acl_as_root) {
3794 0 : become_root();
3795 : }
3796 0 : sret = SMB_VFS_FCHMOD(fsp, posix_perms);
3797 0 : if (set_acl_as_root) {
3798 0 : unbecome_root();
3799 : }
3800 0 : if(sret == -1) {
3801 0 : if (acl_group_override_fsp(fsp)) {
3802 0 : DEBUG(5,("set_nt_acl: acl group "
3803 : "control on and current user "
3804 : "in file %s primary group. "
3805 : "Override chmod\n",
3806 : fsp_str_dbg(fsp)));
3807 :
3808 0 : become_root();
3809 0 : sret = SMB_VFS_FCHMOD(fsp, posix_perms);
3810 0 : unbecome_root();
3811 : }
3812 :
3813 0 : if (sret == -1) {
3814 0 : DEBUG(3,("set_nt_acl: chmod %s, 0%o "
3815 : "failed. Error = %s.\n",
3816 : fsp_str_dbg(fsp),
3817 : (unsigned int)posix_perms,
3818 : strerror(errno)));
3819 0 : free_canon_ace_list(file_ace_list);
3820 0 : free_canon_ace_list(dir_ace_list);
3821 0 : return map_nt_error_from_unix(errno);
3822 : }
3823 : }
3824 : }
3825 : }
3826 :
3827 149785 : free_canon_ace_list(file_ace_list);
3828 149785 : free_canon_ace_list(dir_ace_list);
3829 :
3830 : /* Ensure the stat struct in the fsp is correct. */
3831 149785 : status = vfs_stat_fsp(fsp);
3832 :
3833 149785 : return NT_STATUS_OK;
3834 : }
3835 :
3836 : /****************************************************************************
3837 : Get the actual group bits stored on a file with an ACL. Has no effect if
3838 : the file has no ACL. Needed in dosmode code where the stat() will return
3839 : the mask bits, not the real group bits, for a file with an ACL.
3840 : ****************************************************************************/
3841 :
3842 188646 : int get_acl_group_bits( connection_struct *conn,
3843 : const struct smb_filename *smb_fname,
3844 : mode_t *mode )
3845 : {
3846 188646 : int entry_id = SMB_ACL_FIRST_ENTRY;
3847 : SMB_ACL_ENTRY_T entry;
3848 : SMB_ACL_T posix_acl;
3849 188646 : int result = -1;
3850 :
3851 188646 : posix_acl = SMB_VFS_SYS_ACL_GET_FD(smb_fname->fsp,
3852 : SMB_ACL_TYPE_ACCESS,
3853 : talloc_tos());
3854 188646 : if (posix_acl == (SMB_ACL_T)NULL)
3855 144370 : return -1;
3856 :
3857 137713 : while (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
3858 : SMB_ACL_TAG_T tagtype;
3859 : SMB_ACL_PERMSET_T permset;
3860 :
3861 94089 : entry_id = SMB_ACL_NEXT_ENTRY;
3862 :
3863 94089 : if (sys_acl_get_tag_type(entry, &tagtype) ==-1)
3864 43937 : break;
3865 :
3866 94089 : if (tagtype == SMB_ACL_GROUP_OBJ) {
3867 44058 : if (sys_acl_get_permset(entry, &permset) == -1) {
3868 0 : break;
3869 : } else {
3870 44058 : *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3871 44058 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRGRP : 0);
3872 44058 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3873 44058 : *mode |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3874 44058 : result = 0;
3875 44058 : break;
3876 : }
3877 : }
3878 : }
3879 44058 : TALLOC_FREE(posix_acl);
3880 44058 : return result;
3881 : }
3882 :
3883 : /****************************************************************************
3884 : Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3885 : and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3886 : ****************************************************************************/
3887 :
3888 0 : static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3889 : {
3890 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
3891 : SMB_ACL_ENTRY_T entry;
3892 0 : int num_entries = 0;
3893 :
3894 0 : while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
3895 : SMB_ACL_TAG_T tagtype;
3896 : SMB_ACL_PERMSET_T permset;
3897 : mode_t perms;
3898 :
3899 0 : entry_id = SMB_ACL_NEXT_ENTRY;
3900 :
3901 0 : if (sys_acl_get_tag_type(entry, &tagtype) == -1)
3902 0 : return -1;
3903 :
3904 0 : if (sys_acl_get_permset(entry, &permset) == -1)
3905 0 : return -1;
3906 :
3907 0 : num_entries++;
3908 :
3909 0 : switch(tagtype) {
3910 0 : case SMB_ACL_USER_OBJ:
3911 0 : perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3912 0 : break;
3913 0 : case SMB_ACL_GROUP_OBJ:
3914 0 : perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3915 0 : break;
3916 0 : case SMB_ACL_MASK:
3917 : /*
3918 : * FIXME: The ACL_MASK entry permissions should really be set to
3919 : * the union of the permissions of all ACL_USER,
3920 : * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3921 : * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3922 : */
3923 0 : perms = S_IRUSR|S_IWUSR|S_IXUSR;
3924 0 : break;
3925 0 : case SMB_ACL_OTHER:
3926 0 : perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3927 0 : break;
3928 0 : default:
3929 0 : continue;
3930 : }
3931 :
3932 0 : if (map_acl_perms_to_permset(perms, &permset) == -1)
3933 0 : return -1;
3934 :
3935 0 : if (sys_acl_set_permset(entry, permset) == -1)
3936 0 : return -1;
3937 : }
3938 :
3939 : /*
3940 : * If this is a simple 3 element ACL or no elements then it's a standard
3941 : * UNIX permission set. Just use chmod...
3942 : */
3943 :
3944 0 : if ((num_entries == 3) || (num_entries == 0))
3945 0 : return -1;
3946 :
3947 0 : return 0;
3948 : }
3949 :
3950 : /****************************************************************************
3951 : Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3952 : GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3953 : resulting ACL on TO. Note that name is in UNIX character set.
3954 : ****************************************************************************/
3955 :
3956 0 : static int copy_access_posix_acl(connection_struct *conn,
3957 : const struct smb_filename *smb_fname_from,
3958 : const struct smb_filename *smb_fname_to,
3959 : mode_t mode)
3960 : {
3961 0 : SMB_ACL_T posix_acl = NULL;
3962 0 : int ret = -1;
3963 :
3964 0 : if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(smb_fname_from->fsp,
3965 : SMB_ACL_TYPE_ACCESS,
3966 : talloc_tos())) == NULL)
3967 0 : return -1;
3968 :
3969 0 : if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3970 0 : goto done;
3971 :
3972 0 : ret = SMB_VFS_SYS_ACL_SET_FD(smb_fname_to->fsp,
3973 : SMB_ACL_TYPE_ACCESS, posix_acl);
3974 :
3975 0 : done:
3976 :
3977 0 : TALLOC_FREE(posix_acl);
3978 0 : return ret;
3979 : }
3980 :
3981 : /****************************************************************************
3982 : Check for an existing default POSIX ACL on a directory.
3983 : ****************************************************************************/
3984 :
3985 0 : static bool directory_has_default_posix_acl(connection_struct *conn,
3986 : const struct smb_filename *smb_fname)
3987 : {
3988 0 : SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FD(smb_fname->fsp,
3989 : SMB_ACL_TYPE_DEFAULT,
3990 : talloc_tos());
3991 0 : bool has_acl = False;
3992 : SMB_ACL_ENTRY_T entry;
3993 :
3994 0 : if (def_acl != NULL && (sys_acl_get_entry(def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3995 0 : has_acl = True;
3996 : }
3997 :
3998 0 : if (def_acl) {
3999 0 : TALLOC_FREE(def_acl);
4000 : }
4001 0 : return has_acl;
4002 : }
4003 :
4004 : /****************************************************************************
4005 : If the parent directory has no default ACL but it does have an Access ACL,
4006 : inherit this Access ACL to file name.
4007 : ****************************************************************************/
4008 :
4009 0 : int inherit_access_posix_acl(connection_struct *conn,
4010 : struct smb_filename *inherit_from_dir,
4011 : const struct smb_filename *smb_fname,
4012 : mode_t mode)
4013 : {
4014 0 : if (directory_has_default_posix_acl(conn, inherit_from_dir))
4015 0 : return 0;
4016 :
4017 0 : return copy_access_posix_acl(conn, inherit_from_dir, smb_fname, mode);
4018 : }
4019 :
4020 : /****************************************************************************
4021 : Map from wire type to permset.
4022 : ****************************************************************************/
4023 :
4024 20 : static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
4025 : {
4026 20 : if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
4027 0 : return False;
4028 : }
4029 :
4030 20 : if (sys_acl_clear_perms(*p_permset) == -1) {
4031 0 : return False;
4032 : }
4033 :
4034 20 : if (wire_perm & SMB_POSIX_ACL_READ) {
4035 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1) {
4036 0 : return False;
4037 : }
4038 : }
4039 20 : if (wire_perm & SMB_POSIX_ACL_WRITE) {
4040 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1) {
4041 0 : return False;
4042 : }
4043 : }
4044 20 : if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
4045 20 : if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1) {
4046 0 : return False;
4047 : }
4048 : }
4049 20 : return True;
4050 : }
4051 :
4052 : /****************************************************************************
4053 : Map from wire type to tagtype.
4054 : ****************************************************************************/
4055 :
4056 20 : static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
4057 : {
4058 20 : switch (wire_tt) {
4059 4 : case SMB_POSIX_ACL_USER_OBJ:
4060 4 : *p_tt = SMB_ACL_USER_OBJ;
4061 4 : break;
4062 4 : case SMB_POSIX_ACL_USER:
4063 4 : *p_tt = SMB_ACL_USER;
4064 4 : break;
4065 4 : case SMB_POSIX_ACL_GROUP_OBJ:
4066 4 : *p_tt = SMB_ACL_GROUP_OBJ;
4067 4 : break;
4068 0 : case SMB_POSIX_ACL_GROUP:
4069 0 : *p_tt = SMB_ACL_GROUP;
4070 0 : break;
4071 4 : case SMB_POSIX_ACL_MASK:
4072 4 : *p_tt = SMB_ACL_MASK;
4073 4 : break;
4074 4 : case SMB_POSIX_ACL_OTHER:
4075 4 : *p_tt = SMB_ACL_OTHER;
4076 4 : break;
4077 0 : default:
4078 0 : return False;
4079 : }
4080 20 : return True;
4081 : }
4082 :
4083 : /****************************************************************************
4084 : Create a new POSIX acl from wire permissions.
4085 : FIXME ! How does the share mask/mode fit into this.... ?
4086 : ****************************************************************************/
4087 :
4088 4 : static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn,
4089 : uint16_t num_acls,
4090 : const char *pdata,
4091 : TALLOC_CTX *mem_ctx)
4092 : {
4093 : unsigned int i;
4094 4 : SMB_ACL_T the_acl = sys_acl_init(mem_ctx);
4095 :
4096 4 : if (the_acl == NULL) {
4097 0 : return NULL;
4098 : }
4099 :
4100 48 : for (i = 0; i < num_acls; i++) {
4101 : SMB_ACL_ENTRY_T the_entry;
4102 : SMB_ACL_PERMSET_T the_permset;
4103 : SMB_ACL_TAG_T tag_type;
4104 :
4105 20 : if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
4106 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
4107 : i, strerror(errno) ));
4108 0 : goto fail;
4109 : }
4110 :
4111 20 : if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
4112 0 : DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
4113 : CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
4114 0 : goto fail;
4115 : }
4116 :
4117 20 : if (sys_acl_set_tag_type(the_entry, tag_type) == -1) {
4118 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
4119 : i, strerror(errno) ));
4120 0 : goto fail;
4121 : }
4122 :
4123 : /* Get the permset pointer from the new ACL entry. */
4124 20 : if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
4125 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
4126 : i, strerror(errno) ));
4127 0 : goto fail;
4128 : }
4129 :
4130 : /* Map from wire to permissions. */
4131 20 : if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
4132 0 : DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
4133 : CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
4134 0 : goto fail;
4135 : }
4136 :
4137 : /* Now apply to the new ACL entry. */
4138 20 : if (sys_acl_set_permset(the_entry, the_permset) == -1) {
4139 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
4140 : i, strerror(errno) ));
4141 0 : goto fail;
4142 : }
4143 :
4144 20 : if (tag_type == SMB_ACL_USER) {
4145 4 : uint32_t uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4146 4 : uid_t uid = (uid_t)uidval;
4147 4 : if (sys_acl_set_qualifier(the_entry,(void *)&uid) == -1) {
4148 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
4149 : (unsigned int)uid, i, strerror(errno) ));
4150 0 : goto fail;
4151 : }
4152 : }
4153 :
4154 20 : if (tag_type == SMB_ACL_GROUP) {
4155 0 : uint32_t gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4156 0 : gid_t gid = (uid_t)gidval;
4157 0 : if (sys_acl_set_qualifier(the_entry,(void *)&gid) == -1) {
4158 0 : DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
4159 : (unsigned int)gid, i, strerror(errno) ));
4160 0 : goto fail;
4161 : }
4162 : }
4163 : }
4164 :
4165 4 : return the_acl;
4166 :
4167 0 : fail:
4168 :
4169 0 : if (the_acl != NULL) {
4170 0 : TALLOC_FREE(the_acl);
4171 : }
4172 0 : return NULL;
4173 : }
4174 :
4175 : /****************************************************************************
4176 : Calls from UNIX extensions - Default POSIX ACL set.
4177 : If num_def_acls == 0 and not a directory just return. If it is a directory
4178 : and num_def_acls == 0 then remove the default acl. Else set the default acl
4179 : on the directory.
4180 : ****************************************************************************/
4181 :
4182 4 : NTSTATUS set_unix_posix_default_acl(connection_struct *conn,
4183 : files_struct *fsp,
4184 : uint16_t num_def_acls,
4185 : const char *pdata)
4186 : {
4187 4 : SMB_ACL_T def_acl = NULL;
4188 : NTSTATUS status;
4189 : int ret;
4190 :
4191 4 : if (!fsp->fsp_flags.is_directory) {
4192 0 : return NT_STATUS_INVALID_HANDLE;
4193 : }
4194 :
4195 4 : if (!num_def_acls) {
4196 : /* Remove the default ACL. */
4197 0 : ret = SMB_VFS_SYS_ACL_DELETE_DEF_FD(fsp);
4198 0 : if (ret == -1) {
4199 0 : status = map_nt_error_from_unix(errno);
4200 0 : DBG_INFO("acl_delete_def_fd failed on "
4201 : "directory %s (%s)\n",
4202 : fsp_str_dbg(fsp),
4203 : strerror(errno));
4204 0 : return status;
4205 : }
4206 0 : return NT_STATUS_OK;
4207 : }
4208 :
4209 4 : def_acl = create_posix_acl_from_wire(conn,
4210 : num_def_acls,
4211 : pdata,
4212 : talloc_tos());
4213 4 : if (def_acl == NULL) {
4214 0 : return map_nt_error_from_unix(errno);
4215 : }
4216 :
4217 4 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp,
4218 : SMB_ACL_TYPE_DEFAULT,
4219 : def_acl);
4220 4 : if (ret == -1) {
4221 0 : status = map_nt_error_from_unix(errno);
4222 0 : DBG_INFO("acl_set_file failed on directory %s (%s)\n",
4223 : fsp_str_dbg(fsp),
4224 : strerror(errno));
4225 0 : TALLOC_FREE(def_acl);
4226 0 : return status;
4227 : }
4228 :
4229 4 : DBG_DEBUG("set default acl for file %s\n",
4230 : fsp_str_dbg(fsp));
4231 4 : TALLOC_FREE(def_acl);
4232 4 : return NT_STATUS_OK;
4233 : }
4234 :
4235 : /****************************************************************************
4236 : Remove an ACL from a file. As we don't have acl_delete_entry() available
4237 : we must read the current acl and copy all entries except MASK, USER and GROUP
4238 : to a new acl, then set that. This (at least on Linux) causes any ACL to be
4239 : removed.
4240 : FIXME ! How does the share mask/mode fit into this.... ?
4241 : ****************************************************************************/
4242 :
4243 0 : static NTSTATUS remove_posix_acl(connection_struct *conn,
4244 : files_struct *fsp)
4245 : {
4246 0 : SMB_ACL_T file_acl = NULL;
4247 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
4248 : SMB_ACL_ENTRY_T entry;
4249 : /* Create a new ACL with only 3 entries, u/g/w. */
4250 0 : SMB_ACL_T new_file_acl = NULL;
4251 0 : SMB_ACL_ENTRY_T user_ent = NULL;
4252 0 : SMB_ACL_ENTRY_T group_ent = NULL;
4253 0 : SMB_ACL_ENTRY_T other_ent = NULL;
4254 : NTSTATUS status;
4255 : int ret;
4256 :
4257 0 : new_file_acl = sys_acl_init(talloc_tos());
4258 0 : if (new_file_acl == NULL) {
4259 0 : status = map_nt_error_from_unix(errno);
4260 0 : DBG_INFO("failed to init new ACL with 3 entries "
4261 : "for file %s %s.\n",
4262 : fsp_str_dbg(fsp),
4263 : strerror(errno));
4264 0 : goto done;
4265 : }
4266 :
4267 : /* Now create the u/g/w entries. */
4268 0 : ret = sys_acl_create_entry(&new_file_acl, &user_ent);
4269 0 : if (ret == -1) {
4270 0 : status = map_nt_error_from_unix(errno);
4271 0 : DBG_INFO("Failed to create user entry for file %s. (%s)\n",
4272 : fsp_str_dbg(fsp),
4273 : strerror(errno));
4274 0 : goto done;
4275 : }
4276 0 : ret = sys_acl_set_tag_type(user_ent, SMB_ACL_USER_OBJ);
4277 0 : if (ret == -1) {
4278 0 : status = map_nt_error_from_unix(errno);
4279 0 : DBG_INFO("Failed to set user entry for file %s. (%s)\n",
4280 : fsp_str_dbg(fsp),
4281 : strerror(errno));
4282 0 : goto done;
4283 : }
4284 :
4285 0 : ret = sys_acl_create_entry(&new_file_acl, &group_ent);
4286 0 : if (ret == -1) {
4287 0 : status = map_nt_error_from_unix(errno);
4288 0 : DBG_INFO("Failed to create group entry for file %s. (%s)\n",
4289 : fsp_str_dbg(fsp),
4290 : strerror(errno));
4291 0 : goto done;
4292 : }
4293 0 : ret = sys_acl_set_tag_type(group_ent, SMB_ACL_GROUP_OBJ);
4294 0 : if (ret == -1) {
4295 0 : status = map_nt_error_from_unix(errno);
4296 0 : DBG_INFO("Failed to set group entry for file %s. (%s)\n",
4297 : fsp_str_dbg(fsp),
4298 : strerror(errno));
4299 0 : goto done;
4300 : }
4301 :
4302 0 : ret = sys_acl_create_entry(&new_file_acl, &other_ent);
4303 0 : if (ret == -1) {
4304 0 : status = map_nt_error_from_unix(errno);
4305 0 : DBG_INFO("Failed to create other entry for file %s. (%s)\n",
4306 : fsp_str_dbg(fsp),
4307 : strerror(errno));
4308 0 : goto done;
4309 : }
4310 0 : ret = sys_acl_set_tag_type(other_ent, SMB_ACL_OTHER);
4311 0 : if (ret == -1) {
4312 0 : status = map_nt_error_from_unix(errno);
4313 0 : DBG_INFO("Failed to set other entry for file %s. (%s)\n",
4314 : fsp_str_dbg(fsp),
4315 : strerror(errno));
4316 0 : goto done;
4317 : }
4318 :
4319 : /* Get the current file ACL. */
4320 0 : file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
4321 : SMB_ACL_TYPE_ACCESS,
4322 : talloc_tos());
4323 :
4324 0 : if (file_acl == NULL) {
4325 0 : status = map_nt_error_from_unix(errno);
4326 : /* This is only returned if an error occurred. Even for a file with
4327 : no acl a u/g/w acl should be returned. */
4328 0 : DBG_INFO("failed to get ACL from file %s (%s).\n",
4329 : fsp_str_dbg(fsp),
4330 : strerror(errno));
4331 0 : goto done;
4332 : }
4333 :
4334 0 : while ( sys_acl_get_entry(file_acl, entry_id, &entry) == 1) {
4335 : SMB_ACL_TAG_T tagtype;
4336 : SMB_ACL_PERMSET_T permset;
4337 :
4338 0 : entry_id = SMB_ACL_NEXT_ENTRY;
4339 :
4340 0 : ret = sys_acl_get_tag_type(entry, &tagtype);
4341 0 : if (ret == -1) {
4342 0 : status = map_nt_error_from_unix(errno);
4343 0 : DBG_INFO("failed to get tagtype from ACL "
4344 : "on file %s (%s).\n",
4345 : fsp_str_dbg(fsp),
4346 : strerror(errno));
4347 0 : goto done;
4348 : }
4349 :
4350 0 : ret = sys_acl_get_permset(entry, &permset);
4351 0 : if (ret == -1) {
4352 0 : status = map_nt_error_from_unix(errno);
4353 0 : DBG_INFO("failed to get permset from ACL "
4354 : "on file %s (%s).\n",
4355 : fsp_str_dbg(fsp),
4356 : strerror(errno));
4357 0 : goto done;
4358 : }
4359 :
4360 0 : if (tagtype == SMB_ACL_USER_OBJ) {
4361 0 : ret = sys_acl_set_permset(user_ent, permset);
4362 0 : if (ret == -1) {
4363 0 : status = map_nt_error_from_unix(errno);
4364 0 : DBG_INFO("failed to set permset from ACL "
4365 : "on file %s (%s).\n",
4366 : fsp_str_dbg(fsp),
4367 : strerror(errno));
4368 0 : goto done;
4369 : }
4370 0 : } else if (tagtype == SMB_ACL_GROUP_OBJ) {
4371 0 : ret = sys_acl_set_permset(group_ent, permset);
4372 0 : if (ret == -1) {
4373 0 : status = map_nt_error_from_unix(errno);
4374 0 : DBG_INFO("failed to set permset from ACL "
4375 : "on file %s (%s).\n",
4376 : fsp_str_dbg(fsp),
4377 : strerror(errno));
4378 0 : goto done;
4379 : }
4380 0 : } else if (tagtype == SMB_ACL_OTHER) {
4381 0 : ret = sys_acl_set_permset(other_ent, permset);
4382 0 : if (ret == -1) {
4383 0 : status = map_nt_error_from_unix(errno);
4384 0 : DBG_INFO("failed to set permset from ACL "
4385 : "on file %s (%s).\n",
4386 : fsp_str_dbg(fsp),
4387 : strerror(errno));
4388 0 : goto done;
4389 : }
4390 : }
4391 : }
4392 :
4393 : /* Set the new empty file ACL. */
4394 0 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp, SMB_ACL_TYPE_ACCESS, new_file_acl);
4395 0 : if (ret == -1) {
4396 0 : status = map_nt_error_from_unix(errno);
4397 0 : DBG_INFO("acl_set_file failed on %s (%s)\n",
4398 : fsp_str_dbg(fsp),
4399 : strerror(errno));
4400 0 : goto done;
4401 : }
4402 :
4403 0 : status = NT_STATUS_OK;
4404 :
4405 0 : done:
4406 :
4407 0 : TALLOC_FREE(file_acl);
4408 0 : TALLOC_FREE(new_file_acl);
4409 0 : return status;
4410 : }
4411 :
4412 : /****************************************************************************
4413 : Calls from UNIX extensions - POSIX ACL set.
4414 : If num_def_acls == 0 then read/modify/write acl after removing all entries
4415 : except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
4416 : ****************************************************************************/
4417 :
4418 0 : NTSTATUS set_unix_posix_acl(connection_struct *conn,
4419 : files_struct *fsp,
4420 : uint16_t num_acls,
4421 : const char *pdata)
4422 : {
4423 0 : SMB_ACL_T file_acl = NULL;
4424 : int ret;
4425 : NTSTATUS status;
4426 :
4427 0 : if (!num_acls) {
4428 : /* Remove the ACL from the file. */
4429 0 : return remove_posix_acl(conn, fsp);
4430 : }
4431 :
4432 0 : file_acl = create_posix_acl_from_wire(conn,
4433 : num_acls,
4434 : pdata,
4435 : talloc_tos());
4436 0 : if (file_acl == NULL) {
4437 0 : return map_nt_error_from_unix(errno);
4438 : }
4439 :
4440 0 : ret = SMB_VFS_SYS_ACL_SET_FD(fsp, SMB_ACL_TYPE_ACCESS, file_acl);
4441 0 : if (ret == -1) {
4442 0 : status = map_nt_error_from_unix(errno);
4443 0 : DBG_INFO("acl_set_file failed on %s (%s)\n",
4444 : fsp_str_dbg(fsp),
4445 : strerror(errno));
4446 0 : TALLOC_FREE(file_acl);
4447 0 : return status;
4448 : }
4449 :
4450 0 : DBG_DEBUG("set acl for file %s\n",
4451 : fsp_str_dbg(fsp));
4452 :
4453 0 : TALLOC_FREE(file_acl);
4454 0 : return NT_STATUS_OK;
4455 : }
4456 :
4457 0 : int posix_sys_acl_blob_get_file(vfs_handle_struct *handle,
4458 : const struct smb_filename *smb_fname_in,
4459 : TALLOC_CTX *mem_ctx,
4460 : char **blob_description,
4461 : DATA_BLOB *blob)
4462 : {
4463 : int ret;
4464 0 : TALLOC_CTX *frame = talloc_stackframe();
4465 : /* Initialise this to zero, in a portable way */
4466 0 : struct smb_acl_wrapper acl_wrapper = {
4467 : 0
4468 : };
4469 0 : struct smb_filename *smb_fname = cp_smb_filename_nostream(frame,
4470 : smb_fname_in);
4471 0 : if (smb_fname == NULL) {
4472 0 : TALLOC_FREE(frame);
4473 0 : errno = ENOMEM;
4474 0 : return -1;
4475 : }
4476 :
4477 0 : ret = smb_vfs_call_stat(handle, smb_fname);
4478 0 : if (ret == -1) {
4479 0 : TALLOC_FREE(frame);
4480 0 : return -1;
4481 : }
4482 :
4483 0 : acl_wrapper.owner = smb_fname->st.st_ex_uid;
4484 0 : acl_wrapper.group = smb_fname->st.st_ex_gid;
4485 0 : acl_wrapper.mode = smb_fname->st.st_ex_mode;
4486 :
4487 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4488 : &acl_wrapper,
4489 : (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4490 0 : errno = EINVAL;
4491 0 : TALLOC_FREE(frame);
4492 0 : return -1;
4493 : }
4494 :
4495 0 : *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4496 0 : if (!*blob_description) {
4497 0 : errno = EINVAL;
4498 0 : TALLOC_FREE(frame);
4499 0 : return -1;
4500 : }
4501 :
4502 0 : TALLOC_FREE(frame);
4503 0 : return 0;
4504 : }
4505 :
4506 779423 : int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
4507 : files_struct *fsp,
4508 : TALLOC_CTX *mem_ctx,
4509 : char **blob_description,
4510 : DATA_BLOB *blob)
4511 : {
4512 : SMB_STRUCT_STAT sbuf;
4513 : TALLOC_CTX *frame;
4514 779423 : struct smb_acl_wrapper acl_wrapper = { 0 };
4515 : int ret;
4516 :
4517 779423 : frame = talloc_stackframe();
4518 :
4519 779423 : acl_wrapper.access_acl = smb_vfs_call_sys_acl_get_fd(handle,
4520 : fsp,
4521 : SMB_ACL_TYPE_ACCESS,
4522 : frame);
4523 :
4524 779423 : if (fsp->fsp_flags.is_directory) {
4525 453859 : acl_wrapper.default_acl = smb_vfs_call_sys_acl_get_fd(handle,
4526 : fsp,
4527 : SMB_ACL_TYPE_DEFAULT,
4528 : frame);
4529 : }
4530 :
4531 779423 : ret = smb_vfs_call_fstat(handle, fsp, &sbuf);
4532 779423 : if (ret == -1) {
4533 0 : TALLOC_FREE(frame);
4534 0 : return -1;
4535 : }
4536 :
4537 779423 : acl_wrapper.owner = sbuf.st_ex_uid;
4538 779423 : acl_wrapper.group = sbuf.st_ex_gid;
4539 779423 : acl_wrapper.mode = sbuf.st_ex_mode;
4540 :
4541 779423 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4542 : &acl_wrapper,
4543 : (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4544 0 : errno = EINVAL;
4545 0 : TALLOC_FREE(frame);
4546 0 : return -1;
4547 : }
4548 :
4549 779423 : *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4550 779423 : if (!*blob_description) {
4551 0 : errno = EINVAL;
4552 0 : TALLOC_FREE(frame);
4553 0 : return -1;
4554 : }
4555 :
4556 779423 : TALLOC_FREE(frame);
4557 778164 : return 0;
4558 : }
4559 :
4560 134 : static NTSTATUS make_default_acl_posix(TALLOC_CTX *ctx,
4561 : const char *name,
4562 : const SMB_STRUCT_STAT *psbuf,
4563 : struct security_descriptor **ppdesc)
4564 : {
4565 : struct dom_sid owner_sid, group_sid;
4566 134 : size_t size = 0;
4567 : struct security_ace aces[4];
4568 134 : uint32_t access_mask = 0;
4569 134 : mode_t mode = psbuf->st_ex_mode;
4570 134 : struct security_acl *new_dacl = NULL;
4571 134 : int idx = 0;
4572 :
4573 134 : DBG_DEBUG("file %s mode = 0%o\n",name, (int)mode);
4574 :
4575 134 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4576 134 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4577 :
4578 : /*
4579 : We provide up to 4 ACEs
4580 : - Owner
4581 : - Group
4582 : - Everyone
4583 : - NT System
4584 : */
4585 :
4586 134 : if (mode & S_IRUSR) {
4587 134 : if (mode & S_IWUSR) {
4588 134 : access_mask |= SEC_RIGHTS_FILE_ALL;
4589 : } else {
4590 0 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4591 : }
4592 : }
4593 134 : if (mode & S_IWUSR) {
4594 134 : access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4595 : }
4596 :
4597 134 : init_sec_ace(&aces[idx],
4598 : &owner_sid,
4599 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4600 : access_mask,
4601 : 0);
4602 134 : idx++;
4603 :
4604 134 : access_mask = 0;
4605 134 : if (mode & S_IRGRP) {
4606 134 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4607 : }
4608 134 : if (mode & S_IWGRP) {
4609 : /* note that delete is not granted - this matches posix behaviour */
4610 134 : access_mask |= SEC_RIGHTS_FILE_WRITE;
4611 : }
4612 134 : if (access_mask) {
4613 134 : init_sec_ace(&aces[idx],
4614 : &group_sid,
4615 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4616 : access_mask,
4617 : 0);
4618 134 : idx++;
4619 : }
4620 :
4621 134 : access_mask = 0;
4622 134 : if (mode & S_IROTH) {
4623 134 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4624 : }
4625 134 : if (mode & S_IWOTH) {
4626 134 : access_mask |= SEC_RIGHTS_FILE_WRITE;
4627 : }
4628 134 : if (access_mask) {
4629 134 : init_sec_ace(&aces[idx],
4630 : &global_sid_World,
4631 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4632 : access_mask,
4633 : 0);
4634 134 : idx++;
4635 : }
4636 :
4637 134 : init_sec_ace(&aces[idx],
4638 : &global_sid_System,
4639 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4640 : SEC_RIGHTS_FILE_ALL,
4641 : 0);
4642 134 : idx++;
4643 :
4644 134 : new_dacl = make_sec_acl(ctx,
4645 : NT4_ACL_REVISION,
4646 : idx,
4647 : aces);
4648 :
4649 134 : if (!new_dacl) {
4650 0 : return NT_STATUS_NO_MEMORY;
4651 : }
4652 :
4653 134 : *ppdesc = make_sec_desc(ctx,
4654 : SECURITY_DESCRIPTOR_REVISION_1,
4655 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4656 : &owner_sid,
4657 : &group_sid,
4658 : NULL,
4659 : new_dacl,
4660 : &size);
4661 134 : if (!*ppdesc) {
4662 0 : return NT_STATUS_NO_MEMORY;
4663 : }
4664 134 : return NT_STATUS_OK;
4665 : }
4666 :
4667 110 : static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
4668 : const char *name,
4669 : const SMB_STRUCT_STAT *psbuf,
4670 : struct security_descriptor **ppdesc)
4671 : {
4672 : struct dom_sid owner_sid, group_sid;
4673 110 : size_t size = 0;
4674 : struct security_ace aces[4];
4675 110 : uint32_t access_mask = 0;
4676 110 : mode_t mode = psbuf->st_ex_mode;
4677 110 : struct security_acl *new_dacl = NULL;
4678 110 : int idx = 0;
4679 :
4680 110 : DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
4681 :
4682 110 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4683 110 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4684 :
4685 : /*
4686 : * We provide 2 ACEs:
4687 : * - Owner
4688 : * - NT System
4689 : */
4690 :
4691 110 : if (mode & S_IRUSR) {
4692 110 : if (mode & S_IWUSR) {
4693 110 : access_mask |= SEC_RIGHTS_FILE_ALL;
4694 : } else {
4695 0 : access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4696 : }
4697 : }
4698 110 : if (mode & S_IWUSR) {
4699 110 : access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4700 : }
4701 :
4702 110 : init_sec_ace(&aces[idx],
4703 : &owner_sid,
4704 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4705 : access_mask,
4706 : 0);
4707 110 : idx++;
4708 :
4709 110 : init_sec_ace(&aces[idx],
4710 : &global_sid_System,
4711 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4712 : SEC_RIGHTS_FILE_ALL,
4713 : 0);
4714 110 : idx++;
4715 :
4716 110 : new_dacl = make_sec_acl(ctx,
4717 : NT4_ACL_REVISION,
4718 : idx,
4719 : aces);
4720 :
4721 110 : if (!new_dacl) {
4722 0 : return NT_STATUS_NO_MEMORY;
4723 : }
4724 :
4725 110 : *ppdesc = make_sec_desc(ctx,
4726 : SECURITY_DESCRIPTOR_REVISION_1,
4727 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4728 : &owner_sid,
4729 : &group_sid,
4730 : NULL,
4731 : new_dacl,
4732 : &size);
4733 110 : if (!*ppdesc) {
4734 0 : return NT_STATUS_NO_MEMORY;
4735 : }
4736 110 : return NT_STATUS_OK;
4737 : }
4738 :
4739 3052 : static NTSTATUS make_default_acl_everyone(TALLOC_CTX *ctx,
4740 : const char *name,
4741 : const SMB_STRUCT_STAT *psbuf,
4742 : struct security_descriptor **ppdesc)
4743 : {
4744 : struct dom_sid owner_sid, group_sid;
4745 3052 : size_t size = 0;
4746 : struct security_ace aces[1];
4747 3052 : mode_t mode = psbuf->st_ex_mode;
4748 3052 : struct security_acl *new_dacl = NULL;
4749 3052 : int idx = 0;
4750 :
4751 3052 : DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
4752 :
4753 3052 : uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4754 3052 : gid_to_sid(&group_sid, psbuf->st_ex_gid);
4755 :
4756 : /*
4757 : * We provide one ACEs: full access for everyone
4758 : */
4759 :
4760 3052 : init_sec_ace(&aces[idx],
4761 : &global_sid_World,
4762 : SEC_ACE_TYPE_ACCESS_ALLOWED,
4763 : SEC_RIGHTS_FILE_ALL,
4764 : 0);
4765 3052 : idx++;
4766 :
4767 3052 : new_dacl = make_sec_acl(ctx,
4768 : NT4_ACL_REVISION,
4769 : idx,
4770 : aces);
4771 :
4772 3052 : if (!new_dacl) {
4773 0 : return NT_STATUS_NO_MEMORY;
4774 : }
4775 :
4776 3052 : *ppdesc = make_sec_desc(ctx,
4777 : SECURITY_DESCRIPTOR_REVISION_1,
4778 : SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4779 : &owner_sid,
4780 : &group_sid,
4781 : NULL,
4782 : new_dacl,
4783 : &size);
4784 3052 : if (!*ppdesc) {
4785 0 : return NT_STATUS_NO_MEMORY;
4786 : }
4787 3052 : return NT_STATUS_OK;
4788 : }
4789 :
4790 : static const struct enum_list default_acl_style_list[] = {
4791 : {DEFAULT_ACL_POSIX, "posix"},
4792 : {DEFAULT_ACL_WINDOWS, "windows"},
4793 : {DEFAULT_ACL_EVERYONE, "everyone"},
4794 : };
4795 :
4796 43373 : const struct enum_list *get_default_acl_style_list(void)
4797 : {
4798 43373 : return default_acl_style_list;
4799 : }
4800 :
4801 3296 : NTSTATUS make_default_filesystem_acl(
4802 : TALLOC_CTX *ctx,
4803 : enum default_acl_style acl_style,
4804 : const char *name,
4805 : const SMB_STRUCT_STAT *psbuf,
4806 : struct security_descriptor **ppdesc)
4807 : {
4808 : NTSTATUS status;
4809 :
4810 3296 : switch (acl_style) {
4811 134 : case DEFAULT_ACL_POSIX:
4812 134 : status = make_default_acl_posix(ctx, name, psbuf, ppdesc);
4813 134 : break;
4814 :
4815 110 : case DEFAULT_ACL_WINDOWS:
4816 110 : status = make_default_acl_windows(ctx, name, psbuf, ppdesc);
4817 110 : break;
4818 :
4819 3052 : case DEFAULT_ACL_EVERYONE:
4820 3052 : status = make_default_acl_everyone(ctx, name, psbuf, ppdesc);
4821 3052 : break;
4822 :
4823 0 : default:
4824 0 : DBG_ERR("unknown acl style %d", acl_style);
4825 0 : status = NT_STATUS_INTERNAL_ERROR;
4826 0 : break;
4827 : }
4828 :
4829 3296 : return status;
4830 : }
|