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