blob: e7623102a6c80956cfe384fa7dd19282a46ff7f5
1 | /** |
2 | * acls.c - General function to process NTFS ACLs |
3 | * |
4 | * This module is part of ntfs-3g library, but may also be |
5 | * integrated in tools running over Linux or Windows |
6 | * |
7 | * Copyright (c) 2007-2012 Jean-Pierre Andre |
8 | * |
9 | * This program/include file is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as published |
11 | * by the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This program/include file is distributed in the hope that it will be |
15 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program (in the main directory of the NTFS-3G |
21 | * distribution in the file COPYING); if not, write to the Free Software |
22 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ |
24 | |
25 | #ifdef HAVE_CONFIG_H |
26 | /* |
27 | * integration into ntfs-3g |
28 | */ |
29 | #include "config.h" |
30 | |
31 | #ifdef HAVE_STDIO_H |
32 | #include <stdio.h> |
33 | #endif |
34 | #ifdef HAVE_STDLIB_H |
35 | #include <stdlib.h> |
36 | #endif |
37 | #ifdef HAVE_STRING_H |
38 | #include <string.h> |
39 | #endif |
40 | #ifdef HAVE_ERRNO_H |
41 | #include <errno.h> |
42 | #endif |
43 | #ifdef HAVE_SYS_STAT_H |
44 | #include <sys/stat.h> |
45 | #endif |
46 | #ifdef HAVE_FCNTL_H |
47 | #include <fcntl.h> |
48 | #endif |
49 | #ifdef HAVE_SYSLOG_H |
50 | #include <syslog.h> |
51 | #endif |
52 | #include <unistd.h> |
53 | #include <pwd.h> |
54 | #include <grp.h> |
55 | |
56 | #include "types.h" |
57 | #include "layout.h" |
58 | #include "security.h" |
59 | #include "acls.h" |
60 | #include "misc.h" |
61 | #else |
62 | |
63 | /* |
64 | * integration into secaudit, check whether Win32, |
65 | * may have to be adapted to compiler or something else |
66 | */ |
67 | |
68 | #ifndef WIN32 |
69 | #if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) |
70 | #define WIN32 1 |
71 | #endif |
72 | #endif |
73 | |
74 | #include <stdio.h> |
75 | #include <time.h> |
76 | #include <string.h> |
77 | #include <stdlib.h> |
78 | #include <stdarg.h> |
79 | #include <sys/types.h> |
80 | #include <errno.h> |
81 | |
82 | /* |
83 | * integration into secaudit/Win32 |
84 | */ |
85 | #ifdef WIN32 |
86 | #include <fcntl.h> |
87 | #include <windows.h> |
88 | #define __LITTLE_ENDIAN 1234 |
89 | #define __BYTE_ORDER __LITTLE_ENDIAN |
90 | #else |
91 | /* |
92 | * integration into secaudit/STSC |
93 | */ |
94 | #ifdef STSC |
95 | #include <stat.h> |
96 | #undef __BYTE_ORDER |
97 | #define __BYTE_ORDER __BIG_ENDIAN |
98 | #else |
99 | /* |
100 | * integration into secaudit/Linux |
101 | */ |
102 | #include <sys/stat.h> |
103 | #include <endian.h> |
104 | #include <unistd.h> |
105 | #include <dlfcn.h> |
106 | #endif /* STSC */ |
107 | #endif /* WIN32 */ |
108 | #include "secaudit.h" |
109 | #endif /* HAVE_CONFIG_H */ |
110 | |
111 | /* |
112 | * A few useful constants |
113 | */ |
114 | |
115 | /* |
116 | * null SID (S-1-0-0) |
117 | */ |
118 | |
119 | static const char nullsidbytes[] = { |
120 | 1, /* revision */ |
121 | 1, /* auth count */ |
122 | 0, 0, 0, 0, 0, 0, /* base */ |
123 | 0, 0, 0, 0 /* 1st level */ |
124 | }; |
125 | |
126 | static const SID *nullsid = (const SID*)nullsidbytes; |
127 | |
128 | /* |
129 | * SID for world (S-1-1-0) |
130 | */ |
131 | |
132 | static const char worldsidbytes[] = { |
133 | 1, /* revision */ |
134 | 1, /* auth count */ |
135 | 0, 0, 0, 0, 0, 1, /* base */ |
136 | 0, 0, 0, 0 /* 1st level */ |
137 | } ; |
138 | |
139 | /* |
140 | * SID for authenticated user (S-1-5-11) |
141 | */ |
142 | |
143 | static const char authsidbytes[] = { |
144 | 1, /* revision */ |
145 | 1, /* auth count */ |
146 | 0, 0, 0, 0, 0, 5, /* base */ |
147 | 11, 0, 0, 0 /* 1st level */ |
148 | }; |
149 | |
150 | static const SID *authsid = (const SID*)authsidbytes; |
151 | |
152 | const SID *worldsid = (const SID*)worldsidbytes; |
153 | |
154 | /* |
155 | * SID for administrator |
156 | */ |
157 | |
158 | static const char adminsidbytes[] = { |
159 | 1, /* revision */ |
160 | 2, /* auth count */ |
161 | 0, 0, 0, 0, 0, 5, /* base */ |
162 | 32, 0, 0, 0, /* 1st level */ |
163 | 32, 2, 0, 0 /* 2nd level */ |
164 | }; |
165 | |
166 | const SID *adminsid = (const SID*)adminsidbytes; |
167 | |
168 | /* |
169 | * SID for system |
170 | */ |
171 | |
172 | static const char systemsidbytes[] = { |
173 | 1, /* revision */ |
174 | 1, /* auth count */ |
175 | 0, 0, 0, 0, 0, 5, /* base */ |
176 | 18, 0, 0, 0 /* 1st level */ |
177 | }; |
178 | |
179 | static const SID *systemsid = (const SID*)systemsidbytes; |
180 | |
181 | /* |
182 | * SID for generic creator-owner |
183 | * S-1-3-0 |
184 | */ |
185 | |
186 | static const char ownersidbytes[] = { |
187 | 1, /* revision */ |
188 | 1, /* auth count */ |
189 | 0, 0, 0, 0, 0, 3, /* base */ |
190 | 0, 0, 0, 0 /* 1st level */ |
191 | } ; |
192 | |
193 | static const SID *ownersid = (const SID*)ownersidbytes; |
194 | |
195 | /* |
196 | * SID for generic creator-group |
197 | * S-1-3-1 |
198 | */ |
199 | |
200 | static const char groupsidbytes[] = { |
201 | 1, /* revision */ |
202 | 1, /* auth count */ |
203 | 0, 0, 0, 0, 0, 3, /* base */ |
204 | 1, 0, 0, 0 /* 1st level */ |
205 | } ; |
206 | |
207 | static const SID *groupsid = (const SID*)groupsidbytes; |
208 | |
209 | /* |
210 | * Determine the size of a SID |
211 | */ |
212 | |
213 | int ntfs_sid_size(const SID * sid) |
214 | { |
215 | return (sid->sub_authority_count * 4 + 8); |
216 | } |
217 | |
218 | /* |
219 | * Test whether two SID are equal |
220 | */ |
221 | |
222 | BOOL ntfs_same_sid(const SID *first, const SID *second) |
223 | { |
224 | int size; |
225 | |
226 | size = ntfs_sid_size(first); |
227 | return ((ntfs_sid_size(second) == size) |
228 | && !memcmp(first, second, size)); |
229 | } |
230 | |
231 | /* |
232 | * Test whether a SID means "world user" |
233 | * Local users group also recognized as world |
234 | */ |
235 | |
236 | static int is_world_sid(const SID * usid) |
237 | { |
238 | return ( |
239 | /* check whether S-1-1-0 : world */ |
240 | ((usid->sub_authority_count == 1) |
241 | && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) |
242 | && (usid->identifier_authority.low_part == const_cpu_to_be32(1)) |
243 | && (usid->sub_authority[0] == const_cpu_to_le32(0))) |
244 | |
245 | /* check whether S-1-5-32-545 : local user */ |
246 | || ((usid->sub_authority_count == 2) |
247 | && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) |
248 | && (usid->identifier_authority.low_part == const_cpu_to_be32(5)) |
249 | && (usid->sub_authority[0] == const_cpu_to_le32(32)) |
250 | && (usid->sub_authority[1] == const_cpu_to_le32(545))) |
251 | |
252 | /* check whether S-1-5-11 : authenticated user */ |
253 | || ((usid->sub_authority_count == 1) |
254 | && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) |
255 | && (usid->identifier_authority.low_part == const_cpu_to_be32(5)) |
256 | && (usid->sub_authority[0] == const_cpu_to_le32(11))) |
257 | ); |
258 | } |
259 | |
260 | /* |
261 | * Test whether a SID means "some user (or group)" |
262 | * Currently we only check for S-1-5-21... but we should |
263 | * probably test for other configurations |
264 | */ |
265 | |
266 | BOOL ntfs_is_user_sid(const SID *usid) |
267 | { |
268 | return ((usid->sub_authority_count == 5) |
269 | && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) |
270 | && (usid->identifier_authority.low_part == const_cpu_to_be32(5)) |
271 | && (usid->sub_authority[0] == const_cpu_to_le32(21))); |
272 | } |
273 | |
274 | /* |
275 | * Determine the size of a security attribute |
276 | * whatever the order of fields |
277 | */ |
278 | |
279 | unsigned int ntfs_attr_size(const char *attr) |
280 | { |
281 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
282 | const ACL *pdacl; |
283 | const ACL *psacl; |
284 | const SID *psid; |
285 | unsigned int offdacl; |
286 | unsigned int offsacl; |
287 | unsigned int offowner; |
288 | unsigned int offgroup; |
289 | unsigned int endsid; |
290 | unsigned int endacl; |
291 | unsigned int attrsz; |
292 | |
293 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
294 | /* |
295 | * First check group, which is the last field in all descriptors |
296 | * we build, and in most descriptors built by Windows |
297 | */ |
298 | attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE); |
299 | offgroup = le32_to_cpu(phead->group); |
300 | if (offgroup >= attrsz) { |
301 | /* find end of GSID */ |
302 | psid = (const SID*)&attr[offgroup]; |
303 | endsid = offgroup + ntfs_sid_size(psid); |
304 | if (endsid > attrsz) attrsz = endsid; |
305 | } |
306 | offowner = le32_to_cpu(phead->owner); |
307 | if (offowner >= attrsz) { |
308 | /* find end of USID */ |
309 | psid = (const SID*)&attr[offowner]; |
310 | endsid = offowner + ntfs_sid_size(psid); |
311 | attrsz = endsid; |
312 | } |
313 | offsacl = le32_to_cpu(phead->sacl); |
314 | if (offsacl >= attrsz) { |
315 | /* find end of SACL */ |
316 | psacl = (const ACL*)&attr[offsacl]; |
317 | endacl = offsacl + le16_to_cpu(psacl->size); |
318 | if (endacl > attrsz) |
319 | attrsz = endacl; |
320 | } |
321 | |
322 | |
323 | /* find end of DACL */ |
324 | offdacl = le32_to_cpu(phead->dacl); |
325 | if (offdacl >= attrsz) { |
326 | pdacl = (const ACL*)&attr[offdacl]; |
327 | endacl = offdacl + le16_to_cpu(pdacl->size); |
328 | if (endacl > attrsz) |
329 | attrsz = endacl; |
330 | } |
331 | return (attrsz); |
332 | } |
333 | |
334 | /* |
335 | * Do sanity checks on a SID read from storage |
336 | * (just check revision and number of authorities) |
337 | */ |
338 | |
339 | BOOL ntfs_valid_sid(const SID *sid) |
340 | { |
341 | return ((sid->revision == SID_REVISION) |
342 | && (sid->sub_authority_count >= 1) |
343 | && (sid->sub_authority_count <= 8)); |
344 | } |
345 | |
346 | /* |
347 | * Check whether a SID is acceptable for an implicit |
348 | * mapping pattern. |
349 | * It should have been already checked it is a valid user SID. |
350 | * |
351 | * The last authority reference has to be >= 1000 (Windows usage) |
352 | * and <= 0x7fffffff, so that 30 bits from a uid and 30 more bits |
353 | * from a gid an be inserted with no overflow. |
354 | */ |
355 | |
356 | BOOL ntfs_valid_pattern(const SID *sid) |
357 | { |
358 | int cnt; |
359 | u32 auth; |
360 | le32 leauth; |
361 | |
362 | cnt = sid->sub_authority_count; |
363 | leauth = sid->sub_authority[cnt-1]; |
364 | auth = le32_to_cpu(leauth); |
365 | return ((auth >= 1000) && (auth <= 0x7fffffff)); |
366 | } |
367 | |
368 | /* |
369 | * Compute the uid or gid associated to a SID |
370 | * through an implicit mapping |
371 | * |
372 | * Returns 0 (root) if it does not match pattern |
373 | */ |
374 | |
375 | static u32 findimplicit(const SID *xsid, const SID *pattern, int parity) |
376 | { |
377 | BIGSID defsid; |
378 | SID *psid; |
379 | u32 xid; /* uid or gid */ |
380 | int cnt; |
381 | u32 carry; |
382 | le32 leauth; |
383 | u32 uauth; |
384 | u32 xlast; |
385 | u32 rlast; |
386 | |
387 | memcpy(&defsid,pattern,ntfs_sid_size(pattern)); |
388 | psid = (SID*)&defsid; |
389 | cnt = psid->sub_authority_count; |
390 | xid = 0; |
391 | if (xsid->sub_authority_count == cnt) { |
392 | psid->sub_authority[cnt-1] = xsid->sub_authority[cnt-1]; |
393 | leauth = xsid->sub_authority[cnt-1]; |
394 | xlast = le32_to_cpu(leauth); |
395 | leauth = pattern->sub_authority[cnt-1]; |
396 | rlast = le32_to_cpu(leauth); |
397 | |
398 | if ((xlast > rlast) && !((xlast ^ rlast ^ parity) & 1)) { |
399 | /* direct check for basic situation */ |
400 | if (ntfs_same_sid(psid,xsid)) |
401 | xid = ((xlast - rlast) >> 1) & 0x3fffffff; |
402 | else { |
403 | /* |
404 | * check whether part of mapping had to be |
405 | * recorded in a higher level authority |
406 | */ |
407 | carry = 1; |
408 | do { |
409 | leauth = psid->sub_authority[cnt-2]; |
410 | uauth = le32_to_cpu(leauth) + 1; |
411 | psid->sub_authority[cnt-2] |
412 | = cpu_to_le32(uauth); |
413 | } while (!ntfs_same_sid(psid,xsid) |
414 | && (++carry < 4)); |
415 | if (carry < 4) |
416 | xid = (((xlast - rlast) >> 1) |
417 | & 0x3fffffff) | (carry << 30); |
418 | } |
419 | } |
420 | } |
421 | return (xid); |
422 | } |
423 | |
424 | /* |
425 | * Find usid mapped to a Linux user |
426 | * Returns NULL if not found |
427 | */ |
428 | |
429 | const SID *ntfs_find_usid(const struct MAPPING* usermapping, |
430 | uid_t uid, SID *defusid) |
431 | { |
432 | const struct MAPPING *p; |
433 | const SID *sid; |
434 | le32 leauth; |
435 | u32 uauth; |
436 | int cnt; |
437 | |
438 | if (!uid) |
439 | sid = adminsid; |
440 | else { |
441 | p = usermapping; |
442 | while (p && p->xid && ((uid_t)p->xid != uid)) |
443 | p = p->next; |
444 | if (p && !p->xid) { |
445 | /* |
446 | * default pattern has been reached : |
447 | * build an implicit SID according to pattern |
448 | * (the pattern format was checked while reading |
449 | * the mapping file) |
450 | */ |
451 | memcpy(defusid, p->sid, ntfs_sid_size(p->sid)); |
452 | cnt = defusid->sub_authority_count; |
453 | leauth = defusid->sub_authority[cnt-1]; |
454 | uauth = le32_to_cpu(leauth) + 2*(uid & 0x3fffffff); |
455 | defusid->sub_authority[cnt-1] = cpu_to_le32(uauth); |
456 | if (uid & 0xc0000000) { |
457 | leauth = defusid->sub_authority[cnt-2]; |
458 | uauth = le32_to_cpu(leauth) + ((uid >> 30) & 3); |
459 | defusid->sub_authority[cnt-2] = cpu_to_le32(uauth); |
460 | } |
461 | sid = defusid; |
462 | } else |
463 | sid = (p ? p->sid : (const SID*)NULL); |
464 | } |
465 | return (sid); |
466 | } |
467 | |
468 | /* |
469 | * Find Linux group mapped to a gsid |
470 | * Returns 0 (root) if not found |
471 | */ |
472 | |
473 | const SID *ntfs_find_gsid(const struct MAPPING* groupmapping, |
474 | gid_t gid, SID *defgsid) |
475 | { |
476 | const struct MAPPING *p; |
477 | const SID *sid; |
478 | le32 leauth; |
479 | u32 uauth; |
480 | int cnt; |
481 | |
482 | if (!gid) |
483 | sid = adminsid; |
484 | else { |
485 | p = groupmapping; |
486 | while (p && p->xid && ((gid_t)p->xid != gid)) |
487 | p = p->next; |
488 | if (p && !p->xid) { |
489 | /* |
490 | * default pattern has been reached : |
491 | * build an implicit SID according to pattern |
492 | * (the pattern format was checked while reading |
493 | * the mapping file) |
494 | */ |
495 | memcpy(defgsid, p->sid, ntfs_sid_size(p->sid)); |
496 | cnt = defgsid->sub_authority_count; |
497 | leauth = defgsid->sub_authority[cnt-1]; |
498 | uauth = le32_to_cpu(leauth) + 2*(gid & 0x3fffffff) + 1; |
499 | defgsid->sub_authority[cnt-1] = cpu_to_le32(uauth); |
500 | if (gid & 0xc0000000) { |
501 | leauth = defgsid->sub_authority[cnt-2]; |
502 | uauth = le32_to_cpu(leauth) + ((gid >> 30) & 3); |
503 | defgsid->sub_authority[cnt-2] = cpu_to_le32(uauth); |
504 | } |
505 | sid = defgsid; |
506 | } else |
507 | sid = (p ? p->sid : (const SID*)NULL); |
508 | } |
509 | return (sid); |
510 | } |
511 | |
512 | /* |
513 | * Find Linux owner mapped to a usid |
514 | * Returns 0 (root) if not found |
515 | */ |
516 | |
517 | uid_t ntfs_find_user(const struct MAPPING* usermapping, const SID *usid) |
518 | { |
519 | uid_t uid; |
520 | const struct MAPPING *p; |
521 | |
522 | p = usermapping; |
523 | while (p && p->xid && !ntfs_same_sid(usid, p->sid)) |
524 | p = p->next; |
525 | if (p && !p->xid) |
526 | /* |
527 | * No explicit mapping found, try implicit mapping |
528 | */ |
529 | uid = findimplicit(usid,p->sid,0); |
530 | else |
531 | uid = (p ? p->xid : 0); |
532 | return (uid); |
533 | } |
534 | |
535 | /* |
536 | * Find Linux group mapped to a gsid |
537 | * Returns 0 (root) if not found |
538 | */ |
539 | |
540 | gid_t ntfs_find_group(const struct MAPPING* groupmapping, const SID * gsid) |
541 | { |
542 | gid_t gid; |
543 | const struct MAPPING *p; |
544 | |
545 | p = groupmapping; |
546 | while (p && p->xid && !ntfs_same_sid(gsid, p->sid)) |
547 | p = p->next; |
548 | if (p && !p->xid) |
549 | /* |
550 | * No explicit mapping found, try implicit mapping |
551 | */ |
552 | gid = findimplicit(gsid,p->sid,1); |
553 | else |
554 | gid = (p ? p->xid : 0); |
555 | return (gid); |
556 | } |
557 | |
558 | /* |
559 | * Check the validity of the ACEs in a DACL or SACL |
560 | */ |
561 | |
562 | static BOOL valid_acl(const ACL *pacl, unsigned int end) |
563 | { |
564 | const ACCESS_ALLOWED_ACE *pace; |
565 | unsigned int offace; |
566 | unsigned int acecnt; |
567 | unsigned int acesz; |
568 | unsigned int nace; |
569 | BOOL ok; |
570 | |
571 | ok = TRUE; |
572 | acecnt = le16_to_cpu(pacl->ace_count); |
573 | offace = sizeof(ACL); |
574 | for (nace = 0; (nace < acecnt) && ok; nace++) { |
575 | /* be sure the beginning is within range */ |
576 | if ((offace + sizeof(ACCESS_ALLOWED_ACE)) > end) |
577 | ok = FALSE; |
578 | else { |
579 | pace = (const ACCESS_ALLOWED_ACE*) |
580 | &((const char*)pacl)[offace]; |
581 | acesz = le16_to_cpu(pace->size); |
582 | if (((offace + acesz) > end) |
583 | || !ntfs_valid_sid(&pace->sid) |
584 | || ((ntfs_sid_size(&pace->sid) + 8) != (int)acesz)) |
585 | ok = FALSE; |
586 | offace += acesz; |
587 | } |
588 | } |
589 | return (ok); |
590 | } |
591 | |
592 | /* |
593 | * Do sanity checks on security descriptors read from storage |
594 | * basically, we make sure that every field holds within |
595 | * allocated storage |
596 | * Should not be called with a NULL argument |
597 | * returns TRUE if considered safe |
598 | * if not, error should be logged by caller |
599 | */ |
600 | |
601 | BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz) |
602 | { |
603 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
604 | const ACL *pdacl; |
605 | const ACL *psacl; |
606 | unsigned int offdacl; |
607 | unsigned int offsacl; |
608 | unsigned int offowner; |
609 | unsigned int offgroup; |
610 | BOOL ok; |
611 | |
612 | ok = TRUE; |
613 | |
614 | /* |
615 | * first check overall size if within allocation range |
616 | * and a DACL is present |
617 | * and owner and group SID are valid |
618 | */ |
619 | |
620 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
621 | offdacl = le32_to_cpu(phead->dacl); |
622 | offsacl = le32_to_cpu(phead->sacl); |
623 | offowner = le32_to_cpu(phead->owner); |
624 | offgroup = le32_to_cpu(phead->group); |
625 | pdacl = (const ACL*)&securattr[offdacl]; |
626 | psacl = (const ACL*)&securattr[offsacl]; |
627 | |
628 | /* |
629 | * size check occurs before the above pointers are used |
630 | * |
631 | * "DR Watson" standard directory on WinXP has an |
632 | * old revision and no DACL though SE_DACL_PRESENT is set |
633 | */ |
634 | if ((attrsz >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) |
635 | && (phead->revision == SECURITY_DESCRIPTOR_REVISION) |
636 | && (offowner >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) |
637 | && ((offowner + 2) < attrsz) |
638 | && (offgroup >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) |
639 | && ((offgroup + 2) < attrsz) |
640 | && (!offdacl |
641 | || ((offdacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) |
642 | && (offdacl+sizeof(ACL) <= attrsz))) |
643 | && (!offsacl |
644 | || ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) |
645 | && (offsacl+sizeof(ACL) <= attrsz))) |
646 | && !(phead->owner & const_cpu_to_le32(3)) |
647 | && !(phead->group & const_cpu_to_le32(3)) |
648 | && !(phead->dacl & const_cpu_to_le32(3)) |
649 | && !(phead->sacl & const_cpu_to_le32(3)) |
650 | && (ntfs_attr_size(securattr) <= attrsz) |
651 | && ntfs_valid_sid((const SID*)&securattr[offowner]) |
652 | && ntfs_valid_sid((const SID*)&securattr[offgroup]) |
653 | /* |
654 | * if there is an ACL, as indicated by offdacl, |
655 | * require SE_DACL_PRESENT |
656 | * but "Dr Watson" has SE_DACL_PRESENT though no DACL |
657 | */ |
658 | && (!offdacl |
659 | || ((phead->control & SE_DACL_PRESENT) |
660 | && ((pdacl->revision == ACL_REVISION) |
661 | || (pdacl->revision == ACL_REVISION_DS)))) |
662 | /* same for SACL */ |
663 | && (!offsacl |
664 | || ((phead->control & SE_SACL_PRESENT) |
665 | && ((psacl->revision == ACL_REVISION) |
666 | || (psacl->revision == ACL_REVISION_DS))))) { |
667 | /* |
668 | * Check the DACL and SACL if present |
669 | */ |
670 | if ((offdacl && !valid_acl(pdacl,attrsz - offdacl)) |
671 | || (offsacl && !valid_acl(psacl,attrsz - offsacl))) |
672 | ok = FALSE; |
673 | } else |
674 | ok = FALSE; |
675 | return (ok); |
676 | } |
677 | |
678 | /* |
679 | * Copy the inheritable parts of an ACL |
680 | * |
681 | * Returns the size of the new ACL |
682 | * or zero if nothing is inheritable |
683 | */ |
684 | |
685 | int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, |
686 | const SID *usid, const SID *gsid, BOOL fordir, |
687 | le16 inherited) |
688 | { |
689 | unsigned int src; |
690 | unsigned int dst; |
691 | int oldcnt; |
692 | int newcnt; |
693 | unsigned int selection; |
694 | int nace; |
695 | int acesz; |
696 | int usidsz; |
697 | int gsidsz; |
698 | const ACCESS_ALLOWED_ACE *poldace; |
699 | ACCESS_ALLOWED_ACE *pnewace; |
700 | ACCESS_ALLOWED_ACE *pauthace; |
701 | |
702 | pauthace = (ACCESS_ALLOWED_ACE*)NULL; |
703 | usidsz = ntfs_sid_size(usid); |
704 | gsidsz = ntfs_sid_size(gsid); |
705 | |
706 | /* ACL header */ |
707 | |
708 | newacl->revision = ACL_REVISION; |
709 | newacl->alignment1 = 0; |
710 | newacl->alignment2 = const_cpu_to_le16(0); |
711 | src = dst = sizeof(ACL); |
712 | |
713 | selection = (fordir ? CONTAINER_INHERIT_ACE : OBJECT_INHERIT_ACE); |
714 | newcnt = 0; |
715 | oldcnt = le16_to_cpu(oldacl->ace_count); |
716 | for (nace = 0; nace < oldcnt; nace++) { |
717 | poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src); |
718 | acesz = le16_to_cpu(poldace->size); |
719 | src += acesz; |
720 | /* |
721 | * Inheritance for access, unless this is inheriting |
722 | * an inherited ACL to a directory. |
723 | */ |
724 | if ((poldace->flags & selection) |
725 | && !(fordir && inherited) |
726 | && !ntfs_same_sid(&poldace->sid, ownersid) |
727 | && !ntfs_same_sid(&poldace->sid, groupsid)) { |
728 | pnewace = (ACCESS_ALLOWED_ACE*) |
729 | ((char*)newacl + dst); |
730 | memcpy(pnewace,poldace,acesz); |
731 | /* reencode GENERIC_ALL */ |
732 | if (pnewace->mask & GENERIC_ALL) { |
733 | pnewace->mask &= ~GENERIC_ALL; |
734 | if (fordir) |
735 | pnewace->mask |= OWNER_RIGHTS |
736 | | DIR_READ |
737 | | DIR_WRITE |
738 | | DIR_EXEC; |
739 | else |
740 | /* |
741 | * The last flag is not defined for a file, |
742 | * however Windows sets it, so do the same |
743 | */ |
744 | pnewace->mask |= OWNER_RIGHTS |
745 | | FILE_READ |
746 | | FILE_WRITE |
747 | | FILE_EXEC |
748 | | cpu_to_le32(0x40); |
749 | } |
750 | /* reencode GENERIC_READ (+ EXECUTE) */ |
751 | if (pnewace->mask & GENERIC_READ) { |
752 | if (fordir) |
753 | pnewace->mask |= OWNER_RIGHTS |
754 | | DIR_READ |
755 | | DIR_EXEC; |
756 | else |
757 | pnewace->mask |= OWNER_RIGHTS |
758 | | FILE_READ |
759 | | FILE_EXEC; |
760 | pnewace->mask &= ~(GENERIC_READ |
761 | | GENERIC_EXECUTE |
762 | | WRITE_DAC |
763 | | WRITE_OWNER |
764 | | DELETE | FILE_WRITE_EA |
765 | | FILE_WRITE_ATTRIBUTES); |
766 | } |
767 | /* reencode GENERIC_WRITE */ |
768 | if (pnewace->mask & GENERIC_WRITE) { |
769 | if (fordir) |
770 | pnewace->mask |= OWNER_RIGHTS |
771 | | DIR_WRITE; |
772 | else |
773 | pnewace->mask |= OWNER_RIGHTS |
774 | | FILE_WRITE; |
775 | pnewace->mask &= ~(GENERIC_WRITE |
776 | | WRITE_DAC |
777 | | WRITE_OWNER |
778 | | FILE_DELETE_CHILD); |
779 | } |
780 | /* remove inheritance flags */ |
781 | pnewace->flags &= ~(OBJECT_INHERIT_ACE |
782 | | CONTAINER_INHERIT_ACE |
783 | | INHERIT_ONLY_ACE); |
784 | /* |
785 | * Group similar ACE for authenticated users |
786 | * (should probably be done for other SIDs) |
787 | */ |
788 | if (!fordir |
789 | && (poldace->type == ACCESS_ALLOWED_ACE_TYPE) |
790 | && ntfs_same_sid(&poldace->sid, authsid)) { |
791 | if (pauthace) { |
792 | pauthace->flags |= pnewace->flags; |
793 | pauthace->mask |= pnewace->mask; |
794 | } else { |
795 | pauthace = pnewace; |
796 | if (inherited) |
797 | pnewace->flags |= INHERITED_ACE; |
798 | dst += acesz; |
799 | newcnt++; |
800 | } |
801 | } else { |
802 | if (inherited) |
803 | pnewace->flags |= INHERITED_ACE; |
804 | dst += acesz; |
805 | newcnt++; |
806 | } |
807 | } |
808 | /* |
809 | * Inheritance for access, specific to |
810 | * creator-owner (and creator-group) |
811 | */ |
812 | if (fordir || !inherited |
813 | || (poldace->flags |
814 | & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) { |
815 | pnewace = (ACCESS_ALLOWED_ACE*) |
816 | ((char*)newacl + dst); |
817 | memcpy(pnewace,poldace,acesz); |
818 | /* |
819 | * Replace generic creator-owner and |
820 | * creator-group by owner and group |
821 | * (but keep for further inheritance) |
822 | */ |
823 | if (ntfs_same_sid(&pnewace->sid, ownersid)) { |
824 | memcpy(&pnewace->sid, usid, usidsz); |
825 | pnewace->size = cpu_to_le16(usidsz + 8); |
826 | /* remove inheritance flags */ |
827 | pnewace->flags &= ~(OBJECT_INHERIT_ACE |
828 | | CONTAINER_INHERIT_ACE |
829 | | INHERIT_ONLY_ACE); |
830 | if (inherited) |
831 | pnewace->flags |= INHERITED_ACE; |
832 | dst += usidsz + 8; |
833 | newcnt++; |
834 | } |
835 | if (ntfs_same_sid(&pnewace->sid, groupsid)) { |
836 | memcpy(&pnewace->sid, gsid, gsidsz); |
837 | pnewace->size = cpu_to_le16(gsidsz + 8); |
838 | /* remove inheritance flags */ |
839 | pnewace->flags &= ~(OBJECT_INHERIT_ACE |
840 | | CONTAINER_INHERIT_ACE |
841 | | INHERIT_ONLY_ACE); |
842 | if (inherited) |
843 | pnewace->flags |= INHERITED_ACE; |
844 | dst += gsidsz + 8; |
845 | newcnt++; |
846 | } |
847 | } |
848 | |
849 | /* inheritance for further inheritance */ |
850 | if (fordir |
851 | && (poldace->flags |
852 | & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) { |
853 | pnewace = (ACCESS_ALLOWED_ACE*) |
854 | ((char*)newacl + dst); |
855 | memcpy(pnewace,poldace,acesz); |
856 | if (inherited) |
857 | pnewace->flags |= INHERITED_ACE; |
858 | dst += acesz; |
859 | newcnt++; |
860 | } |
861 | } |
862 | /* |
863 | * Adjust header if something was inherited |
864 | */ |
865 | if (dst > sizeof(ACL)) { |
866 | newacl->ace_count = cpu_to_le16(newcnt); |
867 | newacl->size = cpu_to_le16(dst); |
868 | } else |
869 | dst = 0; |
870 | return (dst); |
871 | } |
872 | |
873 | #if POSIXACLS |
874 | |
875 | /* |
876 | * Do sanity checks on a Posix descriptor |
877 | * Should not be called with a NULL argument |
878 | * returns TRUE if considered safe |
879 | * if not, error should be logged by caller |
880 | */ |
881 | |
882 | BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc) |
883 | { |
884 | const struct POSIX_ACL *pacl; |
885 | int i; |
886 | BOOL ok; |
887 | u16 tag; |
888 | u32 id; |
889 | int perms; |
890 | struct { |
891 | u16 previous; |
892 | u32 previousid; |
893 | u16 tagsset; |
894 | mode_t mode; |
895 | int owners; |
896 | int groups; |
897 | int others; |
898 | } checks[2], *pchk; |
899 | |
900 | for (i=0; i<2; i++) { |
901 | checks[i].mode = 0; |
902 | checks[i].tagsset = 0; |
903 | checks[i].owners = 0; |
904 | checks[i].groups = 0; |
905 | checks[i].others = 0; |
906 | checks[i].previous = 0; |
907 | checks[i].previousid = 0; |
908 | } |
909 | ok = TRUE; |
910 | pacl = &pxdesc->acl; |
911 | /* |
912 | * header (strict for now) |
913 | */ |
914 | if ((pacl->version != POSIX_VERSION) |
915 | || (pacl->flags != 0) |
916 | || (pacl->filler != 0)) |
917 | ok = FALSE; |
918 | /* |
919 | * Reject multiple owner, group or other |
920 | * but do not require them to be present |
921 | * Also check the ACEs are in correct order |
922 | * which implies there is no duplicates |
923 | */ |
924 | for (i=0; i<pxdesc->acccnt + pxdesc->defcnt; i++) { |
925 | if (i >= pxdesc->firstdef) |
926 | pchk = &checks[1]; |
927 | else |
928 | pchk = &checks[0]; |
929 | perms = pacl->ace[i].perms; |
930 | tag = pacl->ace[i].tag; |
931 | pchk->tagsset |= tag; |
932 | id = pacl->ace[i].id; |
933 | if (perms & ~7) ok = FALSE; |
934 | if ((tag < pchk->previous) |
935 | || ((tag == pchk->previous) |
936 | && (id <= pchk->previousid))) |
937 | ok = FALSE; |
938 | pchk->previous = tag; |
939 | pchk->previousid = id; |
940 | switch (tag) { |
941 | case POSIX_ACL_USER_OBJ : |
942 | if (pchk->owners++) |
943 | ok = FALSE; |
944 | if (id != (u32)-1) |
945 | ok = FALSE; |
946 | pchk->mode |= perms << 6; |
947 | break; |
948 | case POSIX_ACL_GROUP_OBJ : |
949 | if (pchk->groups++) |
950 | ok = FALSE; |
951 | if (id != (u32)-1) |
952 | ok = FALSE; |
953 | pchk->mode = (pchk->mode & 07707) | (perms << 3); |
954 | break; |
955 | case POSIX_ACL_OTHER : |
956 | if (pchk->others++) |
957 | ok = FALSE; |
958 | if (id != (u32)-1) |
959 | ok = FALSE; |
960 | pchk->mode |= perms; |
961 | break; |
962 | case POSIX_ACL_USER : |
963 | case POSIX_ACL_GROUP : |
964 | if (id == (u32)-1) |
965 | ok = FALSE; |
966 | break; |
967 | case POSIX_ACL_MASK : |
968 | if (id != (u32)-1) |
969 | ok = FALSE; |
970 | pchk->mode = (pchk->mode & 07707) | (perms << 3); |
971 | break; |
972 | default : |
973 | ok = FALSE; |
974 | break; |
975 | } |
976 | } |
977 | if ((pxdesc->acccnt > 0) |
978 | && ((checks[0].owners != 1) || (checks[0].groups != 1) |
979 | || (checks[0].others != 1))) |
980 | ok = FALSE; |
981 | /* do not check owner, group or other are present in */ |
982 | /* the default ACL, Windows does not necessarily set them */ |
983 | /* descriptor */ |
984 | if (pxdesc->defcnt && (pxdesc->acccnt > pxdesc->firstdef)) |
985 | ok = FALSE; |
986 | if ((pxdesc->acccnt < 0) || (pxdesc->defcnt < 0)) |
987 | ok = FALSE; |
988 | /* check mode, unless null or no tag set */ |
989 | if (pxdesc->mode |
990 | && checks[0].tagsset |
991 | && (checks[0].mode != (pxdesc->mode & 0777))) |
992 | ok = FALSE; |
993 | /* check tagsset */ |
994 | if (pxdesc->tagsset != checks[0].tagsset) |
995 | ok = FALSE; |
996 | return (ok); |
997 | } |
998 | |
999 | /* |
1000 | * Set standard header data into a Posix ACL |
1001 | * The mode argument should provide the 3 upper bits of target mode |
1002 | */ |
1003 | |
1004 | static mode_t posix_header(struct POSIX_SECURITY *pxdesc, mode_t basemode) |
1005 | { |
1006 | mode_t mode; |
1007 | u16 tagsset; |
1008 | struct POSIX_ACE *pace; |
1009 | int i; |
1010 | |
1011 | mode = basemode & 07000; |
1012 | tagsset = 0; |
1013 | for (i=0; i<pxdesc->acccnt; i++) { |
1014 | pace = &pxdesc->acl.ace[i]; |
1015 | tagsset |= pace->tag; |
1016 | switch(pace->tag) { |
1017 | case POSIX_ACL_USER_OBJ : |
1018 | mode |= (pace->perms & 7) << 6; |
1019 | break; |
1020 | case POSIX_ACL_GROUP_OBJ : |
1021 | case POSIX_ACL_MASK : |
1022 | mode = (mode & 07707) | ((pace->perms & 7) << 3); |
1023 | break; |
1024 | case POSIX_ACL_OTHER : |
1025 | mode |= pace->perms & 7; |
1026 | break; |
1027 | default : |
1028 | break; |
1029 | } |
1030 | } |
1031 | pxdesc->tagsset = tagsset; |
1032 | pxdesc->mode = mode; |
1033 | pxdesc->acl.version = POSIX_VERSION; |
1034 | pxdesc->acl.flags = 0; |
1035 | pxdesc->acl.filler = 0; |
1036 | return (mode); |
1037 | } |
1038 | |
1039 | /* |
1040 | * Sort ACEs in a Posix ACL |
1041 | * This is useful for always getting reusable converted ACLs, |
1042 | * it also helps in merging ACEs. |
1043 | * Repeated tag+id are allowed and not merged here. |
1044 | * |
1045 | * Tags should be in ascending sequence and for a repeatable tag |
1046 | * ids should be in ascending sequence. |
1047 | */ |
1048 | |
1049 | void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc) |
1050 | { |
1051 | struct POSIX_ACL *pacl; |
1052 | struct POSIX_ACE ace; |
1053 | int i; |
1054 | int offs; |
1055 | BOOL done; |
1056 | u16 tag; |
1057 | u16 previous; |
1058 | u32 id; |
1059 | u32 previousid; |
1060 | |
1061 | |
1062 | /* |
1063 | * Check sequencing of tag+id in access ACE's |
1064 | */ |
1065 | pacl = &pxdesc->acl; |
1066 | do { |
1067 | done = TRUE; |
1068 | previous = pacl->ace[0].tag; |
1069 | previousid = pacl->ace[0].id; |
1070 | for (i=1; i<pxdesc->acccnt; i++) { |
1071 | tag = pacl->ace[i].tag; |
1072 | id = pacl->ace[i].id; |
1073 | |
1074 | if ((tag < previous) |
1075 | || ((tag == previous) && (id < previousid))) { |
1076 | done = FALSE; |
1077 | memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE)); |
1078 | memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE)); |
1079 | memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE)); |
1080 | } else { |
1081 | previous = tag; |
1082 | previousid = id; |
1083 | } |
1084 | } |
1085 | } while (!done); |
1086 | /* |
1087 | * Same for default ACEs |
1088 | */ |
1089 | do { |
1090 | done = TRUE; |
1091 | if ((pxdesc->defcnt) > 1) { |
1092 | offs = pxdesc->firstdef; |
1093 | previous = pacl->ace[offs].tag; |
1094 | previousid = pacl->ace[offs].id; |
1095 | for (i=offs+1; i<offs+pxdesc->defcnt; i++) { |
1096 | tag = pacl->ace[i].tag; |
1097 | id = pacl->ace[i].id; |
1098 | |
1099 | if ((tag < previous) |
1100 | || ((tag == previous) && (id < previousid))) { |
1101 | done = FALSE; |
1102 | memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE)); |
1103 | memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE)); |
1104 | memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE)); |
1105 | } else { |
1106 | previous = tag; |
1107 | previousid = id; |
1108 | } |
1109 | } |
1110 | } |
1111 | } while (!done); |
1112 | } |
1113 | |
1114 | /* |
1115 | * Merge a new mode into a Posix descriptor |
1116 | * The Posix descriptor is not reallocated, its size is unchanged |
1117 | * |
1118 | * returns 0 if ok |
1119 | */ |
1120 | |
1121 | int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode) |
1122 | { |
1123 | int i; |
1124 | BOOL maskfound; |
1125 | struct POSIX_ACE *pace; |
1126 | int todo; |
1127 | |
1128 | maskfound = FALSE; |
1129 | todo = POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER; |
1130 | for (i=pxdesc->acccnt-1; i>=0; i--) { |
1131 | pace = &pxdesc->acl.ace[i]; |
1132 | switch(pace->tag) { |
1133 | case POSIX_ACL_USER_OBJ : |
1134 | pace->perms = (mode >> 6) & 7; |
1135 | todo &= ~POSIX_ACL_USER_OBJ; |
1136 | break; |
1137 | case POSIX_ACL_GROUP_OBJ : |
1138 | if (!maskfound) |
1139 | pace->perms = (mode >> 3) & 7; |
1140 | todo &= ~POSIX_ACL_GROUP_OBJ; |
1141 | break; |
1142 | case POSIX_ACL_MASK : |
1143 | pace->perms = (mode >> 3) & 7; |
1144 | maskfound = TRUE; |
1145 | break; |
1146 | case POSIX_ACL_OTHER : |
1147 | pace->perms = mode & 7; |
1148 | todo &= ~POSIX_ACL_OTHER; |
1149 | break; |
1150 | default : |
1151 | break; |
1152 | } |
1153 | } |
1154 | pxdesc->mode = mode; |
1155 | return (todo ? -1 : 0); |
1156 | } |
1157 | |
1158 | /* |
1159 | * Replace an access or default Posix ACL |
1160 | * The resulting ACL is checked for validity |
1161 | * |
1162 | * Returns a new ACL or NULL if there is a problem |
1163 | */ |
1164 | |
1165 | struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc, |
1166 | const struct POSIX_ACL *newacl, int count, BOOL deflt) |
1167 | { |
1168 | struct POSIX_SECURITY *newpxdesc; |
1169 | size_t newsize; |
1170 | int offset; |
1171 | int oldoffset; |
1172 | int i; |
1173 | |
1174 | if (deflt) |
1175 | newsize = sizeof(struct POSIX_SECURITY) |
1176 | + (oldpxdesc->acccnt + count)*sizeof(struct POSIX_ACE); |
1177 | else |
1178 | newsize = sizeof(struct POSIX_SECURITY) |
1179 | + (oldpxdesc->defcnt + count)*sizeof(struct POSIX_ACE); |
1180 | newpxdesc = (struct POSIX_SECURITY*)malloc(newsize); |
1181 | if (newpxdesc) { |
1182 | if (deflt) { |
1183 | offset = oldpxdesc->acccnt; |
1184 | newpxdesc->acccnt = oldpxdesc->acccnt; |
1185 | newpxdesc->defcnt = count; |
1186 | newpxdesc->firstdef = offset; |
1187 | /* copy access ACEs */ |
1188 | for (i=0; i<newpxdesc->acccnt; i++) |
1189 | newpxdesc->acl.ace[i] = oldpxdesc->acl.ace[i]; |
1190 | /* copy default ACEs */ |
1191 | for (i=0; i<count; i++) |
1192 | newpxdesc->acl.ace[i + offset] = newacl->ace[i]; |
1193 | } else { |
1194 | offset = count; |
1195 | newpxdesc->acccnt = count; |
1196 | newpxdesc->defcnt = oldpxdesc->defcnt; |
1197 | newpxdesc->firstdef = count; |
1198 | /* copy access ACEs */ |
1199 | for (i=0; i<count; i++) |
1200 | newpxdesc->acl.ace[i] = newacl->ace[i]; |
1201 | /* copy default ACEs */ |
1202 | oldoffset = oldpxdesc->firstdef; |
1203 | for (i=0; i<newpxdesc->defcnt; i++) |
1204 | newpxdesc->acl.ace[i + offset] = oldpxdesc->acl.ace[i + oldoffset]; |
1205 | } |
1206 | /* assume special flags unchanged */ |
1207 | posix_header(newpxdesc, oldpxdesc->mode); |
1208 | if (!ntfs_valid_posix(newpxdesc)) { |
1209 | /* do not log, this is an application error */ |
1210 | free(newpxdesc); |
1211 | newpxdesc = (struct POSIX_SECURITY*)NULL; |
1212 | errno = EINVAL; |
1213 | } |
1214 | } else |
1215 | errno = ENOMEM; |
1216 | return (newpxdesc); |
1217 | } |
1218 | |
1219 | /* |
1220 | * Build an inherited Posix descriptor from parent |
1221 | * descriptor (if any) restricted to creation mode |
1222 | * |
1223 | * Returns the inherited descriptor or NULL if there is a problem |
1224 | */ |
1225 | |
1226 | struct POSIX_SECURITY *ntfs_build_inherited_posix( |
1227 | const struct POSIX_SECURITY *pxdesc, mode_t mode, |
1228 | mode_t mask, BOOL isdir) |
1229 | { |
1230 | struct POSIX_SECURITY *pydesc; |
1231 | struct POSIX_ACE *pyace; |
1232 | int count; |
1233 | int defcnt; |
1234 | int size; |
1235 | int i; |
1236 | s16 tagsset; |
1237 | |
1238 | if (pxdesc && pxdesc->defcnt) { |
1239 | if (isdir) |
1240 | count = 2*pxdesc->defcnt + 3; |
1241 | else |
1242 | count = pxdesc->defcnt + 3; |
1243 | } else |
1244 | count = 3; |
1245 | pydesc = (struct POSIX_SECURITY*)malloc( |
1246 | sizeof(struct POSIX_SECURITY) + count*sizeof(struct POSIX_ACE)); |
1247 | if (pydesc) { |
1248 | /* |
1249 | * Copy inherited tags and adapt perms |
1250 | * Use requested mode, ignoring umask |
1251 | * (not possible with older versions of fuse) |
1252 | */ |
1253 | tagsset = 0; |
1254 | defcnt = (pxdesc ? pxdesc->defcnt : 0); |
1255 | for (i=defcnt-1; i>=0; i--) { |
1256 | pyace = &pydesc->acl.ace[i]; |
1257 | *pyace = pxdesc->acl.ace[pxdesc->firstdef + i]; |
1258 | switch (pyace->tag) { |
1259 | case POSIX_ACL_USER_OBJ : |
1260 | pyace->perms &= (mode >> 6) & 7; |
1261 | break; |
1262 | case POSIX_ACL_GROUP_OBJ : |
1263 | if (!(tagsset & POSIX_ACL_MASK)) |
1264 | pyace->perms &= (mode >> 3) & 7; |
1265 | break; |
1266 | case POSIX_ACL_OTHER : |
1267 | pyace->perms &= mode & 7; |
1268 | break; |
1269 | case POSIX_ACL_MASK : |
1270 | pyace->perms &= (mode >> 3) & 7; |
1271 | break; |
1272 | default : |
1273 | break; |
1274 | } |
1275 | tagsset |= pyace->tag; |
1276 | } |
1277 | pydesc->acccnt = defcnt; |
1278 | /* |
1279 | * If some standard tags were missing, append them from mode |
1280 | * and sort the list |
1281 | * Here we have to use the umask'ed mode |
1282 | */ |
1283 | if (~tagsset & (POSIX_ACL_USER_OBJ |
1284 | | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) { |
1285 | i = defcnt; |
1286 | /* owner was missing */ |
1287 | if (!(tagsset & POSIX_ACL_USER_OBJ)) { |
1288 | pyace = &pydesc->acl.ace[i]; |
1289 | pyace->tag = POSIX_ACL_USER_OBJ; |
1290 | pyace->id = -1; |
1291 | pyace->perms = ((mode & ~mask) >> 6) & 7; |
1292 | tagsset |= POSIX_ACL_USER_OBJ; |
1293 | i++; |
1294 | } |
1295 | /* owning group was missing */ |
1296 | if (!(tagsset & POSIX_ACL_GROUP_OBJ)) { |
1297 | pyace = &pydesc->acl.ace[i]; |
1298 | pyace->tag = POSIX_ACL_GROUP_OBJ; |
1299 | pyace->id = -1; |
1300 | pyace->perms = ((mode & ~mask) >> 3) & 7; |
1301 | tagsset |= POSIX_ACL_GROUP_OBJ; |
1302 | i++; |
1303 | } |
1304 | /* other was missing */ |
1305 | if (!(tagsset & POSIX_ACL_OTHER)) { |
1306 | pyace = &pydesc->acl.ace[i]; |
1307 | pyace->tag = POSIX_ACL_OTHER; |
1308 | pyace->id = -1; |
1309 | pyace->perms = mode & ~mask & 7; |
1310 | tagsset |= POSIX_ACL_OTHER; |
1311 | i++; |
1312 | } |
1313 | pydesc->acccnt = i; |
1314 | pydesc->firstdef = i; |
1315 | pydesc->defcnt = 0; |
1316 | ntfs_sort_posix(pydesc); |
1317 | } |
1318 | |
1319 | /* |
1320 | * append as a default ACL if a directory |
1321 | */ |
1322 | pydesc->firstdef = pydesc->acccnt; |
1323 | if (defcnt && isdir) { |
1324 | size = sizeof(struct POSIX_ACE)*defcnt; |
1325 | memcpy(&pydesc->acl.ace[pydesc->firstdef], |
1326 | &pxdesc->acl.ace[pxdesc->firstdef],size); |
1327 | pydesc->defcnt = defcnt; |
1328 | } else { |
1329 | pydesc->defcnt = 0; |
1330 | } |
1331 | /* assume special bits are not inherited */ |
1332 | posix_header(pydesc, mode & 07000); |
1333 | if (!ntfs_valid_posix(pydesc)) { |
1334 | ntfs_log_error("Error building an inherited Posix desc\n"); |
1335 | errno = EIO; |
1336 | free(pydesc); |
1337 | pydesc = (struct POSIX_SECURITY*)NULL; |
1338 | } |
1339 | } else |
1340 | errno = ENOMEM; |
1341 | return (pydesc); |
1342 | } |
1343 | |
1344 | static int merge_lists_posix(struct POSIX_ACE *targetace, |
1345 | const struct POSIX_ACE *firstace, |
1346 | const struct POSIX_ACE *secondace, |
1347 | int firstcnt, int secondcnt) |
1348 | { |
1349 | int k; |
1350 | |
1351 | k = 0; |
1352 | /* |
1353 | * No list is exhausted : |
1354 | * if same tag+id in both list : |
1355 | * ignore ACE from second list |
1356 | * else take the one with smaller tag+id |
1357 | */ |
1358 | while ((firstcnt > 0) && (secondcnt > 0)) |
1359 | if ((firstace->tag == secondace->tag) |
1360 | && (firstace->id == secondace->id)) { |
1361 | secondace++; |
1362 | secondcnt--; |
1363 | } else |
1364 | if ((firstace->tag < secondace->tag) |
1365 | || ((firstace->tag == secondace->tag) |
1366 | && (firstace->id < secondace->id))) { |
1367 | targetace->tag = firstace->tag; |
1368 | targetace->id = firstace->id; |
1369 | targetace->perms = firstace->perms; |
1370 | firstace++; |
1371 | targetace++; |
1372 | firstcnt--; |
1373 | k++; |
1374 | } else { |
1375 | targetace->tag = secondace->tag; |
1376 | targetace->id = secondace->id; |
1377 | targetace->perms = secondace->perms; |
1378 | secondace++; |
1379 | targetace++; |
1380 | secondcnt--; |
1381 | k++; |
1382 | } |
1383 | /* |
1384 | * One list is exhausted, copy the other one |
1385 | */ |
1386 | while (firstcnt > 0) { |
1387 | targetace->tag = firstace->tag; |
1388 | targetace->id = firstace->id; |
1389 | targetace->perms = firstace->perms; |
1390 | firstace++; |
1391 | targetace++; |
1392 | firstcnt--; |
1393 | k++; |
1394 | } |
1395 | while (secondcnt > 0) { |
1396 | targetace->tag = secondace->tag; |
1397 | targetace->id = secondace->id; |
1398 | targetace->perms = secondace->perms; |
1399 | secondace++; |
1400 | targetace++; |
1401 | secondcnt--; |
1402 | k++; |
1403 | } |
1404 | return (k); |
1405 | } |
1406 | |
1407 | /* |
1408 | * Merge two Posix ACLs |
1409 | * The input ACLs have to be adequately sorted |
1410 | * |
1411 | * Returns the merged ACL, which is allocated and has to be freed by caller, |
1412 | * or NULL if failed |
1413 | */ |
1414 | |
1415 | struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first, |
1416 | const struct POSIX_SECURITY *second) |
1417 | { |
1418 | struct POSIX_SECURITY *pxdesc; |
1419 | struct POSIX_ACE *targetace; |
1420 | const struct POSIX_ACE *firstace; |
1421 | const struct POSIX_ACE *secondace; |
1422 | size_t size; |
1423 | int k; |
1424 | |
1425 | size = sizeof(struct POSIX_SECURITY) |
1426 | + (first->acccnt + first->defcnt |
1427 | + second->acccnt + second->defcnt)*sizeof(struct POSIX_ACE); |
1428 | pxdesc = (struct POSIX_SECURITY*)malloc(size); |
1429 | if (pxdesc) { |
1430 | /* |
1431 | * merge access ACEs |
1432 | */ |
1433 | firstace = first->acl.ace; |
1434 | secondace = second->acl.ace; |
1435 | targetace = pxdesc->acl.ace; |
1436 | k = merge_lists_posix(targetace,firstace,secondace, |
1437 | first->acccnt,second->acccnt); |
1438 | pxdesc->acccnt = k; |
1439 | /* |
1440 | * merge default ACEs |
1441 | */ |
1442 | pxdesc->firstdef = k; |
1443 | firstace = &first->acl.ace[first->firstdef]; |
1444 | secondace = &second->acl.ace[second->firstdef]; |
1445 | targetace = &pxdesc->acl.ace[k]; |
1446 | k = merge_lists_posix(targetace,firstace,secondace, |
1447 | first->defcnt,second->defcnt); |
1448 | pxdesc->defcnt = k; |
1449 | /* |
1450 | * build header |
1451 | */ |
1452 | pxdesc->acl.version = POSIX_VERSION; |
1453 | pxdesc->acl.flags = 0; |
1454 | pxdesc->acl.filler = 0; |
1455 | pxdesc->mode = 0; |
1456 | pxdesc->tagsset = 0; |
1457 | } else |
1458 | errno = ENOMEM; |
1459 | return (pxdesc); |
1460 | } |
1461 | |
1462 | struct BUILD_CONTEXT { |
1463 | BOOL isdir; |
1464 | BOOL adminowns; |
1465 | BOOL groupowns; |
1466 | u16 selfuserperms; |
1467 | u16 selfgrpperms; |
1468 | u16 grpperms; |
1469 | u16 othperms; |
1470 | u16 mask; |
1471 | u16 designates; |
1472 | u16 withmask; |
1473 | u16 rootspecial; |
1474 | } ; |
1475 | |
1476 | |
1477 | |
1478 | static BOOL build_user_denials(ACL *pacl, |
1479 | const SID *usid, struct MAPPING* const mapping[], |
1480 | ACE_FLAGS flags, const struct POSIX_ACE *pxace, |
1481 | struct BUILD_CONTEXT *pset) |
1482 | { |
1483 | BIGSID defsid; |
1484 | ACCESS_ALLOWED_ACE *pdace; |
1485 | const SID *sid; |
1486 | int sidsz; |
1487 | int pos; |
1488 | int acecnt; |
1489 | le32 grants; |
1490 | le32 denials; |
1491 | u16 perms; |
1492 | u16 mixperms; |
1493 | u16 tag; |
1494 | BOOL rejected; |
1495 | BOOL rootuser; |
1496 | BOOL avoidmask; |
1497 | |
1498 | rejected = FALSE; |
1499 | tag = pxace->tag; |
1500 | perms = pxace->perms; |
1501 | rootuser = FALSE; |
1502 | pos = le16_to_cpu(pacl->size); |
1503 | acecnt = le16_to_cpu(pacl->ace_count); |
1504 | avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) |
1505 | && ((pset->designates && pset->withmask) |
1506 | || (!pset->designates && !pset->withmask)); |
1507 | if (tag == POSIX_ACL_USER_OBJ) { |
1508 | sid = usid; |
1509 | sidsz = ntfs_sid_size(sid); |
1510 | grants = OWNER_RIGHTS; |
1511 | } else { |
1512 | if (pxace->id) { |
1513 | sid = NTFS_FIND_USID(mapping[MAPUSERS], |
1514 | pxace->id, (SID*)&defsid); |
1515 | grants = WORLD_RIGHTS; |
1516 | } else { |
1517 | sid = adminsid; |
1518 | rootuser = TRUE; |
1519 | grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK; |
1520 | } |
1521 | if (sid) { |
1522 | sidsz = ntfs_sid_size(sid); |
1523 | /* |
1524 | * Insert denial of complement of mask for |
1525 | * each designated user (except root) |
1526 | * WRITE_OWNER is inserted so that |
1527 | * the mask can be identified |
1528 | */ |
1529 | if (!avoidmask && !rootuser) { |
1530 | denials = WRITE_OWNER; |
1531 | pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1532 | if (pset->isdir) { |
1533 | if (!(pset->mask & POSIX_PERM_X)) |
1534 | denials |= DIR_EXEC; |
1535 | if (!(pset->mask & POSIX_PERM_W)) |
1536 | denials |= DIR_WRITE; |
1537 | if (!(pset->mask & POSIX_PERM_R)) |
1538 | denials |= DIR_READ; |
1539 | } else { |
1540 | if (!(pset->mask & POSIX_PERM_X)) |
1541 | denials |= FILE_EXEC; |
1542 | if (!(pset->mask & POSIX_PERM_W)) |
1543 | denials |= FILE_WRITE; |
1544 | if (!(pset->mask & POSIX_PERM_R)) |
1545 | denials |= FILE_READ; |
1546 | } |
1547 | if (rootuser) |
1548 | grants &= ~ROOT_OWNER_UNMARK; |
1549 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
1550 | pdace->flags = flags; |
1551 | pdace->size = cpu_to_le16(sidsz + 8); |
1552 | pdace->mask = denials; |
1553 | memcpy((char*)&pdace->sid, sid, sidsz); |
1554 | pos += sidsz + 8; |
1555 | acecnt++; |
1556 | } |
1557 | } else |
1558 | rejected = TRUE; |
1559 | } |
1560 | if (!rejected) { |
1561 | if (pset->isdir) { |
1562 | if (perms & POSIX_PERM_X) |
1563 | grants |= DIR_EXEC; |
1564 | if (perms & POSIX_PERM_W) |
1565 | grants |= DIR_WRITE; |
1566 | if (perms & POSIX_PERM_R) |
1567 | grants |= DIR_READ; |
1568 | } else { |
1569 | if (perms & POSIX_PERM_X) |
1570 | grants |= FILE_EXEC; |
1571 | if (perms & POSIX_PERM_W) |
1572 | grants |= FILE_WRITE; |
1573 | if (perms & POSIX_PERM_R) |
1574 | grants |= FILE_READ; |
1575 | } |
1576 | |
1577 | /* a possible ACE to deny owner what he/she would */ |
1578 | /* induely get from administrator, group or world */ |
1579 | /* unless owner is administrator or group */ |
1580 | |
1581 | denials = const_cpu_to_le32(0); |
1582 | pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1583 | if (!pset->adminowns && !rootuser) { |
1584 | if (!pset->groupowns) { |
1585 | mixperms = pset->grpperms | pset->othperms; |
1586 | if (tag == POSIX_ACL_USER_OBJ) |
1587 | mixperms |= pset->selfuserperms; |
1588 | if (pset->isdir) { |
1589 | if (mixperms & POSIX_PERM_X) |
1590 | denials |= DIR_EXEC; |
1591 | if (mixperms & POSIX_PERM_W) |
1592 | denials |= DIR_WRITE; |
1593 | if (mixperms & POSIX_PERM_R) |
1594 | denials |= DIR_READ; |
1595 | } else { |
1596 | if (mixperms & POSIX_PERM_X) |
1597 | denials |= FILE_EXEC; |
1598 | if (mixperms & POSIX_PERM_W) |
1599 | denials |= FILE_WRITE; |
1600 | if (mixperms & POSIX_PERM_R) |
1601 | denials |= FILE_READ; |
1602 | } |
1603 | } else { |
1604 | mixperms = ~pset->grpperms & pset->othperms; |
1605 | if (tag == POSIX_ACL_USER_OBJ) |
1606 | mixperms |= pset->selfuserperms; |
1607 | if (pset->isdir) { |
1608 | if (mixperms & POSIX_PERM_X) |
1609 | denials |= DIR_EXEC; |
1610 | if (mixperms & POSIX_PERM_W) |
1611 | denials |= DIR_WRITE; |
1612 | if (mixperms & POSIX_PERM_R) |
1613 | denials |= DIR_READ; |
1614 | } else { |
1615 | if (mixperms & POSIX_PERM_X) |
1616 | denials |= FILE_EXEC; |
1617 | if (mixperms & POSIX_PERM_W) |
1618 | denials |= FILE_WRITE; |
1619 | if (mixperms & POSIX_PERM_R) |
1620 | denials |= FILE_READ; |
1621 | } |
1622 | } |
1623 | denials &= ~grants; |
1624 | if (denials) { |
1625 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
1626 | pdace->flags = flags; |
1627 | pdace->size = cpu_to_le16(sidsz + 8); |
1628 | pdace->mask = denials; |
1629 | memcpy((char*)&pdace->sid, sid, sidsz); |
1630 | pos += sidsz + 8; |
1631 | acecnt++; |
1632 | } |
1633 | } |
1634 | } |
1635 | pacl->size = cpu_to_le16(pos); |
1636 | pacl->ace_count = cpu_to_le16(acecnt); |
1637 | return (!rejected); |
1638 | } |
1639 | |
1640 | static BOOL build_user_grants(ACL *pacl, |
1641 | const SID *usid, struct MAPPING* const mapping[], |
1642 | ACE_FLAGS flags, const struct POSIX_ACE *pxace, |
1643 | struct BUILD_CONTEXT *pset) |
1644 | { |
1645 | BIGSID defsid; |
1646 | ACCESS_ALLOWED_ACE *pgace; |
1647 | const SID *sid; |
1648 | int sidsz; |
1649 | int pos; |
1650 | int acecnt; |
1651 | le32 grants; |
1652 | u16 perms; |
1653 | u16 tag; |
1654 | BOOL rejected; |
1655 | BOOL rootuser; |
1656 | |
1657 | rejected = FALSE; |
1658 | tag = pxace->tag; |
1659 | perms = pxace->perms; |
1660 | rootuser = FALSE; |
1661 | pos = le16_to_cpu(pacl->size); |
1662 | acecnt = le16_to_cpu(pacl->ace_count); |
1663 | if (tag == POSIX_ACL_USER_OBJ) { |
1664 | sid = usid; |
1665 | sidsz = ntfs_sid_size(sid); |
1666 | grants = OWNER_RIGHTS; |
1667 | } else { |
1668 | if (pxace->id) { |
1669 | sid = NTFS_FIND_USID(mapping[MAPUSERS], |
1670 | pxace->id, (SID*)&defsid); |
1671 | if (sid) |
1672 | sidsz = ntfs_sid_size(sid); |
1673 | else |
1674 | rejected = TRUE; |
1675 | grants = WORLD_RIGHTS; |
1676 | } else { |
1677 | sid = adminsid; |
1678 | sidsz = ntfs_sid_size(sid); |
1679 | rootuser = TRUE; |
1680 | grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK; |
1681 | } |
1682 | } |
1683 | if (!rejected) { |
1684 | if (pset->isdir) { |
1685 | if (perms & POSIX_PERM_X) |
1686 | grants |= DIR_EXEC; |
1687 | if (perms & POSIX_PERM_W) |
1688 | grants |= DIR_WRITE; |
1689 | if (perms & POSIX_PERM_R) |
1690 | grants |= DIR_READ; |
1691 | } else { |
1692 | if (perms & POSIX_PERM_X) |
1693 | grants |= FILE_EXEC; |
1694 | if (perms & POSIX_PERM_W) |
1695 | grants |= FILE_WRITE; |
1696 | if (perms & POSIX_PERM_R) |
1697 | grants |= FILE_READ; |
1698 | } |
1699 | if (rootuser) |
1700 | grants &= ~ROOT_OWNER_UNMARK; |
1701 | pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1702 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
1703 | pgace->size = cpu_to_le16(sidsz + 8); |
1704 | pgace->flags = flags; |
1705 | pgace->mask = grants; |
1706 | memcpy((char*)&pgace->sid, sid, sidsz); |
1707 | pos += sidsz + 8; |
1708 | acecnt = le16_to_cpu(pacl->ace_count) + 1; |
1709 | pacl->ace_count = cpu_to_le16(acecnt); |
1710 | pacl->size = cpu_to_le16(pos); |
1711 | } |
1712 | return (!rejected); |
1713 | } |
1714 | |
1715 | |
1716 | /* a grant ACE for group */ |
1717 | /* unless group-obj has the same rights as world */ |
1718 | /* but present if group is owner or owner is administrator */ |
1719 | /* this ACE will be inserted after denials for group */ |
1720 | |
1721 | static BOOL build_group_denials_grant(ACL *pacl, |
1722 | const SID *gsid, struct MAPPING* const mapping[], |
1723 | ACE_FLAGS flags, const struct POSIX_ACE *pxace, |
1724 | struct BUILD_CONTEXT *pset) |
1725 | { |
1726 | BIGSID defsid; |
1727 | ACCESS_ALLOWED_ACE *pdace; |
1728 | ACCESS_ALLOWED_ACE *pgace; |
1729 | const SID *sid; |
1730 | int sidsz; |
1731 | int pos; |
1732 | int acecnt; |
1733 | le32 grants; |
1734 | le32 denials; |
1735 | u16 perms; |
1736 | u16 mixperms; |
1737 | u16 tag; |
1738 | BOOL avoidmask; |
1739 | BOOL rootgroup; |
1740 | BOOL rejected; |
1741 | |
1742 | rejected = FALSE; |
1743 | tag = pxace->tag; |
1744 | perms = pxace->perms; |
1745 | pos = le16_to_cpu(pacl->size); |
1746 | acecnt = le16_to_cpu(pacl->ace_count); |
1747 | rootgroup = FALSE; |
1748 | avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) |
1749 | && ((pset->designates && pset->withmask) |
1750 | || (!pset->designates && !pset->withmask)); |
1751 | if (tag == POSIX_ACL_GROUP_OBJ) |
1752 | sid = gsid; |
1753 | else |
1754 | if (pxace->id) |
1755 | sid = NTFS_FIND_GSID(mapping[MAPGROUPS], |
1756 | pxace->id, (SID*)&defsid); |
1757 | else { |
1758 | sid = adminsid; |
1759 | rootgroup = TRUE; |
1760 | } |
1761 | if (sid) { |
1762 | sidsz = ntfs_sid_size(sid); |
1763 | /* |
1764 | * Insert denial of complement of mask for |
1765 | * each group |
1766 | * WRITE_OWNER is inserted so that |
1767 | * the mask can be identified |
1768 | * Note : this mask may lead on Windows to |
1769 | * deny rights to administrators belonging |
1770 | * to some user group |
1771 | */ |
1772 | if ((!avoidmask && !rootgroup) |
1773 | || (pset->rootspecial |
1774 | && (tag == POSIX_ACL_GROUP_OBJ))) { |
1775 | denials = WRITE_OWNER; |
1776 | pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1777 | if (pset->isdir) { |
1778 | if (!(pset->mask & POSIX_PERM_X)) |
1779 | denials |= DIR_EXEC; |
1780 | if (!(pset->mask & POSIX_PERM_W)) |
1781 | denials |= DIR_WRITE; |
1782 | if (!(pset->mask & POSIX_PERM_R)) |
1783 | denials |= DIR_READ; |
1784 | } else { |
1785 | if (!(pset->mask & POSIX_PERM_X)) |
1786 | denials |= FILE_EXEC; |
1787 | if (!(pset->mask & POSIX_PERM_W)) |
1788 | denials |= FILE_WRITE; |
1789 | if (!(pset->mask & POSIX_PERM_R)) |
1790 | denials |= FILE_READ; |
1791 | } |
1792 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
1793 | pdace->flags = flags; |
1794 | pdace->size = cpu_to_le16(sidsz + 8); |
1795 | pdace->mask = denials; |
1796 | memcpy((char*)&pdace->sid, sid, sidsz); |
1797 | pos += sidsz + 8; |
1798 | acecnt++; |
1799 | } |
1800 | } else |
1801 | rejected = TRUE; |
1802 | if (!rejected |
1803 | && (pset->adminowns |
1804 | || pset->groupowns |
1805 | || avoidmask |
1806 | || rootgroup |
1807 | || (perms != pset->othperms))) { |
1808 | grants = WORLD_RIGHTS; |
1809 | if (rootgroup) |
1810 | grants &= ~ROOT_GROUP_UNMARK; |
1811 | if (pset->isdir) { |
1812 | if (perms & POSIX_PERM_X) |
1813 | grants |= DIR_EXEC; |
1814 | if (perms & POSIX_PERM_W) |
1815 | grants |= DIR_WRITE; |
1816 | if (perms & POSIX_PERM_R) |
1817 | grants |= DIR_READ; |
1818 | } else { |
1819 | if (perms & POSIX_PERM_X) |
1820 | grants |= FILE_EXEC; |
1821 | if (perms & POSIX_PERM_W) |
1822 | grants |= FILE_WRITE; |
1823 | if (perms & POSIX_PERM_R) |
1824 | grants |= FILE_READ; |
1825 | } |
1826 | |
1827 | /* a possible ACE to deny group what it would get from world */ |
1828 | /* or administrator, unless owner is administrator or group */ |
1829 | |
1830 | denials = const_cpu_to_le32(0); |
1831 | pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1832 | if (!pset->adminowns |
1833 | && !pset->groupowns |
1834 | && !rootgroup) { |
1835 | mixperms = pset->othperms; |
1836 | if (tag == POSIX_ACL_GROUP_OBJ) |
1837 | mixperms |= pset->selfgrpperms; |
1838 | if (pset->isdir) { |
1839 | if (mixperms & POSIX_PERM_X) |
1840 | denials |= DIR_EXEC; |
1841 | if (mixperms & POSIX_PERM_W) |
1842 | denials |= DIR_WRITE; |
1843 | if (mixperms & POSIX_PERM_R) |
1844 | denials |= DIR_READ; |
1845 | } else { |
1846 | if (mixperms & POSIX_PERM_X) |
1847 | denials |= FILE_EXEC; |
1848 | if (mixperms & POSIX_PERM_W) |
1849 | denials |= FILE_WRITE; |
1850 | if (mixperms & POSIX_PERM_R) |
1851 | denials |= FILE_READ; |
1852 | } |
1853 | denials &= ~(grants | OWNER_RIGHTS); |
1854 | if (denials) { |
1855 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
1856 | pdace->flags = flags; |
1857 | pdace->size = cpu_to_le16(sidsz + 8); |
1858 | pdace->mask = denials; |
1859 | memcpy((char*)&pdace->sid, sid, sidsz); |
1860 | pos += sidsz + 8; |
1861 | acecnt++; |
1862 | } |
1863 | } |
1864 | |
1865 | /* now insert grants to group if more than world */ |
1866 | if (pset->adminowns |
1867 | || pset->groupowns |
1868 | || (avoidmask && (pset->designates || pset->withmask)) |
1869 | || (perms & ~pset->othperms) |
1870 | || (pset->rootspecial |
1871 | && (tag == POSIX_ACL_GROUP_OBJ)) |
1872 | || (tag == POSIX_ACL_GROUP)) { |
1873 | if (rootgroup) |
1874 | grants &= ~ROOT_GROUP_UNMARK; |
1875 | pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; |
1876 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
1877 | pgace->flags = flags; |
1878 | pgace->size = cpu_to_le16(sidsz + 8); |
1879 | pgace->mask = grants; |
1880 | memcpy((char*)&pgace->sid, sid, sidsz); |
1881 | pos += sidsz + 8; |
1882 | acecnt++; |
1883 | } |
1884 | } |
1885 | pacl->size = cpu_to_le16(pos); |
1886 | pacl->ace_count = cpu_to_le16(acecnt); |
1887 | return (!rejected); |
1888 | } |
1889 | |
1890 | |
1891 | /* |
1892 | * Build an ACL composed of several ACE's |
1893 | * returns size of ACL or zero if failed |
1894 | * |
1895 | * Three schemes are defined : |
1896 | * |
1897 | * 1) if root is neither owner nor group up to 7 ACE's are set up : |
1898 | * - denials to owner (preventing grants to world or group to apply) |
1899 | * + mask denials to designated user (unless mask allows all) |
1900 | * + denials to designated user |
1901 | * - grants to owner (always present - first grant) |
1902 | * + grants to designated user |
1903 | * + mask denial to group (unless mask allows all) |
1904 | * - denials to group (preventing grants to world to apply) |
1905 | * - grants to group (unless group has no more than world rights) |
1906 | * + mask denials to designated group (unless mask allows all) |
1907 | * + grants to designated group |
1908 | * + denials to designated group |
1909 | * - grants to world (unless none) |
1910 | * - full privileges to administrator, always present |
1911 | * - full privileges to system, always present |
1912 | * |
1913 | * The same scheme is applied for Posix ACLs, with the mask represented |
1914 | * as denials prepended to grants for designated users and groups |
1915 | * |
1916 | * This is inspired by an Internet Draft from Marius Aamodt Eriksen |
1917 | * for mapping NFSv4 ACLs to Posix ACLs (draft-ietf-nfsv4-acl-mapping-00.txt) |
1918 | * More recent versions of the draft (draft-ietf-nfsv4-acl-mapping-05.txt) |
1919 | * are not followed, as they ignore the Posix mask and lead to |
1920 | * loss of compatibility with Linux implementations on other fs. |
1921 | * |
1922 | * Note that denials to group are located after grants to owner. |
1923 | * This only occurs in the unfrequent situation where world |
1924 | * has more rights than group and cannot be avoided if owner and other |
1925 | * have some common right which is denied to group (eg for mode 745 |
1926 | * executing has to be denied to group, but not to owner or world). |
1927 | * This rare situation is processed by Windows correctly, but |
1928 | * Windows utilities may want to change the order, with a |
1929 | * consequence of applying the group denials to the Windows owner. |
1930 | * The interpretation on Linux is not affected by the order change. |
1931 | * |
1932 | * 2) if root is either owner or group, two problems arise : |
1933 | * - granting full rights to administrator (as needed to transpose |
1934 | * to Windows rights bypassing granting to root) would imply |
1935 | * Linux permissions to always be seen as rwx, no matter the chmod |
1936 | * - there is no different SID to separate an administrator owner |
1937 | * from an administrator group. Hence Linux permissions for owner |
1938 | * would always be similar to permissions to group. |
1939 | * |
1940 | * as a work-around, up to 5 ACE's are set up if owner or group : |
1941 | * - grants to owner, always present at first position |
1942 | * - grants to group, always present |
1943 | * - grants to world, unless none |
1944 | * - full privileges to administrator, always present |
1945 | * - full privileges to system, always present |
1946 | * |
1947 | * On Windows, these ACE's are processed normally, though they |
1948 | * are redundant (owner, group and administrator are the same, |
1949 | * as a consequence any denials would damage administrator rights) |
1950 | * but on Linux, privileges to administrator are ignored (they |
1951 | * are not needed as root has always full privileges), and |
1952 | * neither grants to group are applied to owner, nor grants to |
1953 | * world are applied to owner or group. |
1954 | * |
1955 | * 3) finally a similar situation arises when group is owner (they |
1956 | * have the same SID), but is not root. |
1957 | * In this situation up to 6 ACE's are set up : |
1958 | * |
1959 | * - denials to owner (preventing grants to world to apply) |
1960 | * - grants to owner (always present) |
1961 | * - grants to group (unless groups has same rights as world) |
1962 | * - grants to world (unless none) |
1963 | * - full privileges to administrator, always present |
1964 | * - full privileges to system, always present |
1965 | * |
1966 | * On Windows, these ACE's are processed normally, though they |
1967 | * are redundant (as owner and group are the same), but this has |
1968 | * no impact on administrator rights |
1969 | * |
1970 | * Special flags (S_ISVTX, S_ISGID, S_ISUID) : |
1971 | * an extra null ACE is inserted to hold these flags, using |
1972 | * the same conventions as cygwin. |
1973 | * |
1974 | */ |
1975 | |
1976 | static int buildacls_posix(struct MAPPING* const mapping[], |
1977 | char *secattr, int offs, const struct POSIX_SECURITY *pxdesc, |
1978 | int isdir, const SID *usid, const SID *gsid) |
1979 | { |
1980 | struct BUILD_CONTEXT aceset[2], *pset; |
1981 | BOOL adminowns; |
1982 | BOOL groupowns; |
1983 | ACL *pacl; |
1984 | ACCESS_ALLOWED_ACE *pgace; |
1985 | ACCESS_ALLOWED_ACE *pdace; |
1986 | const struct POSIX_ACE *pxace; |
1987 | BOOL ok; |
1988 | mode_t mode; |
1989 | u16 tag; |
1990 | u16 perms; |
1991 | ACE_FLAGS flags; |
1992 | int pos; |
1993 | int i; |
1994 | int k; |
1995 | BIGSID defsid; |
1996 | const SID *sid; |
1997 | int acecnt; |
1998 | int usidsz; |
1999 | int wsidsz; |
2000 | int asidsz; |
2001 | int ssidsz; |
2002 | int nsidsz; |
2003 | le32 grants; |
2004 | |
2005 | usidsz = ntfs_sid_size(usid); |
2006 | wsidsz = ntfs_sid_size(worldsid); |
2007 | asidsz = ntfs_sid_size(adminsid); |
2008 | ssidsz = ntfs_sid_size(systemsid); |
2009 | mode = pxdesc->mode; |
2010 | /* adminowns and groupowns are used for both lists */ |
2011 | adminowns = ntfs_same_sid(usid, adminsid) |
2012 | || ntfs_same_sid(gsid, adminsid); |
2013 | groupowns = !adminowns && ntfs_same_sid(usid, gsid); |
2014 | |
2015 | ok = TRUE; |
2016 | |
2017 | /* ACL header */ |
2018 | pacl = (ACL*)&secattr[offs]; |
2019 | pacl->revision = ACL_REVISION; |
2020 | pacl->alignment1 = 0; |
2021 | pacl->size = cpu_to_le16(sizeof(ACL) + usidsz + 8); |
2022 | pacl->ace_count = const_cpu_to_le16(0); |
2023 | pacl->alignment2 = const_cpu_to_le16(0); |
2024 | |
2025 | /* |
2026 | * Determine what is allowed to some group or world |
2027 | * to prevent designated users or other groups to get |
2028 | * rights from groups or world |
2029 | * Do the same if owner and group appear as designated |
2030 | * user or group |
2031 | * Also get global mask |
2032 | */ |
2033 | for (k=0; k<2; k++) { |
2034 | pset = &aceset[k]; |
2035 | pset->selfuserperms = 0; |
2036 | pset->selfgrpperms = 0; |
2037 | pset->grpperms = 0; |
2038 | pset->othperms = 0; |
2039 | pset->mask = (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); |
2040 | pset->designates = 0; |
2041 | pset->withmask = 0; |
2042 | pset->rootspecial = 0; |
2043 | pset->adminowns = adminowns; |
2044 | pset->groupowns = groupowns; |
2045 | pset->isdir = isdir; |
2046 | } |
2047 | |
2048 | for (i=pxdesc->acccnt+pxdesc->defcnt-1; i>=0; i--) { |
2049 | if (i >= pxdesc->acccnt) { |
2050 | pset = &aceset[1]; |
2051 | pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; |
2052 | } else { |
2053 | pset = &aceset[0]; |
2054 | pxace = &pxdesc->acl.ace[i]; |
2055 | } |
2056 | switch (pxace->tag) { |
2057 | case POSIX_ACL_USER : |
2058 | pset->designates++; |
2059 | if (pxace->id) { |
2060 | sid = NTFS_FIND_USID(mapping[MAPUSERS], |
2061 | pxace->id, (SID*)&defsid); |
2062 | if (sid && ntfs_same_sid(sid,usid)) |
2063 | pset->selfuserperms |= pxace->perms; |
2064 | } else |
2065 | /* root as designated user is processed apart */ |
2066 | pset->rootspecial = TRUE; |
2067 | break; |
2068 | case POSIX_ACL_GROUP : |
2069 | pset->designates++; |
2070 | if (pxace->id) { |
2071 | sid = NTFS_FIND_GSID(mapping[MAPUSERS], |
2072 | pxace->id, (SID*)&defsid); |
2073 | if (sid && ntfs_same_sid(sid,gsid)) |
2074 | pset->selfgrpperms |= pxace->perms; |
2075 | } else |
2076 | /* root as designated group is processed apart */ |
2077 | pset->rootspecial = TRUE; |
2078 | /* fall through */ |
2079 | case POSIX_ACL_GROUP_OBJ : |
2080 | pset->grpperms |= pxace->perms; |
2081 | break; |
2082 | case POSIX_ACL_OTHER : |
2083 | pset->othperms = pxace->perms; |
2084 | break; |
2085 | case POSIX_ACL_MASK : |
2086 | pset->withmask++; |
2087 | pset->mask = pxace->perms; |
2088 | default : |
2089 | break; |
2090 | } |
2091 | } |
2092 | |
2093 | if (pxdesc->defcnt && (pxdesc->firstdef != pxdesc->acccnt)) { |
2094 | ntfs_log_error("** error : access and default not consecutive\n"); |
2095 | return (0); |
2096 | } |
2097 | /* |
2098 | * First insert all denials for owner and each |
2099 | * designated user (with mask if needed) |
2100 | */ |
2101 | |
2102 | pacl->ace_count = const_cpu_to_le16(0); |
2103 | pacl->size = const_cpu_to_le16(sizeof(ACL)); |
2104 | for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) { |
2105 | if (i >= pxdesc->acccnt) { |
2106 | flags = INHERIT_ONLY_ACE |
2107 | | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; |
2108 | pset = &aceset[1]; |
2109 | pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; |
2110 | } else { |
2111 | if (pxdesc->defcnt) |
2112 | flags = NO_PROPAGATE_INHERIT_ACE; |
2113 | else |
2114 | flags = (isdir ? DIR_INHERITANCE |
2115 | : FILE_INHERITANCE); |
2116 | pset = &aceset[0]; |
2117 | pxace = &pxdesc->acl.ace[i]; |
2118 | } |
2119 | tag = pxace->tag; |
2120 | perms = pxace->perms; |
2121 | switch (tag) { |
2122 | |
2123 | /* insert denial ACEs for each owner or allowed user */ |
2124 | |
2125 | case POSIX_ACL_USER : |
2126 | case POSIX_ACL_USER_OBJ : |
2127 | |
2128 | ok = build_user_denials(pacl, |
2129 | usid, mapping, flags, pxace, pset); |
2130 | break; |
2131 | default : |
2132 | break; |
2133 | } |
2134 | } |
2135 | |
2136 | /* |
2137 | * for directories, insert a world execution denial |
2138 | * inherited to plain files. |
2139 | * This is to prevent Windows from granting execution |
2140 | * of files through inheritance from parent directory |
2141 | */ |
2142 | |
2143 | if (isdir && ok) { |
2144 | pos = le16_to_cpu(pacl->size); |
2145 | pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; |
2146 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
2147 | pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; |
2148 | pdace->size = cpu_to_le16(wsidsz + 8); |
2149 | pdace->mask = FILE_EXEC; |
2150 | memcpy((char*)&pdace->sid, worldsid, wsidsz); |
2151 | pos += wsidsz + 8; |
2152 | acecnt = le16_to_cpu(pacl->ace_count) + 1; |
2153 | pacl->ace_count = cpu_to_le16(acecnt); |
2154 | pacl->size = cpu_to_le16(pos); |
2155 | } |
2156 | |
2157 | /* |
2158 | * now insert (if needed) |
2159 | * - grants to owner and designated users |
2160 | * - mask and denials for all groups |
2161 | * - grants to other |
2162 | */ |
2163 | |
2164 | for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) { |
2165 | if (i >= pxdesc->acccnt) { |
2166 | flags = INHERIT_ONLY_ACE |
2167 | | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; |
2168 | pset = &aceset[1]; |
2169 | pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; |
2170 | } else { |
2171 | if (pxdesc->defcnt) |
2172 | flags = NO_PROPAGATE_INHERIT_ACE; |
2173 | else |
2174 | flags = (isdir ? DIR_INHERITANCE |
2175 | : FILE_INHERITANCE); |
2176 | pset = &aceset[0]; |
2177 | pxace = &pxdesc->acl.ace[i]; |
2178 | } |
2179 | tag = pxace->tag; |
2180 | perms = pxace->perms; |
2181 | switch (tag) { |
2182 | |
2183 | /* ACE for each owner or allowed user */ |
2184 | |
2185 | case POSIX_ACL_USER : |
2186 | case POSIX_ACL_USER_OBJ : |
2187 | ok = build_user_grants(pacl,usid, |
2188 | mapping,flags,pxace,pset); |
2189 | break; |
2190 | |
2191 | case POSIX_ACL_GROUP : |
2192 | case POSIX_ACL_GROUP_OBJ : |
2193 | |
2194 | /* denials and grants for groups */ |
2195 | |
2196 | ok = build_group_denials_grant(pacl,gsid, |
2197 | mapping,flags,pxace,pset); |
2198 | break; |
2199 | |
2200 | case POSIX_ACL_OTHER : |
2201 | |
2202 | /* grants for other users */ |
2203 | |
2204 | pos = le16_to_cpu(pacl->size); |
2205 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2206 | grants = WORLD_RIGHTS; |
2207 | if (isdir) { |
2208 | if (perms & POSIX_PERM_X) |
2209 | grants |= DIR_EXEC; |
2210 | if (perms & POSIX_PERM_W) |
2211 | grants |= DIR_WRITE; |
2212 | if (perms & POSIX_PERM_R) |
2213 | grants |= DIR_READ; |
2214 | } else { |
2215 | if (perms & POSIX_PERM_X) |
2216 | grants |= FILE_EXEC; |
2217 | if (perms & POSIX_PERM_W) |
2218 | grants |= FILE_WRITE; |
2219 | if (perms & POSIX_PERM_R) |
2220 | grants |= FILE_READ; |
2221 | } |
2222 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2223 | pgace->flags = flags; |
2224 | pgace->size = cpu_to_le16(wsidsz + 8); |
2225 | pgace->mask = grants; |
2226 | memcpy((char*)&pgace->sid, worldsid, wsidsz); |
2227 | pos += wsidsz + 8; |
2228 | acecnt = le16_to_cpu(pacl->ace_count) + 1; |
2229 | pacl->ace_count = cpu_to_le16(acecnt); |
2230 | pacl->size = cpu_to_le16(pos); |
2231 | break; |
2232 | } |
2233 | } |
2234 | |
2235 | if (!ok) { |
2236 | errno = EINVAL; |
2237 | pos = 0; |
2238 | } else { |
2239 | /* an ACE for administrators */ |
2240 | /* always full access */ |
2241 | |
2242 | pos = le16_to_cpu(pacl->size); |
2243 | acecnt = le16_to_cpu(pacl->ace_count); |
2244 | if (isdir) |
2245 | flags = OBJECT_INHERIT_ACE |
2246 | | CONTAINER_INHERIT_ACE; |
2247 | else |
2248 | flags = NO_PROPAGATE_INHERIT_ACE; |
2249 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2250 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2251 | pgace->flags = flags; |
2252 | pgace->size = cpu_to_le16(asidsz + 8); |
2253 | grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; |
2254 | pgace->mask = grants; |
2255 | memcpy((char*)&pgace->sid, adminsid, asidsz); |
2256 | pos += asidsz + 8; |
2257 | acecnt++; |
2258 | |
2259 | /* an ACE for system (needed ?) */ |
2260 | /* always full access */ |
2261 | |
2262 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2263 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2264 | pgace->flags = flags; |
2265 | pgace->size = cpu_to_le16(ssidsz + 8); |
2266 | grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; |
2267 | pgace->mask = grants; |
2268 | memcpy((char*)&pgace->sid, systemsid, ssidsz); |
2269 | pos += ssidsz + 8; |
2270 | acecnt++; |
2271 | |
2272 | /* a null ACE to hold special flags */ |
2273 | /* using the same representation as cygwin */ |
2274 | |
2275 | if (mode & (S_ISVTX | S_ISGID | S_ISUID)) { |
2276 | nsidsz = ntfs_sid_size(nullsid); |
2277 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2278 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2279 | pgace->flags = NO_PROPAGATE_INHERIT_ACE; |
2280 | pgace->size = cpu_to_le16(nsidsz + 8); |
2281 | grants = const_cpu_to_le32(0); |
2282 | if (mode & S_ISUID) |
2283 | grants |= FILE_APPEND_DATA; |
2284 | if (mode & S_ISGID) |
2285 | grants |= FILE_WRITE_DATA; |
2286 | if (mode & S_ISVTX) |
2287 | grants |= FILE_READ_DATA; |
2288 | pgace->mask = grants; |
2289 | memcpy((char*)&pgace->sid, nullsid, nsidsz); |
2290 | pos += nsidsz + 8; |
2291 | acecnt++; |
2292 | } |
2293 | |
2294 | /* fix ACL header */ |
2295 | pacl->size = cpu_to_le16(pos); |
2296 | pacl->ace_count = cpu_to_le16(acecnt); |
2297 | } |
2298 | return (ok ? pos : 0); |
2299 | } |
2300 | |
2301 | #endif /* POSIXACLS */ |
2302 | |
2303 | static int buildacls(char *secattr, int offs, mode_t mode, int isdir, |
2304 | const SID * usid, const SID * gsid) |
2305 | { |
2306 | ACL *pacl; |
2307 | ACCESS_ALLOWED_ACE *pgace; |
2308 | ACCESS_ALLOWED_ACE *pdace; |
2309 | BOOL adminowns; |
2310 | BOOL groupowns; |
2311 | ACE_FLAGS gflags; |
2312 | int pos; |
2313 | int acecnt; |
2314 | int usidsz; |
2315 | int gsidsz; |
2316 | int wsidsz; |
2317 | int asidsz; |
2318 | int ssidsz; |
2319 | int nsidsz; |
2320 | le32 grants; |
2321 | le32 denials; |
2322 | |
2323 | usidsz = ntfs_sid_size(usid); |
2324 | gsidsz = ntfs_sid_size(gsid); |
2325 | wsidsz = ntfs_sid_size(worldsid); |
2326 | asidsz = ntfs_sid_size(adminsid); |
2327 | ssidsz = ntfs_sid_size(systemsid); |
2328 | adminowns = ntfs_same_sid(usid, adminsid) |
2329 | || ntfs_same_sid(gsid, adminsid); |
2330 | groupowns = !adminowns && ntfs_same_sid(usid, gsid); |
2331 | |
2332 | /* ACL header */ |
2333 | pacl = (ACL*)&secattr[offs]; |
2334 | pacl->revision = ACL_REVISION; |
2335 | pacl->alignment1 = 0; |
2336 | pacl->size = cpu_to_le16(sizeof(ACL) + usidsz + 8); |
2337 | pacl->ace_count = const_cpu_to_le16(1); |
2338 | pacl->alignment2 = const_cpu_to_le16(0); |
2339 | pos = sizeof(ACL); |
2340 | acecnt = 0; |
2341 | |
2342 | /* compute a grant ACE for owner */ |
2343 | /* this ACE will be inserted after denial for owner */ |
2344 | |
2345 | grants = OWNER_RIGHTS; |
2346 | if (isdir) { |
2347 | gflags = DIR_INHERITANCE; |
2348 | if (mode & S_IXUSR) |
2349 | grants |= DIR_EXEC; |
2350 | if (mode & S_IWUSR) |
2351 | grants |= DIR_WRITE; |
2352 | if (mode & S_IRUSR) |
2353 | grants |= DIR_READ; |
2354 | } else { |
2355 | gflags = FILE_INHERITANCE; |
2356 | if (mode & S_IXUSR) |
2357 | grants |= FILE_EXEC; |
2358 | if (mode & S_IWUSR) |
2359 | grants |= FILE_WRITE; |
2360 | if (mode & S_IRUSR) |
2361 | grants |= FILE_READ; |
2362 | } |
2363 | |
2364 | /* a possible ACE to deny owner what he/she would */ |
2365 | /* induely get from administrator, group or world */ |
2366 | /* unless owner is administrator or group */ |
2367 | |
2368 | denials = const_cpu_to_le32(0); |
2369 | pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; |
2370 | if (!adminowns) { |
2371 | if (!groupowns) { |
2372 | if (isdir) { |
2373 | pdace->flags = DIR_INHERITANCE; |
2374 | if (mode & (S_IXGRP | S_IXOTH)) |
2375 | denials |= DIR_EXEC; |
2376 | if (mode & (S_IWGRP | S_IWOTH)) |
2377 | denials |= DIR_WRITE; |
2378 | if (mode & (S_IRGRP | S_IROTH)) |
2379 | denials |= DIR_READ; |
2380 | } else { |
2381 | pdace->flags = FILE_INHERITANCE; |
2382 | if (mode & (S_IXGRP | S_IXOTH)) |
2383 | denials |= FILE_EXEC; |
2384 | if (mode & (S_IWGRP | S_IWOTH)) |
2385 | denials |= FILE_WRITE; |
2386 | if (mode & (S_IRGRP | S_IROTH)) |
2387 | denials |= FILE_READ; |
2388 | } |
2389 | } else { |
2390 | if (isdir) { |
2391 | pdace->flags = DIR_INHERITANCE; |
2392 | if ((mode & S_IXOTH) && !(mode & S_IXGRP)) |
2393 | denials |= DIR_EXEC; |
2394 | if ((mode & S_IWOTH) && !(mode & S_IWGRP)) |
2395 | denials |= DIR_WRITE; |
2396 | if ((mode & S_IROTH) && !(mode & S_IRGRP)) |
2397 | denials |= DIR_READ; |
2398 | } else { |
2399 | pdace->flags = FILE_INHERITANCE; |
2400 | if ((mode & S_IXOTH) && !(mode & S_IXGRP)) |
2401 | denials |= FILE_EXEC; |
2402 | if ((mode & S_IWOTH) && !(mode & S_IWGRP)) |
2403 | denials |= FILE_WRITE; |
2404 | if ((mode & S_IROTH) && !(mode & S_IRGRP)) |
2405 | denials |= FILE_READ; |
2406 | } |
2407 | } |
2408 | denials &= ~grants; |
2409 | if (denials) { |
2410 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
2411 | pdace->size = cpu_to_le16(usidsz + 8); |
2412 | pdace->mask = denials; |
2413 | memcpy((char*)&pdace->sid, usid, usidsz); |
2414 | pos += usidsz + 8; |
2415 | acecnt++; |
2416 | } |
2417 | } |
2418 | /* |
2419 | * for directories, a world execution denial |
2420 | * inherited to plain files |
2421 | */ |
2422 | |
2423 | if (isdir) { |
2424 | pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; |
2425 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
2426 | pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; |
2427 | pdace->size = cpu_to_le16(wsidsz + 8); |
2428 | pdace->mask = FILE_EXEC; |
2429 | memcpy((char*)&pdace->sid, worldsid, wsidsz); |
2430 | pos += wsidsz + 8; |
2431 | acecnt++; |
2432 | } |
2433 | |
2434 | |
2435 | /* now insert grants to owner */ |
2436 | pgace = (ACCESS_ALLOWED_ACE*) &secattr[offs + pos]; |
2437 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2438 | pgace->size = cpu_to_le16(usidsz + 8); |
2439 | pgace->flags = gflags; |
2440 | pgace->mask = grants; |
2441 | memcpy((char*)&pgace->sid, usid, usidsz); |
2442 | pos += usidsz + 8; |
2443 | acecnt++; |
2444 | |
2445 | /* a grant ACE for group */ |
2446 | /* unless group has the same rights as world */ |
2447 | /* but present if group is owner or owner is administrator */ |
2448 | /* this ACE will be inserted after denials for group */ |
2449 | |
2450 | if (adminowns |
2451 | || groupowns |
2452 | || (((mode >> 3) ^ mode) & 7)) { |
2453 | grants = WORLD_RIGHTS; |
2454 | if (isdir) { |
2455 | gflags = DIR_INHERITANCE; |
2456 | if (mode & S_IXGRP) |
2457 | grants |= DIR_EXEC; |
2458 | if (mode & S_IWGRP) |
2459 | grants |= DIR_WRITE; |
2460 | if (mode & S_IRGRP) |
2461 | grants |= DIR_READ; |
2462 | } else { |
2463 | gflags = FILE_INHERITANCE; |
2464 | if (mode & S_IXGRP) |
2465 | grants |= FILE_EXEC; |
2466 | if (mode & S_IWGRP) |
2467 | grants |= FILE_WRITE; |
2468 | if (mode & S_IRGRP) |
2469 | grants |= FILE_READ; |
2470 | } |
2471 | |
2472 | /* a possible ACE to deny group what it would get from world */ |
2473 | /* or administrator, unless owner is administrator or group */ |
2474 | |
2475 | denials = const_cpu_to_le32(0); |
2476 | pdace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2477 | if (!adminowns && !groupowns) { |
2478 | if (isdir) { |
2479 | pdace->flags = DIR_INHERITANCE; |
2480 | if (mode & S_IXOTH) |
2481 | denials |= DIR_EXEC; |
2482 | if (mode & S_IWOTH) |
2483 | denials |= DIR_WRITE; |
2484 | if (mode & S_IROTH) |
2485 | denials |= DIR_READ; |
2486 | } else { |
2487 | pdace->flags = FILE_INHERITANCE; |
2488 | if (mode & S_IXOTH) |
2489 | denials |= FILE_EXEC; |
2490 | if (mode & S_IWOTH) |
2491 | denials |= FILE_WRITE; |
2492 | if (mode & S_IROTH) |
2493 | denials |= FILE_READ; |
2494 | } |
2495 | denials &= ~(grants | OWNER_RIGHTS); |
2496 | if (denials) { |
2497 | pdace->type = ACCESS_DENIED_ACE_TYPE; |
2498 | pdace->size = cpu_to_le16(gsidsz + 8); |
2499 | pdace->mask = denials; |
2500 | memcpy((char*)&pdace->sid, gsid, gsidsz); |
2501 | pos += gsidsz + 8; |
2502 | acecnt++; |
2503 | } |
2504 | } |
2505 | |
2506 | if (adminowns |
2507 | || groupowns |
2508 | || ((mode >> 3) & ~mode & 7)) { |
2509 | /* now insert grants to group */ |
2510 | /* if more rights than other */ |
2511 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2512 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2513 | pgace->flags = gflags; |
2514 | pgace->size = cpu_to_le16(gsidsz + 8); |
2515 | pgace->mask = grants; |
2516 | memcpy((char*)&pgace->sid, gsid, gsidsz); |
2517 | pos += gsidsz + 8; |
2518 | acecnt++; |
2519 | } |
2520 | } |
2521 | |
2522 | /* an ACE for world users */ |
2523 | |
2524 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2525 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2526 | grants = WORLD_RIGHTS; |
2527 | if (isdir) { |
2528 | pgace->flags = DIR_INHERITANCE; |
2529 | if (mode & S_IXOTH) |
2530 | grants |= DIR_EXEC; |
2531 | if (mode & S_IWOTH) |
2532 | grants |= DIR_WRITE; |
2533 | if (mode & S_IROTH) |
2534 | grants |= DIR_READ; |
2535 | } else { |
2536 | pgace->flags = FILE_INHERITANCE; |
2537 | if (mode & S_IXOTH) |
2538 | grants |= FILE_EXEC; |
2539 | if (mode & S_IWOTH) |
2540 | grants |= FILE_WRITE; |
2541 | if (mode & S_IROTH) |
2542 | grants |= FILE_READ; |
2543 | } |
2544 | pgace->size = cpu_to_le16(wsidsz + 8); |
2545 | pgace->mask = grants; |
2546 | memcpy((char*)&pgace->sid, worldsid, wsidsz); |
2547 | pos += wsidsz + 8; |
2548 | acecnt++; |
2549 | |
2550 | /* an ACE for administrators */ |
2551 | /* always full access */ |
2552 | |
2553 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2554 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2555 | if (isdir) |
2556 | pgace->flags = DIR_INHERITANCE; |
2557 | else |
2558 | pgace->flags = FILE_INHERITANCE; |
2559 | pgace->size = cpu_to_le16(asidsz + 8); |
2560 | grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; |
2561 | pgace->mask = grants; |
2562 | memcpy((char*)&pgace->sid, adminsid, asidsz); |
2563 | pos += asidsz + 8; |
2564 | acecnt++; |
2565 | |
2566 | /* an ACE for system (needed ?) */ |
2567 | /* always full access */ |
2568 | |
2569 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2570 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2571 | if (isdir) |
2572 | pgace->flags = DIR_INHERITANCE; |
2573 | else |
2574 | pgace->flags = FILE_INHERITANCE; |
2575 | pgace->size = cpu_to_le16(ssidsz + 8); |
2576 | grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; |
2577 | pgace->mask = grants; |
2578 | memcpy((char*)&pgace->sid, systemsid, ssidsz); |
2579 | pos += ssidsz + 8; |
2580 | acecnt++; |
2581 | |
2582 | /* a null ACE to hold special flags */ |
2583 | /* using the same representation as cygwin */ |
2584 | |
2585 | if (mode & (S_ISVTX | S_ISGID | S_ISUID)) { |
2586 | nsidsz = ntfs_sid_size(nullsid); |
2587 | pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; |
2588 | pgace->type = ACCESS_ALLOWED_ACE_TYPE; |
2589 | pgace->flags = NO_PROPAGATE_INHERIT_ACE; |
2590 | pgace->size = cpu_to_le16(nsidsz + 8); |
2591 | grants = const_cpu_to_le32(0); |
2592 | if (mode & S_ISUID) |
2593 | grants |= FILE_APPEND_DATA; |
2594 | if (mode & S_ISGID) |
2595 | grants |= FILE_WRITE_DATA; |
2596 | if (mode & S_ISVTX) |
2597 | grants |= FILE_READ_DATA; |
2598 | pgace->mask = grants; |
2599 | memcpy((char*)&pgace->sid, nullsid, nsidsz); |
2600 | pos += nsidsz + 8; |
2601 | acecnt++; |
2602 | } |
2603 | |
2604 | /* fix ACL header */ |
2605 | pacl->size = cpu_to_le16(pos); |
2606 | pacl->ace_count = cpu_to_le16(acecnt); |
2607 | return (pos); |
2608 | } |
2609 | |
2610 | #if POSIXACLS |
2611 | |
2612 | /* |
2613 | * Build a full security descriptor from a Posix ACL |
2614 | * returns descriptor in allocated memory, must free() after use |
2615 | */ |
2616 | |
2617 | char *ntfs_build_descr_posix(struct MAPPING* const mapping[], |
2618 | struct POSIX_SECURITY *pxdesc, |
2619 | int isdir, const SID *usid, const SID *gsid) |
2620 | { |
2621 | int newattrsz; |
2622 | SECURITY_DESCRIPTOR_RELATIVE *pnhead; |
2623 | char *newattr; |
2624 | int aclsz; |
2625 | int usidsz; |
2626 | int gsidsz; |
2627 | int wsidsz; |
2628 | int asidsz; |
2629 | int ssidsz; |
2630 | int k; |
2631 | |
2632 | usidsz = ntfs_sid_size(usid); |
2633 | gsidsz = ntfs_sid_size(gsid); |
2634 | wsidsz = ntfs_sid_size(worldsid); |
2635 | asidsz = ntfs_sid_size(adminsid); |
2636 | ssidsz = ntfs_sid_size(systemsid); |
2637 | |
2638 | /* allocate enough space for the new security attribute */ |
2639 | newattrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ |
2640 | + usidsz + gsidsz /* usid and gsid */ |
2641 | + sizeof(ACL) /* acl header */ |
2642 | + 2*(8 + usidsz) /* two possible ACE for user */ |
2643 | + 3*(8 + gsidsz) /* three possible ACE for group and mask */ |
2644 | + 8 + wsidsz /* one ACE for world */ |
2645 | + 8 + asidsz /* one ACE for admin */ |
2646 | + 8 + ssidsz; /* one ACE for system */ |
2647 | if (isdir) /* a world denial for directories */ |
2648 | newattrsz += 8 + wsidsz; |
2649 | if (pxdesc->mode & 07000) /* a NULL ACE for special modes */ |
2650 | newattrsz += 8 + ntfs_sid_size(nullsid); |
2651 | /* account for non-owning users and groups */ |
2652 | for (k=0; k<pxdesc->acccnt; k++) { |
2653 | if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER) |
2654 | || (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP)) |
2655 | newattrsz += 3*40; /* fixme : maximum size */ |
2656 | } |
2657 | /* account for default ACE's */ |
2658 | newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */ |
2659 | newattr = (char*)ntfs_malloc(newattrsz); |
2660 | if (newattr) { |
2661 | /* build the main header part */ |
2662 | pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr; |
2663 | pnhead->revision = SECURITY_DESCRIPTOR_REVISION; |
2664 | pnhead->alignment = 0; |
2665 | /* |
2666 | * The flag SE_DACL_PROTECTED prevents the ACL |
2667 | * to be changed in an inheritance after creation |
2668 | */ |
2669 | pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED |
2670 | | SE_SELF_RELATIVE; |
2671 | /* |
2672 | * Windows prefers ACL first, do the same to |
2673 | * get the same hash value and avoid duplication |
2674 | */ |
2675 | /* build permissions */ |
2676 | aclsz = buildacls_posix(mapping,newattr, |
2677 | sizeof(SECURITY_DESCRIPTOR_RELATIVE), |
2678 | pxdesc, isdir, usid, gsid); |
2679 | if (aclsz && ((int)(sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2680 | + aclsz + usidsz + gsidsz) <= newattrsz)) { |
2681 | /* append usid and gsid */ |
2682 | memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2683 | + aclsz], usid, usidsz); |
2684 | memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2685 | + aclsz + usidsz], gsid, gsidsz); |
2686 | /* positions of ACL, USID and GSID into header */ |
2687 | pnhead->owner = |
2688 | cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2689 | + aclsz); |
2690 | pnhead->group = |
2691 | cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2692 | + aclsz + usidsz); |
2693 | pnhead->sacl = const_cpu_to_le32(0); |
2694 | pnhead->dacl = |
2695 | const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); |
2696 | } else { |
2697 | /* ACL failure (errno set) or overflow */ |
2698 | free(newattr); |
2699 | newattr = (char*)NULL; |
2700 | if (aclsz) { |
2701 | /* hope error was detected before overflowing */ |
2702 | ntfs_log_error("Security descriptor is longer than expected\n"); |
2703 | errno = EIO; |
2704 | } |
2705 | } |
2706 | } else |
2707 | errno = ENOMEM; |
2708 | return (newattr); |
2709 | } |
2710 | |
2711 | #endif /* POSIXACLS */ |
2712 | |
2713 | /* |
2714 | * Build a full security descriptor |
2715 | * returns descriptor in allocated memory, must free() after use |
2716 | */ |
2717 | |
2718 | char *ntfs_build_descr(mode_t mode, |
2719 | int isdir, const SID * usid, const SID * gsid) |
2720 | { |
2721 | int newattrsz; |
2722 | SECURITY_DESCRIPTOR_RELATIVE *pnhead; |
2723 | char *newattr; |
2724 | int aclsz; |
2725 | int usidsz; |
2726 | int gsidsz; |
2727 | int wsidsz; |
2728 | int asidsz; |
2729 | int ssidsz; |
2730 | |
2731 | usidsz = ntfs_sid_size(usid); |
2732 | gsidsz = ntfs_sid_size(gsid); |
2733 | wsidsz = ntfs_sid_size(worldsid); |
2734 | asidsz = ntfs_sid_size(adminsid); |
2735 | ssidsz = ntfs_sid_size(systemsid); |
2736 | |
2737 | /* allocate enough space for the new security attribute */ |
2738 | newattrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ |
2739 | + usidsz + gsidsz /* usid and gsid */ |
2740 | + sizeof(ACL) /* acl header */ |
2741 | + 2*(8 + usidsz) /* two possible ACE for user */ |
2742 | + 2*(8 + gsidsz) /* two possible ACE for group */ |
2743 | + 8 + wsidsz /* one ACE for world */ |
2744 | + 8 + asidsz /* one ACE for admin */ |
2745 | + 8 + ssidsz; /* one ACE for system */ |
2746 | if (isdir) /* a world denial for directories */ |
2747 | newattrsz += 8 + wsidsz; |
2748 | if (mode & 07000) /* a NULL ACE for special modes */ |
2749 | newattrsz += 8 + ntfs_sid_size(nullsid); |
2750 | newattr = (char*)ntfs_malloc(newattrsz); |
2751 | if (newattr) { |
2752 | /* build the main header part */ |
2753 | pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) newattr; |
2754 | pnhead->revision = SECURITY_DESCRIPTOR_REVISION; |
2755 | pnhead->alignment = 0; |
2756 | /* |
2757 | * The flag SE_DACL_PROTECTED prevents the ACL |
2758 | * to be changed in an inheritance after creation |
2759 | */ |
2760 | pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED |
2761 | | SE_SELF_RELATIVE; |
2762 | /* |
2763 | * Windows prefers ACL first, do the same to |
2764 | * get the same hash value and avoid duplication |
2765 | */ |
2766 | /* build permissions */ |
2767 | aclsz = buildacls(newattr, |
2768 | sizeof(SECURITY_DESCRIPTOR_RELATIVE), |
2769 | mode, isdir, usid, gsid); |
2770 | if (((int)sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2771 | + aclsz + usidsz + gsidsz) <= newattrsz) { |
2772 | /* append usid and gsid */ |
2773 | memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2774 | + aclsz], usid, usidsz); |
2775 | memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2776 | + aclsz + usidsz], gsid, gsidsz); |
2777 | /* positions of ACL, USID and GSID into header */ |
2778 | pnhead->owner = |
2779 | cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2780 | + aclsz); |
2781 | pnhead->group = |
2782 | cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) |
2783 | + aclsz + usidsz); |
2784 | pnhead->sacl = const_cpu_to_le32(0); |
2785 | pnhead->dacl = |
2786 | const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); |
2787 | } else { |
2788 | /* hope error was detected before overflowing */ |
2789 | free(newattr); |
2790 | newattr = (char*)NULL; |
2791 | ntfs_log_error("Security descriptor is longer than expected\n"); |
2792 | errno = EIO; |
2793 | } |
2794 | } else |
2795 | errno = ENOMEM; |
2796 | return (newattr); |
2797 | } |
2798 | |
2799 | /* |
2800 | * Create a mode_t permission set |
2801 | * from owner, group and world grants as represented in ACEs |
2802 | */ |
2803 | |
2804 | static int merge_permissions(BOOL isdir, |
2805 | le32 owner, le32 group, le32 world, le32 special) |
2806 | |
2807 | { |
2808 | int perm; |
2809 | |
2810 | perm = 0; |
2811 | /* build owner permission */ |
2812 | if (owner) { |
2813 | if (isdir) { |
2814 | /* exec if any of list, traverse */ |
2815 | if (owner & DIR_GEXEC) |
2816 | perm |= S_IXUSR; |
2817 | /* write if any of addfile, adddir, delchild */ |
2818 | if (owner & DIR_GWRITE) |
2819 | perm |= S_IWUSR; |
2820 | /* read if any of list */ |
2821 | if (owner & DIR_GREAD) |
2822 | perm |= S_IRUSR; |
2823 | } else { |
2824 | /* exec if execute or generic execute */ |
2825 | if (owner & FILE_GEXEC) |
2826 | perm |= S_IXUSR; |
2827 | /* write if any of writedata or generic write */ |
2828 | if (owner & FILE_GWRITE) |
2829 | perm |= S_IWUSR; |
2830 | /* read if any of readdata or generic read */ |
2831 | if (owner & FILE_GREAD) |
2832 | perm |= S_IRUSR; |
2833 | } |
2834 | } |
2835 | /* build group permission */ |
2836 | if (group) { |
2837 | if (isdir) { |
2838 | /* exec if any of list, traverse */ |
2839 | if (group & DIR_GEXEC) |
2840 | perm |= S_IXGRP; |
2841 | /* write if any of addfile, adddir, delchild */ |
2842 | if (group & DIR_GWRITE) |
2843 | perm |= S_IWGRP; |
2844 | /* read if any of list */ |
2845 | if (group & DIR_GREAD) |
2846 | perm |= S_IRGRP; |
2847 | } else { |
2848 | /* exec if execute */ |
2849 | if (group & FILE_GEXEC) |
2850 | perm |= S_IXGRP; |
2851 | /* write if any of writedata, appenddata */ |
2852 | if (group & FILE_GWRITE) |
2853 | perm |= S_IWGRP; |
2854 | /* read if any of readdata */ |
2855 | if (group & FILE_GREAD) |
2856 | perm |= S_IRGRP; |
2857 | } |
2858 | } |
2859 | /* build world permission */ |
2860 | if (world) { |
2861 | if (isdir) { |
2862 | /* exec if any of list, traverse */ |
2863 | if (world & DIR_GEXEC) |
2864 | perm |= S_IXOTH; |
2865 | /* write if any of addfile, adddir, delchild */ |
2866 | if (world & DIR_GWRITE) |
2867 | perm |= S_IWOTH; |
2868 | /* read if any of list */ |
2869 | if (world & DIR_GREAD) |
2870 | perm |= S_IROTH; |
2871 | } else { |
2872 | /* exec if execute */ |
2873 | if (world & FILE_GEXEC) |
2874 | perm |= S_IXOTH; |
2875 | /* write if any of writedata, appenddata */ |
2876 | if (world & FILE_GWRITE) |
2877 | perm |= S_IWOTH; |
2878 | /* read if any of readdata */ |
2879 | if (world & FILE_GREAD) |
2880 | perm |= S_IROTH; |
2881 | } |
2882 | } |
2883 | /* build special permission flags */ |
2884 | if (special) { |
2885 | if (special & FILE_APPEND_DATA) |
2886 | perm |= S_ISUID; |
2887 | if (special & FILE_WRITE_DATA) |
2888 | perm |= S_ISGID; |
2889 | if (special & FILE_READ_DATA) |
2890 | perm |= S_ISVTX; |
2891 | } |
2892 | return (perm); |
2893 | } |
2894 | |
2895 | #if POSIXACLS |
2896 | |
2897 | /* |
2898 | * Normalize a Posix ACL either from a sorted raw set of |
2899 | * access ACEs or default ACEs |
2900 | * (standard case : different owner, group and administrator) |
2901 | */ |
2902 | |
2903 | static int norm_std_permissions_posix(struct POSIX_SECURITY *posix_desc, |
2904 | BOOL groupowns, int start, int count, int target) |
2905 | { |
2906 | int j,k; |
2907 | s32 id; |
2908 | u16 tag; |
2909 | u16 tagsset; |
2910 | struct POSIX_ACE *pxace; |
2911 | mode_t grantgrps; |
2912 | mode_t grantwrld; |
2913 | mode_t denywrld; |
2914 | mode_t allow; |
2915 | mode_t deny; |
2916 | mode_t perms; |
2917 | mode_t mode; |
2918 | |
2919 | mode = 0; |
2920 | tagsset = 0; |
2921 | /* |
2922 | * Determine what is granted to some group or world |
2923 | * Also get denials to world which are meant to prevent |
2924 | * execution flags to be inherited by plain files |
2925 | */ |
2926 | pxace = posix_desc->acl.ace; |
2927 | grantgrps = 0; |
2928 | grantwrld = 0; |
2929 | denywrld = 0; |
2930 | for (j=start; j<(start + count); j++) { |
2931 | if (pxace[j].perms & POSIX_PERM_DENIAL) { |
2932 | /* deny world exec unless for default */ |
2933 | if ((pxace[j].tag == POSIX_ACL_OTHER) |
2934 | && !start) |
2935 | denywrld = pxace[j].perms; |
2936 | } else { |
2937 | switch (pxace[j].tag) { |
2938 | case POSIX_ACL_GROUP_OBJ : |
2939 | grantgrps |= pxace[j].perms; |
2940 | break; |
2941 | case POSIX_ACL_GROUP : |
2942 | if (pxace[j].id) |
2943 | grantgrps |= pxace[j].perms; |
2944 | break; |
2945 | case POSIX_ACL_OTHER : |
2946 | grantwrld = pxace[j].perms; |
2947 | break; |
2948 | default : |
2949 | break; |
2950 | } |
2951 | } |
2952 | } |
2953 | /* |
2954 | * Collect groups of ACEs related to the same id |
2955 | * and determine what is granted and what is denied. |
2956 | * It is important the ACEs have been sorted |
2957 | */ |
2958 | j = start; |
2959 | k = target; |
2960 | while (j < (start + count)) { |
2961 | tag = pxace[j].tag; |
2962 | id = pxace[j].id; |
2963 | if (pxace[j].perms & POSIX_PERM_DENIAL) { |
2964 | deny = pxace[j].perms | denywrld; |
2965 | allow = 0; |
2966 | } else { |
2967 | deny = denywrld; |
2968 | allow = pxace[j].perms; |
2969 | } |
2970 | j++; |
2971 | while ((j < (start + count)) |
2972 | && (pxace[j].tag == tag) |
2973 | && (pxace[j].id == id)) { |
2974 | if (pxace[j].perms & POSIX_PERM_DENIAL) |
2975 | deny |= pxace[j].perms; |
2976 | else |
2977 | allow |= pxace[j].perms; |
2978 | j++; |
2979 | } |
2980 | /* |
2981 | * Build the permissions equivalent to grants and denials |
2982 | */ |
2983 | if (groupowns) { |
2984 | if (tag == POSIX_ACL_MASK) |
2985 | perms = ~deny; |
2986 | else |
2987 | perms = allow & ~deny; |
2988 | } else |
2989 | switch (tag) { |
2990 | case POSIX_ACL_USER_OBJ : |
2991 | perms = (allow | grantgrps | grantwrld) & ~deny; |
2992 | break; |
2993 | case POSIX_ACL_USER : |
2994 | if (id) |
2995 | perms = (allow | grantgrps | grantwrld) |
2996 | & ~deny; |
2997 | else |
2998 | perms = allow; |
2999 | break; |
3000 | case POSIX_ACL_GROUP_OBJ : |
3001 | perms = (allow | grantwrld) & ~deny; |
3002 | break; |
3003 | case POSIX_ACL_GROUP : |
3004 | if (id) |
3005 | perms = (allow | grantwrld) & ~deny; |
3006 | else |
3007 | perms = allow; |
3008 | break; |
3009 | case POSIX_ACL_MASK : |
3010 | perms = ~deny; |
3011 | break; |
3012 | default : |
3013 | perms = allow & ~deny; |
3014 | break; |
3015 | } |
3016 | /* |
3017 | * Store into a Posix ACE |
3018 | */ |
3019 | if (tag != POSIX_ACL_SPECIAL) { |
3020 | pxace[k].tag = tag; |
3021 | pxace[k].id = id; |
3022 | pxace[k].perms = perms |
3023 | & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); |
3024 | tagsset |= tag; |
3025 | k++; |
3026 | } |
3027 | switch (tag) { |
3028 | case POSIX_ACL_USER_OBJ : |
3029 | mode |= ((perms & 7) << 6); |
3030 | break; |
3031 | case POSIX_ACL_GROUP_OBJ : |
3032 | case POSIX_ACL_MASK : |
3033 | mode = (mode & 07707) | ((perms & 7) << 3); |
3034 | break; |
3035 | case POSIX_ACL_OTHER : |
3036 | mode |= perms & 7; |
3037 | break; |
3038 | case POSIX_ACL_SPECIAL : |
3039 | mode |= (perms & (S_ISVTX | S_ISUID | S_ISGID)); |
3040 | break; |
3041 | default : |
3042 | break; |
3043 | } |
3044 | } |
3045 | if (!start) { /* not satisfactory */ |
3046 | posix_desc->mode = mode; |
3047 | posix_desc->tagsset = tagsset; |
3048 | } |
3049 | return (k - target); |
3050 | } |
3051 | |
3052 | #endif /* POSIXACLS */ |
3053 | |
3054 | /* |
3055 | * Interpret an ACL and extract meaningful grants |
3056 | * (standard case : different owner, group and administrator) |
3057 | */ |
3058 | |
3059 | static int build_std_permissions(const char *securattr, |
3060 | const SID *usid, const SID *gsid, BOOL isdir) |
3061 | { |
3062 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3063 | const ACL *pacl; |
3064 | const ACCESS_ALLOWED_ACE *pace; |
3065 | int offdacl; |
3066 | int offace; |
3067 | int acecnt; |
3068 | int nace; |
3069 | BOOL noown; |
3070 | le32 special; |
3071 | le32 allowown, allowgrp, allowall; |
3072 | le32 denyown, denygrp, denyall; |
3073 | |
3074 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3075 | offdacl = le32_to_cpu(phead->dacl); |
3076 | pacl = (const ACL*)&securattr[offdacl]; |
3077 | special = const_cpu_to_le32(0); |
3078 | allowown = allowgrp = allowall = const_cpu_to_le32(0); |
3079 | denyown = denygrp = denyall = const_cpu_to_le32(0); |
3080 | noown = TRUE; |
3081 | if (offdacl) { |
3082 | acecnt = le16_to_cpu(pacl->ace_count); |
3083 | offace = offdacl + sizeof(ACL); |
3084 | } else { |
3085 | acecnt = 0; |
3086 | offace = 0; |
3087 | } |
3088 | for (nace = 0; nace < acecnt; nace++) { |
3089 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3090 | if (!(pace->flags & INHERIT_ONLY_ACE)) { |
3091 | if (ntfs_same_sid(usid, &pace->sid) |
3092 | || ntfs_same_sid(ownersid, &pace->sid)) { |
3093 | noown = FALSE; |
3094 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3095 | allowown |= pace->mask; |
3096 | else if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3097 | denyown |= pace->mask; |
3098 | } else |
3099 | if (ntfs_same_sid(gsid, &pace->sid) |
3100 | && !(pace->mask & WRITE_OWNER)) { |
3101 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3102 | allowgrp |= pace->mask; |
3103 | else if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3104 | denygrp |= pace->mask; |
3105 | } else |
3106 | if (is_world_sid((const SID*)&pace->sid)) { |
3107 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3108 | allowall |= pace->mask; |
3109 | else |
3110 | if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3111 | denyall |= pace->mask; |
3112 | } else |
3113 | if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) |
3114 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) |
3115 | special |= pace->mask; |
3116 | } |
3117 | offace += le16_to_cpu(pace->size); |
3118 | } |
3119 | /* |
3120 | * No indication about owner's rights : grant basic rights |
3121 | * This happens for files created by Windows in directories |
3122 | * created by Linux and owned by root, because Windows |
3123 | * merges the admin ACEs |
3124 | */ |
3125 | if (noown) |
3126 | allowown = (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE); |
3127 | /* |
3128 | * Add to owner rights granted to group or world |
3129 | * unless denied personaly, and add to group rights |
3130 | * granted to world unless denied specifically |
3131 | */ |
3132 | allowown |= (allowgrp | allowall); |
3133 | allowgrp |= allowall; |
3134 | return (merge_permissions(isdir, |
3135 | allowown & ~(denyown | denyall), |
3136 | allowgrp & ~(denygrp | denyall), |
3137 | allowall & ~denyall, |
3138 | special)); |
3139 | } |
3140 | |
3141 | /* |
3142 | * Interpret an ACL and extract meaningful grants |
3143 | * (special case : owner and group are the same, |
3144 | * and not administrator) |
3145 | */ |
3146 | |
3147 | static int build_owngrp_permissions(const char *securattr, |
3148 | const SID *usid, BOOL isdir) |
3149 | { |
3150 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3151 | const ACL *pacl; |
3152 | const ACCESS_ALLOWED_ACE *pace; |
3153 | int offdacl; |
3154 | int offace; |
3155 | int acecnt; |
3156 | int nace; |
3157 | le32 special; |
3158 | BOOL grppresent; |
3159 | BOOL ownpresent; |
3160 | le32 allowown, allowgrp, allowall; |
3161 | le32 denyown, denygrp, denyall; |
3162 | |
3163 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3164 | offdacl = le32_to_cpu(phead->dacl); |
3165 | pacl = (const ACL*)&securattr[offdacl]; |
3166 | special = const_cpu_to_le32(0); |
3167 | allowown = allowgrp = allowall = const_cpu_to_le32(0); |
3168 | denyown = denygrp = denyall = const_cpu_to_le32(0); |
3169 | ownpresent = FALSE; |
3170 | grppresent = FALSE; |
3171 | if (offdacl) { |
3172 | acecnt = le16_to_cpu(pacl->ace_count); |
3173 | offace = offdacl + sizeof(ACL); |
3174 | } else { |
3175 | acecnt = 0; |
3176 | offace = 0; |
3177 | } |
3178 | for (nace = 0; nace < acecnt; nace++) { |
3179 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3180 | if (!(pace->flags & INHERIT_ONLY_ACE)) { |
3181 | if ((ntfs_same_sid(usid, &pace->sid) |
3182 | || ntfs_same_sid(ownersid, &pace->sid)) |
3183 | && (pace->mask & WRITE_OWNER)) { |
3184 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { |
3185 | allowown |= pace->mask; |
3186 | ownpresent = TRUE; |
3187 | } |
3188 | } else |
3189 | if (ntfs_same_sid(usid, &pace->sid) |
3190 | && (!(pace->mask & WRITE_OWNER))) { |
3191 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { |
3192 | allowgrp |= pace->mask; |
3193 | grppresent = TRUE; |
3194 | } |
3195 | } else |
3196 | if (is_world_sid((const SID*)&pace->sid)) { |
3197 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3198 | allowall |= pace->mask; |
3199 | else |
3200 | if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3201 | denyall |= pace->mask; |
3202 | } else |
3203 | if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) |
3204 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) |
3205 | special |= pace->mask; |
3206 | } |
3207 | offace += le16_to_cpu(pace->size); |
3208 | } |
3209 | if (!ownpresent) |
3210 | allowown = allowall; |
3211 | if (!grppresent) |
3212 | allowgrp = allowall; |
3213 | return (merge_permissions(isdir, |
3214 | allowown & ~(denyown | denyall), |
3215 | allowgrp & ~(denygrp | denyall), |
3216 | allowall & ~denyall, |
3217 | special)); |
3218 | } |
3219 | |
3220 | #if POSIXACLS |
3221 | |
3222 | /* |
3223 | * Normalize a Posix ACL either from a sorted raw set of |
3224 | * access ACEs or default ACEs |
3225 | * (special case : owner or/and group is administrator) |
3226 | */ |
3227 | |
3228 | static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc, |
3229 | int start, int count, int target) |
3230 | { |
3231 | int j,k; |
3232 | s32 id; |
3233 | u16 tag; |
3234 | u16 tagsset; |
3235 | struct POSIX_ACE *pxace; |
3236 | mode_t denywrld; |
3237 | mode_t allow; |
3238 | mode_t deny; |
3239 | mode_t perms; |
3240 | mode_t mode; |
3241 | |
3242 | mode = 0; |
3243 | pxace = posix_desc->acl.ace; |
3244 | tagsset = 0; |
3245 | denywrld = 0; |
3246 | /* |
3247 | * Get denials to world which are meant to prevent |
3248 | * execution flags to be inherited by plain files |
3249 | */ |
3250 | for (j=start; j<(start + count); j++) { |
3251 | if (pxace[j].perms & POSIX_PERM_DENIAL) { |
3252 | /* deny world exec not for default */ |
3253 | if ((pxace[j].tag == POSIX_ACL_OTHER) |
3254 | && !start) |
3255 | denywrld = pxace[j].perms; |
3256 | } |
3257 | } |
3258 | /* |
3259 | * Collect groups of ACEs related to the same id |
3260 | * and determine what is granted (denials are ignored) |
3261 | * It is important the ACEs have been sorted |
3262 | */ |
3263 | j = start; |
3264 | k = target; |
3265 | deny = 0; |
3266 | while (j < (start + count)) { |
3267 | allow = 0; |
3268 | tag = pxace[j].tag; |
3269 | id = pxace[j].id; |
3270 | if (tag == POSIX_ACL_MASK) { |
3271 | deny = pxace[j].perms; |
3272 | j++; |
3273 | while ((j < (start + count)) |
3274 | && (pxace[j].tag == POSIX_ACL_MASK)) |
3275 | j++; |
3276 | } else { |
3277 | if (!(pxace[j].perms & POSIX_PERM_DENIAL)) |
3278 | allow = pxace[j].perms; |
3279 | j++; |
3280 | while ((j < (start + count)) |
3281 | && (pxace[j].tag == tag) |
3282 | && (pxace[j].id == id)) { |
3283 | if (!(pxace[j].perms & POSIX_PERM_DENIAL)) |
3284 | allow |= pxace[j].perms; |
3285 | j++; |
3286 | } |
3287 | } |
3288 | |
3289 | /* |
3290 | * Store the grants into a Posix ACE |
3291 | */ |
3292 | if (tag == POSIX_ACL_MASK) |
3293 | perms = ~deny; |
3294 | else |
3295 | perms = allow & ~denywrld; |
3296 | if (tag != POSIX_ACL_SPECIAL) { |
3297 | pxace[k].tag = tag; |
3298 | pxace[k].id = id; |
3299 | pxace[k].perms = perms |
3300 | & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); |
3301 | tagsset |= tag; |
3302 | k++; |
3303 | } |
3304 | switch (tag) { |
3305 | case POSIX_ACL_USER_OBJ : |
3306 | mode |= ((perms & 7) << 6); |
3307 | break; |
3308 | case POSIX_ACL_GROUP_OBJ : |
3309 | case POSIX_ACL_MASK : |
3310 | mode = (mode & 07707) | ((perms & 7) << 3); |
3311 | break; |
3312 | case POSIX_ACL_OTHER : |
3313 | mode |= perms & 7; |
3314 | break; |
3315 | case POSIX_ACL_SPECIAL : |
3316 | mode |= perms & (S_ISVTX | S_ISUID | S_ISGID); |
3317 | break; |
3318 | default : |
3319 | break; |
3320 | } |
3321 | } |
3322 | if (!start) { /* not satisfactory */ |
3323 | posix_desc->mode = mode; |
3324 | posix_desc->tagsset = tagsset; |
3325 | } |
3326 | return (k - target); |
3327 | } |
3328 | |
3329 | #endif /* POSIXACLS */ |
3330 | |
3331 | /* |
3332 | * Interpret an ACL and extract meaningful grants |
3333 | * (special case : owner or/and group is administrator) |
3334 | */ |
3335 | |
3336 | |
3337 | static int build_ownadmin_permissions(const char *securattr, |
3338 | const SID *usid, const SID *gsid, BOOL isdir) |
3339 | { |
3340 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3341 | const ACL *pacl; |
3342 | const ACCESS_ALLOWED_ACE *pace; |
3343 | int offdacl; |
3344 | int offace; |
3345 | int acecnt; |
3346 | int nace; |
3347 | BOOL firstapply; |
3348 | int isforeign; |
3349 | le32 special; |
3350 | le32 allowown, allowgrp, allowall; |
3351 | le32 denyown, denygrp, denyall; |
3352 | |
3353 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3354 | offdacl = le32_to_cpu(phead->dacl); |
3355 | pacl = (const ACL*)&securattr[offdacl]; |
3356 | special = const_cpu_to_le32(0); |
3357 | allowown = allowgrp = allowall = const_cpu_to_le32(0); |
3358 | denyown = denygrp = denyall = const_cpu_to_le32(0); |
3359 | if (offdacl) { |
3360 | acecnt = le16_to_cpu(pacl->ace_count); |
3361 | offace = offdacl + sizeof(ACL); |
3362 | } else { |
3363 | acecnt = 0; |
3364 | offace = 0; |
3365 | } |
3366 | firstapply = TRUE; |
3367 | isforeign = 3; |
3368 | for (nace = 0; nace < acecnt; nace++) { |
3369 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3370 | if (!(pace->flags & INHERIT_ONLY_ACE) |
3371 | && !(~pace->mask & (ROOT_OWNER_UNMARK | ROOT_GROUP_UNMARK))) { |
3372 | if ((ntfs_same_sid(usid, &pace->sid) |
3373 | || ntfs_same_sid(ownersid, &pace->sid)) |
3374 | && (((pace->mask & WRITE_OWNER) && firstapply))) { |
3375 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { |
3376 | allowown |= pace->mask; |
3377 | isforeign &= ~1; |
3378 | } else |
3379 | if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3380 | denyown |= pace->mask; |
3381 | } else |
3382 | if (ntfs_same_sid(gsid, &pace->sid) |
3383 | && (!(pace->mask & WRITE_OWNER))) { |
3384 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { |
3385 | allowgrp |= pace->mask; |
3386 | isforeign &= ~2; |
3387 | } else |
3388 | if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3389 | denygrp |= pace->mask; |
3390 | } else if (is_world_sid((const SID*)&pace->sid)) { |
3391 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3392 | allowall |= pace->mask; |
3393 | else |
3394 | if (pace->type == ACCESS_DENIED_ACE_TYPE) |
3395 | denyall |= pace->mask; |
3396 | } |
3397 | firstapply = FALSE; |
3398 | } else |
3399 | if (!(pace->flags & INHERIT_ONLY_ACE)) |
3400 | if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) |
3401 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) |
3402 | special |= pace->mask; |
3403 | offace += le16_to_cpu(pace->size); |
3404 | } |
3405 | if (isforeign) { |
3406 | allowown |= (allowgrp | allowall); |
3407 | allowgrp |= allowall; |
3408 | } |
3409 | return (merge_permissions(isdir, |
3410 | allowown & ~(denyown | denyall), |
3411 | allowgrp & ~(denygrp | denyall), |
3412 | allowall & ~denyall, |
3413 | special)); |
3414 | } |
3415 | |
3416 | #if OWNERFROMACL |
3417 | |
3418 | /* |
3419 | * Define the owner of a file as the first user allowed |
3420 | * to change the owner, instead of the user defined as owner. |
3421 | * |
3422 | * This produces better approximations for files written by a |
3423 | * Windows user in an inheritable directory owned by another user, |
3424 | * as the access rights are inheritable but the ownership is not. |
3425 | * |
3426 | * An important case is the directories "Documents and Settings/user" |
3427 | * which the users must have access to, though Windows considers them |
3428 | * as owned by administrator. |
3429 | */ |
3430 | |
3431 | const SID *ntfs_acl_owner(const char *securattr) |
3432 | { |
3433 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3434 | const SID *usid; |
3435 | const ACL *pacl; |
3436 | const ACCESS_ALLOWED_ACE *pace; |
3437 | int offdacl; |
3438 | int offace; |
3439 | int acecnt; |
3440 | int nace; |
3441 | BOOL found; |
3442 | |
3443 | found = FALSE; |
3444 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3445 | offdacl = le32_to_cpu(phead->dacl); |
3446 | if (offdacl) { |
3447 | pacl = (const ACL*)&securattr[offdacl]; |
3448 | acecnt = le16_to_cpu(pacl->ace_count); |
3449 | offace = offdacl + sizeof(ACL); |
3450 | nace = 0; |
3451 | do { |
3452 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3453 | if ((pace->mask & WRITE_OWNER) |
3454 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3455 | && ntfs_is_user_sid(&pace->sid)) |
3456 | found = TRUE; |
3457 | offace += le16_to_cpu(pace->size); |
3458 | } while (!found && (++nace < acecnt)); |
3459 | } |
3460 | if (found) |
3461 | usid = &pace->sid; |
3462 | else |
3463 | usid = (const SID*)&securattr[le32_to_cpu(phead->owner)]; |
3464 | return (usid); |
3465 | } |
3466 | |
3467 | #else |
3468 | |
3469 | /* |
3470 | * Special case for files owned by administrator with full |
3471 | * access granted to a mapped user : consider this user as the tenant |
3472 | * of the file. |
3473 | * |
3474 | * This situation cannot be represented with Linux concepts and can |
3475 | * only be found for files or directories created by Windows. |
3476 | * Typical situation : directory "Documents and Settings/user" which |
3477 | * is on the path to user's files and must be given access to user |
3478 | * only. |
3479 | * |
3480 | * Check file is owned by administrator and no user has rights before |
3481 | * calling. |
3482 | * Returns the uid of tenant or zero if none |
3483 | */ |
3484 | |
3485 | |
3486 | static uid_t find_tenant(struct MAPPING *const mapping[], |
3487 | const char *securattr) |
3488 | { |
3489 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3490 | const ACL *pacl; |
3491 | const ACCESS_ALLOWED_ACE *pace; |
3492 | int offdacl; |
3493 | int offace; |
3494 | int acecnt; |
3495 | int nace; |
3496 | uid_t tid; |
3497 | uid_t xid; |
3498 | |
3499 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3500 | offdacl = le32_to_cpu(phead->dacl); |
3501 | pacl = (const ACL*)&securattr[offdacl]; |
3502 | tid = 0; |
3503 | if (offdacl) { |
3504 | acecnt = le16_to_cpu(pacl->ace_count); |
3505 | offace = offdacl + sizeof(ACL); |
3506 | } else |
3507 | acecnt = 0; |
3508 | for (nace = 0; nace < acecnt; nace++) { |
3509 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3510 | if ((pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3511 | && (pace->mask & DIR_WRITE)) { |
3512 | xid = NTFS_FIND_USER(mapping[MAPUSERS], &pace->sid); |
3513 | if (xid) tid = xid; |
3514 | } |
3515 | offace += le16_to_cpu(pace->size); |
3516 | } |
3517 | return (tid); |
3518 | } |
3519 | |
3520 | #endif /* OWNERFROMACL */ |
3521 | |
3522 | #if POSIXACLS |
3523 | |
3524 | /* |
3525 | * Build Posix permissions from an ACL |
3526 | * returns a pointer to the requested permissions |
3527 | * or a null pointer (with errno set) if there is a problem |
3528 | * |
3529 | * If the NTFS ACL was created according to our rules, the retrieved |
3530 | * Posix ACL should be the exact ACL which was set. However if |
3531 | * the NTFS ACL was built by a different tool, the result could |
3532 | * be a a poor approximation of what was expected |
3533 | */ |
3534 | |
3535 | struct POSIX_SECURITY *ntfs_build_permissions_posix( |
3536 | struct MAPPING *const mapping[], |
3537 | const char *securattr, |
3538 | const SID *usid, const SID *gsid, BOOL isdir) |
3539 | { |
3540 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3541 | struct POSIX_SECURITY *pxdesc; |
3542 | const ACL *pacl; |
3543 | const ACCESS_ALLOWED_ACE *pace; |
3544 | struct POSIX_ACE *pxace; |
3545 | struct { |
3546 | uid_t prevuid; |
3547 | gid_t prevgid; |
3548 | int groupmasks; |
3549 | s16 tagsset; |
3550 | BOOL gotowner; |
3551 | BOOL gotownermask; |
3552 | BOOL gotgroup; |
3553 | mode_t permswrld; |
3554 | } ctx[2], *pctx; |
3555 | int offdacl; |
3556 | int offace; |
3557 | int alloccnt; |
3558 | int acecnt; |
3559 | uid_t uid; |
3560 | gid_t gid; |
3561 | int i,j; |
3562 | int k,l; |
3563 | BOOL ignore; |
3564 | BOOL adminowns; |
3565 | BOOL groupowns; |
3566 | BOOL firstinh; |
3567 | BOOL genericinh; |
3568 | |
3569 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; |
3570 | offdacl = le32_to_cpu(phead->dacl); |
3571 | if (offdacl) { |
3572 | pacl = (const ACL*)&securattr[offdacl]; |
3573 | acecnt = le16_to_cpu(pacl->ace_count); |
3574 | offace = offdacl + sizeof(ACL); |
3575 | } else { |
3576 | acecnt = 0; |
3577 | offace = 0; |
3578 | } |
3579 | adminowns = FALSE; |
3580 | groupowns = ntfs_same_sid(gsid,usid); |
3581 | firstinh = FALSE; |
3582 | genericinh = FALSE; |
3583 | /* |
3584 | * Build a raw posix security descriptor |
3585 | * by just translating permissions and ids |
3586 | * Add 2 to the count of ACE to be able to insert |
3587 | * a group ACE later in access and default ACLs |
3588 | * and add 2 more to be able to insert ACEs for owner |
3589 | * and 2 more for other |
3590 | */ |
3591 | alloccnt = acecnt + 6; |
3592 | pxdesc = (struct POSIX_SECURITY*)malloc( |
3593 | sizeof(struct POSIX_SECURITY) |
3594 | + alloccnt*sizeof(struct POSIX_ACE)); |
3595 | k = 0; |
3596 | l = alloccnt; |
3597 | for (i=0; i<2; i++) { |
3598 | pctx = &ctx[i]; |
3599 | pctx->permswrld = 0; |
3600 | pctx->prevuid = -1; |
3601 | pctx->prevgid = -1; |
3602 | pctx->groupmasks = 0; |
3603 | pctx->tagsset = 0; |
3604 | pctx->gotowner = FALSE; |
3605 | pctx->gotgroup = FALSE; |
3606 | pctx->gotownermask = FALSE; |
3607 | } |
3608 | for (j=0; j<acecnt; j++) { |
3609 | pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; |
3610 | if (pace->flags & INHERIT_ONLY_ACE) { |
3611 | pxace = &pxdesc->acl.ace[l - 1]; |
3612 | pctx = &ctx[1]; |
3613 | } else { |
3614 | pxace = &pxdesc->acl.ace[k]; |
3615 | pctx = &ctx[0]; |
3616 | } |
3617 | ignore = FALSE; |
3618 | /* |
3619 | * grants for root as a designated user or group |
3620 | */ |
3621 | if ((~pace->mask & (ROOT_OWNER_UNMARK | ROOT_GROUP_UNMARK)) |
3622 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3623 | && ntfs_same_sid(&pace->sid, adminsid)) { |
3624 | pxace->tag = (pace->mask & ROOT_OWNER_UNMARK ? POSIX_ACL_GROUP : POSIX_ACL_USER); |
3625 | pxace->id = 0; |
3626 | if ((pace->mask & (GENERIC_ALL | WRITE_OWNER)) |
3627 | && (pace->flags & INHERIT_ONLY_ACE)) |
3628 | ignore = genericinh = TRUE; |
3629 | } else |
3630 | if (ntfs_same_sid(usid, &pace->sid)) { |
3631 | pxace->id = -1; |
3632 | /* |
3633 | * Owner has no write-owner right : |
3634 | * a group was defined same as owner |
3635 | * or admin was owner or group : |
3636 | * denials are meant to owner |
3637 | * and grants are meant to group |
3638 | */ |
3639 | if (!(pace->mask & (WRITE_OWNER | GENERIC_ALL)) |
3640 | && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) { |
3641 | if (ntfs_same_sid(gsid,usid)) { |
3642 | pxace->tag = POSIX_ACL_GROUP_OBJ; |
3643 | pxace->id = -1; |
3644 | } else { |
3645 | if (ntfs_same_sid(&pace->sid,usid)) |
3646 | groupowns = TRUE; |
3647 | gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); |
3648 | if (gid) { |
3649 | pxace->tag = POSIX_ACL_GROUP; |
3650 | pxace->id = gid; |
3651 | pctx->prevgid = gid; |
3652 | } else { |
3653 | uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); |
3654 | if (uid) { |
3655 | pxace->tag = POSIX_ACL_USER; |
3656 | pxace->id = uid; |
3657 | } else |
3658 | ignore = TRUE; |
3659 | } |
3660 | } |
3661 | } else { |
3662 | /* |
3663 | * when group owns, late denials for owner |
3664 | * mean group mask |
3665 | */ |
3666 | if ((pace->type == ACCESS_DENIED_ACE_TYPE) |
3667 | && (pace->mask & WRITE_OWNER)) { |
3668 | pxace->tag = POSIX_ACL_MASK; |
3669 | pctx->gotownermask = TRUE; |
3670 | if (pctx->gotowner) |
3671 | pctx->groupmasks++; |
3672 | } else { |
3673 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3674 | pctx->gotowner = TRUE; |
3675 | if (pctx->gotownermask && !pctx->gotowner) { |
3676 | uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); |
3677 | pxace->id = uid; |
3678 | pxace->tag = POSIX_ACL_USER; |
3679 | } else |
3680 | pxace->tag = POSIX_ACL_USER_OBJ; |
3681 | /* system ignored, and admin */ |
3682 | /* ignored at first position */ |
3683 | if (pace->flags & INHERIT_ONLY_ACE) { |
3684 | if ((firstinh && ntfs_same_sid(&pace->sid,adminsid)) |
3685 | || ntfs_same_sid(&pace->sid,systemsid)) |
3686 | ignore = TRUE; |
3687 | if (!firstinh) { |
3688 | firstinh = TRUE; |
3689 | } |
3690 | } else { |
3691 | if ((adminowns && ntfs_same_sid(&pace->sid,adminsid)) |
3692 | || ntfs_same_sid(&pace->sid,systemsid)) |
3693 | ignore = TRUE; |
3694 | if (ntfs_same_sid(usid,adminsid)) |
3695 | adminowns = TRUE; |
3696 | } |
3697 | } |
3698 | } |
3699 | } else if (ntfs_same_sid(gsid, &pace->sid)) { |
3700 | if ((pace->type == ACCESS_DENIED_ACE_TYPE) |
3701 | && (pace->mask & WRITE_OWNER)) { |
3702 | pxace->tag = POSIX_ACL_MASK; |
3703 | pxace->id = -1; |
3704 | if (pctx->gotowner) |
3705 | pctx->groupmasks++; |
3706 | } else { |
3707 | if (pctx->gotgroup || (pctx->groupmasks > 1)) { |
3708 | gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); |
3709 | if (gid) { |
3710 | pxace->id = gid; |
3711 | pxace->tag = POSIX_ACL_GROUP; |
3712 | pctx->prevgid = gid; |
3713 | } else |
3714 | ignore = TRUE; |
3715 | } else { |
3716 | pxace->id = -1; |
3717 | pxace->tag = POSIX_ACL_GROUP_OBJ; |
3718 | if (pace->type == ACCESS_ALLOWED_ACE_TYPE) |
3719 | pctx->gotgroup = TRUE; |
3720 | } |
3721 | |
3722 | if (ntfs_same_sid(gsid,adminsid) |
3723 | || ntfs_same_sid(gsid,systemsid)) { |
3724 | if (pace->mask & (WRITE_OWNER | GENERIC_ALL)) |
3725 | ignore = TRUE; |
3726 | if (ntfs_same_sid(gsid,adminsid)) |
3727 | adminowns = TRUE; |
3728 | else |
3729 | genericinh = ignore; |
3730 | } |
3731 | } |
3732 | } else if (is_world_sid((const SID*)&pace->sid)) { |
3733 | pxace->id = -1; |
3734 | pxace->tag = POSIX_ACL_OTHER; |
3735 | if ((pace->type == ACCESS_DENIED_ACE_TYPE) |
3736 | && (pace->flags & INHERIT_ONLY_ACE)) |
3737 | ignore = TRUE; |
3738 | } else if (ntfs_same_sid((const SID*)&pace->sid,nullsid)) { |
3739 | pxace->id = -1; |
3740 | pxace->tag = POSIX_ACL_SPECIAL; |
3741 | } else { |
3742 | uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); |
3743 | if (uid) { |
3744 | if ((pace->type == ACCESS_DENIED_ACE_TYPE) |
3745 | && (pace->mask & WRITE_OWNER) |
3746 | && (pctx->prevuid != uid)) { |
3747 | pxace->id = -1; |
3748 | pxace->tag = POSIX_ACL_MASK; |
3749 | } else { |
3750 | pxace->id = uid; |
3751 | pxace->tag = POSIX_ACL_USER; |
3752 | } |
3753 | pctx->prevuid = uid; |
3754 | } else { |
3755 | gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); |
3756 | if (gid) { |
3757 | if ((pace->type == ACCESS_DENIED_ACE_TYPE) |
3758 | && (pace->mask & WRITE_OWNER) |
3759 | && (pctx->prevgid != gid)) { |
3760 | pxace->tag = POSIX_ACL_MASK; |
3761 | pctx->groupmasks++; |
3762 | } else { |
3763 | pxace->tag = POSIX_ACL_GROUP; |
3764 | } |
3765 | pxace->id = gid; |
3766 | pctx->prevgid = gid; |
3767 | } else { |
3768 | /* |
3769 | * do not grant rights to unknown |
3770 | * people and do not define root as a |
3771 | * designated user or group |
3772 | */ |
3773 | ignore = TRUE; |
3774 | } |
3775 | } |
3776 | } |
3777 | if (!ignore) { |
3778 | pxace->perms = 0; |
3779 | /* specific decoding for vtx/uid/gid */ |
3780 | if (pxace->tag == POSIX_ACL_SPECIAL) { |
3781 | if (pace->mask & FILE_APPEND_DATA) |
3782 | pxace->perms |= S_ISUID; |
3783 | if (pace->mask & FILE_WRITE_DATA) |
3784 | pxace->perms |= S_ISGID; |
3785 | if (pace->mask & FILE_READ_DATA) |
3786 | pxace->perms |= S_ISVTX; |
3787 | } else |
3788 | if (isdir) { |
3789 | if (pace->mask & DIR_GEXEC) |
3790 | pxace->perms |= POSIX_PERM_X; |
3791 | if (pace->mask & DIR_GWRITE) |
3792 | pxace->perms |= POSIX_PERM_W; |
3793 | if (pace->mask & DIR_GREAD) |
3794 | pxace->perms |= POSIX_PERM_R; |
3795 | if ((pace->mask & GENERIC_ALL) |
3796 | && (pace->flags & INHERIT_ONLY_ACE)) |
3797 | pxace->perms |= POSIX_PERM_X |
3798 | | POSIX_PERM_W |
3799 | | POSIX_PERM_R; |
3800 | } else { |
3801 | if (pace->mask & FILE_GEXEC) |
3802 | pxace->perms |= POSIX_PERM_X; |
3803 | if (pace->mask & FILE_GWRITE) |
3804 | pxace->perms |= POSIX_PERM_W; |
3805 | if (pace->mask & FILE_GREAD) |
3806 | pxace->perms |= POSIX_PERM_R; |
3807 | } |
3808 | |
3809 | if (pace->type != ACCESS_ALLOWED_ACE_TYPE) |
3810 | pxace->perms |= POSIX_PERM_DENIAL; |
3811 | else |
3812 | if (pxace->tag == POSIX_ACL_OTHER) |
3813 | pctx->permswrld |= pxace->perms; |
3814 | pctx->tagsset |= pxace->tag; |
3815 | if (pace->flags & INHERIT_ONLY_ACE) { |
3816 | l--; |
3817 | } else { |
3818 | k++; |
3819 | } |
3820 | } |
3821 | offace += le16_to_cpu(pace->size); |
3822 | } |
3823 | /* |
3824 | * Create world perms if none (both lists) |
3825 | */ |
3826 | for (i=0; i<2; i++) |
3827 | if ((genericinh || !i) |
3828 | && !(ctx[i].tagsset & POSIX_ACL_OTHER)) { |
3829 | if (i) |
3830 | pxace = &pxdesc->acl.ace[--l]; |
3831 | else |
3832 | pxace = &pxdesc->acl.ace[k++]; |
3833 | pxace->tag = POSIX_ACL_OTHER; |
3834 | pxace->id = -1; |
3835 | pxace->perms = 0; |
3836 | ctx[i].tagsset |= POSIX_ACL_OTHER; |
3837 | ctx[i].permswrld = 0; |
3838 | } |
3839 | /* |
3840 | * Set basic owner perms if none (both lists) |
3841 | * This happens for files created by Windows in directories |
3842 | * created by Linux and owned by root, because Windows |
3843 | * merges the admin ACEs |
3844 | */ |
3845 | for (i=0; i<2; i++) |
3846 | if (!(ctx[i].tagsset & POSIX_ACL_USER_OBJ) |
3847 | && (ctx[i].tagsset & POSIX_ACL_OTHER)) { |
3848 | if (i) |
3849 | pxace = &pxdesc->acl.ace[--l]; |
3850 | else |
3851 | pxace = &pxdesc->acl.ace[k++]; |
3852 | pxace->tag = POSIX_ACL_USER_OBJ; |
3853 | pxace->id = -1; |
3854 | pxace->perms = POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X; |
3855 | ctx[i].tagsset |= POSIX_ACL_USER_OBJ; |
3856 | } |
3857 | /* |
3858 | * Duplicate world perms as group_obj perms if none |
3859 | */ |
3860 | for (i=0; i<2; i++) |
3861 | if ((ctx[i].tagsset & POSIX_ACL_OTHER) |
3862 | && !(ctx[i].tagsset & POSIX_ACL_GROUP_OBJ)) { |
3863 | if (i) |
3864 | pxace = &pxdesc->acl.ace[--l]; |
3865 | else |
3866 | pxace = &pxdesc->acl.ace[k++]; |
3867 | pxace->tag = POSIX_ACL_GROUP_OBJ; |
3868 | pxace->id = -1; |
3869 | pxace->perms = ctx[i].permswrld; |
3870 | ctx[i].tagsset |= POSIX_ACL_GROUP_OBJ; |
3871 | } |
3872 | /* |
3873 | * Also duplicate world perms as group perms if they |
3874 | * were converted to mask and not followed by a group entry |
3875 | */ |
3876 | if (ctx[0].groupmasks) { |
3877 | for (j=k-2; j>=0; j--) { |
3878 | if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) |
3879 | && (pxdesc->acl.ace[j].id != -1) |
3880 | && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) |
3881 | || (pxdesc->acl.ace[j+1].id |
3882 | != pxdesc->acl.ace[j].id))) { |
3883 | pxace = &pxdesc->acl.ace[k]; |
3884 | pxace->tag = POSIX_ACL_GROUP; |
3885 | pxace->id = pxdesc->acl.ace[j].id; |
3886 | pxace->perms = ctx[0].permswrld; |
3887 | ctx[0].tagsset |= POSIX_ACL_GROUP; |
3888 | k++; |
3889 | } |
3890 | if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) |
3891 | pxdesc->acl.ace[j].id = -1; |
3892 | } |
3893 | } |
3894 | if (ctx[1].groupmasks) { |
3895 | for (j=l; j<(alloccnt-1); j++) { |
3896 | if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) |
3897 | && (pxdesc->acl.ace[j].id != -1) |
3898 | && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) |
3899 | || (pxdesc->acl.ace[j+1].id |
3900 | != pxdesc->acl.ace[j].id))) { |
3901 | pxace = &pxdesc->acl.ace[l - 1]; |
3902 | pxace->tag = POSIX_ACL_GROUP; |
3903 | pxace->id = pxdesc->acl.ace[j].id; |
3904 | pxace->perms = ctx[1].permswrld; |
3905 | ctx[1].tagsset |= POSIX_ACL_GROUP; |
3906 | l--; |
3907 | } |
3908 | if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) |
3909 | pxdesc->acl.ace[j].id = -1; |
3910 | } |
3911 | } |
3912 | |
3913 | /* |
3914 | * Insert default mask if none present and |
3915 | * there are designated users or groups |
3916 | * (the space for it has not beed used) |
3917 | */ |
3918 | for (i=0; i<2; i++) |
3919 | if ((ctx[i].tagsset & (POSIX_ACL_USER | POSIX_ACL_GROUP)) |
3920 | && !(ctx[i].tagsset & POSIX_ACL_MASK)) { |
3921 | if (i) |
3922 | pxace = &pxdesc->acl.ace[--l]; |
3923 | else |
3924 | pxace = &pxdesc->acl.ace[k++]; |
3925 | pxace->tag = POSIX_ACL_MASK; |
3926 | pxace->id = -1; |
3927 | pxace->perms = POSIX_PERM_DENIAL; |
3928 | ctx[i].tagsset |= POSIX_ACL_MASK; |
3929 | } |
3930 | |
3931 | if (k > l) { |
3932 | ntfs_log_error("Posix descriptor is longer than expected\n"); |
3933 | errno = EIO; |
3934 | free(pxdesc); |
3935 | pxdesc = (struct POSIX_SECURITY*)NULL; |
3936 | } else { |
3937 | pxdesc->acccnt = k; |
3938 | pxdesc->defcnt = alloccnt - l; |
3939 | pxdesc->firstdef = l; |
3940 | pxdesc->tagsset = ctx[0].tagsset; |
3941 | pxdesc->acl.version = POSIX_VERSION; |
3942 | pxdesc->acl.flags = 0; |
3943 | pxdesc->acl.filler = 0; |
3944 | ntfs_sort_posix(pxdesc); |
3945 | if (adminowns) { |
3946 | k = norm_ownadmin_permissions_posix(pxdesc, |
3947 | 0, pxdesc->acccnt, 0); |
3948 | pxdesc->acccnt = k; |
3949 | l = norm_ownadmin_permissions_posix(pxdesc, |
3950 | pxdesc->firstdef, pxdesc->defcnt, k); |
3951 | pxdesc->firstdef = k; |
3952 | pxdesc->defcnt = l; |
3953 | } else { |
3954 | k = norm_std_permissions_posix(pxdesc,groupowns, |
3955 | 0, pxdesc->acccnt, 0); |
3956 | pxdesc->acccnt = k; |
3957 | l = norm_std_permissions_posix(pxdesc,groupowns, |
3958 | pxdesc->firstdef, pxdesc->defcnt, k); |
3959 | pxdesc->firstdef = k; |
3960 | pxdesc->defcnt = l; |
3961 | } |
3962 | } |
3963 | if (pxdesc && !ntfs_valid_posix(pxdesc)) { |
3964 | ntfs_log_error("Invalid Posix descriptor built\n"); |
3965 | errno = EIO; |
3966 | free(pxdesc); |
3967 | pxdesc = (struct POSIX_SECURITY*)NULL; |
3968 | } |
3969 | return (pxdesc); |
3970 | } |
3971 | |
3972 | #endif /* POSIXACLS */ |
3973 | |
3974 | /* |
3975 | * Build unix-style (mode_t) permissions from an ACL |
3976 | * returns the requested permissions |
3977 | * or a negative result (with errno set) if there is a problem |
3978 | */ |
3979 | |
3980 | int ntfs_build_permissions(const char *securattr, |
3981 | const SID *usid, const SID *gsid, BOOL isdir) |
3982 | { |
3983 | int perm; |
3984 | BOOL adminowns; |
3985 | BOOL groupowns; |
3986 | |
3987 | adminowns = ntfs_same_sid(usid,adminsid) |
3988 | || ntfs_same_sid(gsid,adminsid); |
3989 | groupowns = !adminowns && ntfs_same_sid(gsid,usid); |
3990 | if (adminowns) |
3991 | perm = build_ownadmin_permissions(securattr, usid, gsid, isdir); |
3992 | else |
3993 | if (groupowns) |
3994 | perm = build_owngrp_permissions(securattr, usid, isdir); |
3995 | else |
3996 | perm = build_std_permissions(securattr, usid, gsid, isdir); |
3997 | return (perm); |
3998 | } |
3999 | |
4000 | /* |
4001 | * The following must be in some library... |
4002 | */ |
4003 | |
4004 | static unsigned long atoul(const char *p) |
4005 | { /* must be somewhere ! */ |
4006 | unsigned long v; |
4007 | |
4008 | v = 0; |
4009 | while ((*p >= '0') && (*p <= '9')) |
4010 | v = v * 10 + (*p++) - '0'; |
4011 | return (v); |
4012 | } |
4013 | |
4014 | /* |
4015 | * Build an internal representation of a SID |
4016 | * Returns a copy in allocated memory if it succeeds |
4017 | * The SID is checked to be a valid user one. |
4018 | */ |
4019 | |
4020 | static SID *encodesid(const char *sidstr) |
4021 | { |
4022 | SID *sid; |
4023 | int cnt; |
4024 | BIGSID bigsid; |
4025 | SID *bsid; |
4026 | u32 auth; |
4027 | const char *p; |
4028 | |
4029 | sid = (SID*) NULL; |
4030 | if (!strncmp(sidstr, "S-1-", 4)) { |
4031 | bsid = (SID*)&bigsid; |
4032 | bsid->revision = SID_REVISION; |
4033 | p = &sidstr[4]; |
4034 | auth = atoul(p); |
4035 | bsid->identifier_authority.high_part = const_cpu_to_be16(0); |
4036 | bsid->identifier_authority.low_part = cpu_to_be32(auth); |
4037 | cnt = 0; |
4038 | p = strchr(p, '-'); |
4039 | while (p && (cnt < 8)) { |
4040 | p++; |
4041 | auth = atoul(p); |
4042 | bsid->sub_authority[cnt] = cpu_to_le32(auth); |
4043 | p = strchr(p, '-'); |
4044 | cnt++; |
4045 | } |
4046 | bsid->sub_authority_count = cnt; |
4047 | if ((cnt > 0) && ntfs_valid_sid(bsid) && ntfs_is_user_sid(bsid)) { |
4048 | sid = (SID*) ntfs_malloc(4 * cnt + 8); |
4049 | if (sid) |
4050 | memcpy(sid, bsid, 4 * cnt + 8); |
4051 | } |
4052 | } |
4053 | return (sid); |
4054 | } |
4055 | |
4056 | /* |
4057 | * Get a single mapping item from buffer |
4058 | * |
4059 | * Always reads a full line, truncating long lines |
4060 | * Refills buffer when exhausted |
4061 | * Returns pointer to item, or NULL when there is no more |
4062 | */ |
4063 | |
4064 | static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid, |
4065 | off_t *poffs, char *buf, int *psrc, s64 *psize) |
4066 | { |
4067 | int src; |
4068 | int dst; |
4069 | char *q; |
4070 | char *pu; |
4071 | char *pg; |
4072 | int gotend; |
4073 | struct MAPLIST *item; |
4074 | |
4075 | src = *psrc; |
4076 | dst = 0; |
4077 | /* allocate and get a full line */ |
4078 | item = (struct MAPLIST*)ntfs_malloc(sizeof(struct MAPLIST)); |
4079 | if (item) { |
4080 | do { |
4081 | gotend = 0; |
4082 | while ((src < *psize) |
4083 | && (buf[src] != '\n')) { |
4084 | if (dst < LINESZ) |
4085 | item->maptext[dst++] = buf[src]; |
4086 | src++; |
4087 | } |
4088 | if (src >= *psize) { |
4089 | *poffs += *psize; |
4090 | *psize = reader(fileid, buf, (size_t)BUFSZ, *poffs); |
4091 | src = 0; |
4092 | } else { |
4093 | gotend = 1; |
4094 | src++; |
4095 | item->maptext[dst] = '\0'; |
4096 | dst = 0; |
4097 | } |
4098 | } while (*psize && ((item->maptext[0] == '#') || !gotend)); |
4099 | if (gotend) { |
4100 | pu = pg = (char*)NULL; |
4101 | /* decompose into uid, gid and sid */ |
4102 | item->uidstr = item->maptext; |
4103 | item->gidstr = strchr(item->uidstr, ':'); |
4104 | if (item->gidstr) { |
4105 | pu = item->gidstr++; |
4106 | item->sidstr = strchr(item->gidstr, ':'); |
4107 | if (item->sidstr) { |
4108 | pg = item->sidstr++; |
4109 | q = strchr(item->sidstr, ':'); |
4110 | if (q) *q = 0; |
4111 | } |
4112 | } |
4113 | if (pu && pg) |
4114 | *pu = *pg = '\0'; |
4115 | else { |
4116 | ntfs_log_early_error("Bad mapping item \"%s\"\n", |
4117 | item->maptext); |
4118 | free(item); |
4119 | item = (struct MAPLIST*)NULL; |
4120 | } |
4121 | } else { |
4122 | free(item); /* free unused item */ |
4123 | item = (struct MAPLIST*)NULL; |
4124 | } |
4125 | } |
4126 | *psrc = src; |
4127 | return (item); |
4128 | } |
4129 | |
4130 | /* |
4131 | * Read user mapping file and split into their attribute. |
4132 | * Parameters are kept as text in a chained list until logins |
4133 | * are converted to uid. |
4134 | * Returns the head of list, if any |
4135 | * |
4136 | * If an absolute path is provided, the mapping file is assumed |
4137 | * to be located in another mounted file system, and plain read() |
4138 | * are used to get its contents. |
4139 | * If a relative path is provided, the mapping file is assumed |
4140 | * to be located on the current file system, and internal IO |
4141 | * have to be used since we are still mounting and we have not |
4142 | * entered the fuse loop yet. |
4143 | */ |
4144 | |
4145 | struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid) |
4146 | { |
4147 | char buf[BUFSZ]; |
4148 | struct MAPLIST *item; |
4149 | struct MAPLIST *firstitem; |
4150 | struct MAPLIST *lastitem; |
4151 | int src; |
4152 | off_t offs; |
4153 | s64 size; |
4154 | |
4155 | firstitem = (struct MAPLIST*)NULL; |
4156 | lastitem = (struct MAPLIST*)NULL; |
4157 | offs = 0; |
4158 | size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0); |
4159 | if (size > 0) { |
4160 | src = 0; |
4161 | do { |
4162 | item = getmappingitem(reader, fileid, &offs, |
4163 | buf, &src, &size); |
4164 | if (item) { |
4165 | item->next = (struct MAPLIST*)NULL; |
4166 | if (lastitem) |
4167 | lastitem->next = item; |
4168 | else |
4169 | firstitem = item; |
4170 | lastitem = item; |
4171 | } |
4172 | } while (item); |
4173 | } |
4174 | return (firstitem); |
4175 | } |
4176 | |
4177 | /* |
4178 | * Free memory used to store the user mapping |
4179 | * The only purpose is to facilitate the detection of memory leaks |
4180 | */ |
4181 | |
4182 | void ntfs_free_mapping(struct MAPPING *mapping[]) |
4183 | { |
4184 | struct MAPPING *user; |
4185 | struct MAPPING *group; |
4186 | |
4187 | /* free user mappings */ |
4188 | while (mapping[MAPUSERS]) { |
4189 | user = mapping[MAPUSERS]; |
4190 | /* do not free SIDs used for group mappings */ |
4191 | group = mapping[MAPGROUPS]; |
4192 | while (group && (group->sid != user->sid)) |
4193 | group = group->next; |
4194 | if (!group) |
4195 | free(user->sid); |
4196 | /* free group list if any */ |
4197 | if (user->grcnt) |
4198 | free(user->groups); |
4199 | /* unchain item and free */ |
4200 | mapping[MAPUSERS] = user->next; |
4201 | free(user); |
4202 | } |
4203 | /* free group mappings */ |
4204 | while (mapping[MAPGROUPS]) { |
4205 | group = mapping[MAPGROUPS]; |
4206 | free(group->sid); |
4207 | /* unchain item and free */ |
4208 | mapping[MAPGROUPS] = group->next; |
4209 | free(group); |
4210 | } |
4211 | } |
4212 | |
4213 | |
4214 | /* |
4215 | * Build the user mapping list |
4216 | * user identification may be given in symbolic or numeric format |
4217 | * |
4218 | * ! Note ! : does getpwnam() read /etc/passwd or some other file ? |
4219 | * if so there is a possible recursion into fuse if this |
4220 | * file is on NTFS, and fuse is not recursion safe. |
4221 | */ |
4222 | |
4223 | struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem) |
4224 | { |
4225 | struct MAPLIST *item; |
4226 | struct MAPPING *firstmapping; |
4227 | struct MAPPING *lastmapping; |
4228 | struct MAPPING *mapping; |
4229 | struct passwd *pwd; |
4230 | SID *sid; |
4231 | int uid; |
4232 | |
4233 | firstmapping = (struct MAPPING*)NULL; |
4234 | lastmapping = (struct MAPPING*)NULL; |
4235 | for (item = firstitem; item; item = item->next) { |
4236 | if ((item->uidstr[0] >= '0') && (item->uidstr[0] <= '9')) |
4237 | uid = atoi(item->uidstr); |
4238 | else { |
4239 | uid = 0; |
4240 | if (item->uidstr[0]) { |
4241 | pwd = getpwnam(item->uidstr); |
4242 | if (pwd) |
4243 | uid = pwd->pw_uid; |
4244 | else |
4245 | ntfs_log_early_error("Invalid user \"%s\"\n", |
4246 | item->uidstr); |
4247 | } |
4248 | } |
4249 | /* |
4250 | * Records with no uid and no gid are inserted |
4251 | * to define the implicit mapping pattern |
4252 | */ |
4253 | if (uid |
4254 | || (!item->uidstr[0] && !item->gidstr[0])) { |
4255 | sid = encodesid(item->sidstr); |
4256 | if (sid && !item->uidstr[0] && !item->gidstr[0] |
4257 | && !ntfs_valid_pattern(sid)) { |
4258 | ntfs_log_error("Bad implicit SID pattern %s\n", |
4259 | item->sidstr); |
4260 | sid = (SID*)NULL; |
4261 | } |
4262 | if (sid) { |
4263 | mapping = |
4264 | (struct MAPPING*) |
4265 | ntfs_malloc(sizeof(struct MAPPING)); |
4266 | if (mapping) { |
4267 | mapping->sid = sid; |
4268 | mapping->xid = uid; |
4269 | mapping->grcnt = 0; |
4270 | mapping->next = (struct MAPPING*)NULL; |
4271 | if (lastmapping) |
4272 | lastmapping->next = mapping; |
4273 | else |
4274 | firstmapping = mapping; |
4275 | lastmapping = mapping; |
4276 | } |
4277 | } |
4278 | } |
4279 | } |
4280 | return (firstmapping); |
4281 | } |
4282 | |
4283 | /* |
4284 | * Build the group mapping list |
4285 | * group identification may be given in symbolic or numeric format |
4286 | * |
4287 | * gid not associated to a uid are processed first in order |
4288 | * to favour real groups |
4289 | * |
4290 | * ! Note ! : does getgrnam() read /etc/group or some other file ? |
4291 | * if so there is a possible recursion into fuse if this |
4292 | * file is on NTFS, and fuse is not recursion safe. |
4293 | */ |
4294 | |
4295 | struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem) |
4296 | { |
4297 | struct MAPLIST *item; |
4298 | struct MAPPING *firstmapping; |
4299 | struct MAPPING *lastmapping; |
4300 | struct MAPPING *mapping; |
4301 | struct group *grp; |
4302 | BOOL secondstep; |
4303 | BOOL ok; |
4304 | int step; |
4305 | SID *sid; |
4306 | int gid; |
4307 | |
4308 | firstmapping = (struct MAPPING*)NULL; |
4309 | lastmapping = (struct MAPPING*)NULL; |
4310 | for (step=1; step<=2; step++) { |
4311 | for (item = firstitem; item; item = item->next) { |
4312 | secondstep = (item->uidstr[0] != '\0') |
4313 | || !item->gidstr[0]; |
4314 | ok = (step == 1 ? !secondstep : secondstep); |
4315 | if ((item->gidstr[0] >= '0') |
4316 | && (item->gidstr[0] <= '9')) |
4317 | gid = atoi(item->gidstr); |
4318 | else { |
4319 | gid = 0; |
4320 | if (item->gidstr[0]) { |
4321 | grp = getgrnam(item->gidstr); |
4322 | if (grp) |
4323 | gid = grp->gr_gid; |
4324 | else |
4325 | ntfs_log_early_error("Invalid group \"%s\"\n", |
4326 | item->gidstr); |
4327 | } |
4328 | } |
4329 | /* |
4330 | * Records with no uid and no gid are inserted in the |
4331 | * second step to define the implicit mapping pattern |
4332 | */ |
4333 | if (ok |
4334 | && (gid |
4335 | || (!item->uidstr[0] && !item->gidstr[0]))) { |
4336 | sid = encodesid(item->sidstr); |
4337 | if (sid && !item->uidstr[0] && !item->gidstr[0] |
4338 | && !ntfs_valid_pattern(sid)) { |
4339 | /* error already logged */ |
4340 | sid = (SID*)NULL; |
4341 | } |
4342 | if (sid) { |
4343 | mapping = (struct MAPPING*) |
4344 | ntfs_malloc(sizeof(struct MAPPING)); |
4345 | if (mapping) { |
4346 | mapping->sid = sid; |
4347 | mapping->xid = gid; |
4348 | mapping->grcnt = 0; |
4349 | mapping->next = (struct MAPPING*)NULL; |
4350 | if (lastmapping) |
4351 | lastmapping->next = mapping; |
4352 | else |
4353 | firstmapping = mapping; |
4354 | lastmapping = mapping; |
4355 | } |
4356 | } |
4357 | } |
4358 | } |
4359 | } |
4360 | return (firstmapping); |
4361 | } |
4362 |