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