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