blob: 3e098d57cf6773ec8307f8687363455dcc4cd5f1
1 | /* |
2 | * Display and audit security attributes in an NTFS volume |
3 | * |
4 | * Copyright (c) 2007-2010 Jean-Pierre Andre |
5 | * |
6 | * Options : |
7 | * -a auditing security data |
8 | * -b backing up NTFS ACLs |
9 | * -e set extra backed-up parameters (in conjunction with -s) |
10 | * -h displaying hexadecimal security descriptors within a file |
11 | * -r recursing in a directory |
12 | * -s setting backed-up NTFS ACLs |
13 | * -v verbose (very verbose if set twice) |
14 | * also, if compile-time option is set |
15 | * -t run internal tests (with no access to storage) |
16 | * |
17 | * On Linux (being root, with volume not mounted) : |
18 | * secaudit -h [file] |
19 | * display the security descriptors found in file |
20 | * secaudit -a[rv] volume |
21 | * audit the volume |
22 | * secaudit [-v] volume file |
23 | * display the security parameters of file |
24 | * secaudit -r[v] volume directory |
25 | * display the security parameters of files in directory |
26 | * secaudit -b[v] volume [directory] |
27 | * backup the security parameters of files in directory |
28 | * secaudit -s[ve] volume [backupfile] |
29 | * set the security parameters as indicated in backup |
30 | * with -e set extra parameters (Windows attrib) |
31 | * secaudit volume perms file |
32 | * set the security parameters of file to perms (mode or acl) |
33 | * secaudit -r[v] volume perms directory |
34 | * set the security parameters of files in directory to perms |
35 | * special case, does not require being root : |
36 | * secaudit [-v] mounted-file |
37 | * display the security parameters of mounted file |
38 | * |
39 | * |
40 | * On Windows (the volume being part of file name) |
41 | * secaudit -h [file] |
42 | * display the security descriptors found in file |
43 | * secaudit [-v] file |
44 | * display the security parameters of file |
45 | * secaudit -r[v] directory |
46 | * display the security parameters of files in directory |
47 | * secaudit -b[v] directory |
48 | * backup the security parameters of files in directory |
49 | * secaudit -s[v] [backupfile] |
50 | * set the security parameters as indicated in backup |
51 | * with -e set extra parameters (Windows attrib) |
52 | * secaudit perms file |
53 | * set the security parameters of file to perms (mode or acl) |
54 | * secaudit -r[v] perms directory |
55 | * set the security parameters of files in directory to perms |
56 | */ |
57 | |
58 | /* History |
59 | * |
60 | * Nov 2007 |
61 | * - first version, by concatenating miscellaneous utilities |
62 | * |
63 | * Jan 2008, version 1.0.1 |
64 | * - fixed mode displaying |
65 | * - added a global severe errors count |
66 | * |
67 | * Feb 2008, version 1.0.2 |
68 | * - implemented conversions for big-endian machines |
69 | * |
70 | * Mar 2008, version 1.0.3 |
71 | * - avoided consistency checks on $Secure when there is no such file |
72 | * |
73 | * Mar 2008, version 1.0.4 |
74 | * - changed ordering of ACE's |
75 | * - changed representation for special flags |
76 | * - defaulted to stdin for option -h |
77 | * - added self tests (compile time option) |
78 | * - fixed errors specific to big-endian computers |
79 | * |
80 | * Apr 2008, version 1.1.0 |
81 | * - developped Posix ACLs to NTFS ACLs conversions |
82 | * - developped NTFS ACLs backup and restore |
83 | * |
84 | * Apr 2008, version 1.1.1 |
85 | * - fixed an error specific to big-endian computers |
86 | * - checked hash value and fixed error report in restore |
87 | * - improved display in showhex() and restore() |
88 | * |
89 | * Apr 2008, version 1.1.2 |
90 | * - improved and fixed Posix ACLs to NTFS ACLs conversions |
91 | * |
92 | * Apr 2008, version 1.1.3 |
93 | * - reenabled recursion for setting a new mode or ACL |
94 | * - processed Unicode file names and displayed them as UTF-8 |
95 | * - allocated dynamically memory for file names when recursing |
96 | * |
97 | * May 2008, version 1.1.4 |
98 | * - all Unicode/UTF-8 strings checked and processed |
99 | * |
100 | * Jul 2008, version 1.1.5 |
101 | * - made Windows owner consistent with Linux owner when changing mode |
102 | * - allowed owner change on Windows when it does not match Linux owner |
103 | * - skipped currently unused code |
104 | * |
105 | * Aug 2008, version 1.2.0 |
106 | * - processed \.NTFS-3G\UserMapping on Windows |
107 | * - made use of user mappings through the security API or direct access |
108 | * - fixed a bug in restore |
109 | * - fixed UTF-8 conversions |
110 | * |
111 | * Sep 2008, version 1.3.0 |
112 | * - split the code to have part of it shared with ntfs-3g library |
113 | * - fixed testing for end of SDS block |
114 | * - added samples checking in selftest for easier debugging |
115 | * |
116 | * Oct 2008, version 1.3.1 |
117 | * - fixed outputting long long data when testing on a Palm organizer |
118 | * |
119 | * Dec 2008, version 1.3.2 |
120 | * - fixed restoring ACLs |
121 | * - added optional logging of ACL hashes to facilitate restore checks |
122 | * - fixed collecting SACLs |
123 | * - fixed setting special control flags |
124 | * - fixed clearing existing SACLs (Linux only) and DACLs |
125 | * - changed the sequencing of items when quering a security descriptor |
126 | * - avoided recursing on junctions and symlinks on Windows |
127 | * |
128 | * Jan 2009, version 1.3.3 |
129 | * - save/restore Windows attributes (code from Faisal) |
130 | * |
131 | * Mar 2009, version 1.3.4 |
132 | * - enabled displaying attributes of a mounted file over Linux |
133 | * |
134 | * Apr 2009, version 1.3.5 |
135 | * - fixed initialisation of stand-alone user mapping |
136 | * - fixed POSIXACL redefinition when included in the ntfs-3g package |
137 | * - fixed displaying of options |
138 | * - fixed a dependency on the shared library version used |
139 | * |
140 | * May 2009, version 1.3.6 |
141 | * - added new samples for self testing |
142 | * |
143 | * Jun 2009, version 1.3.7 |
144 | * - fixed displaying owner and group of a mounted file over Linux |
145 | * |
146 | * Jul 2009, version 1.3.8 |
147 | * - fixed again displaying owner and group of a mounted file over Linux |
148 | * - cleaned some code to avoid warnings |
149 | * |
150 | * Nov 2009, version 1.3.9 |
151 | * - allowed security descriptors up to 64K |
152 | * |
153 | * Nov 2009, version 1.3.10 |
154 | * - applied patches for MacOSX from Erik Larsson |
155 | * |
156 | * Nov 2009, version 1.3.11 |
157 | * - replace <attr/xattr.h> by <sys/xattr.h> (provided by glibc) |
158 | * |
159 | * Dec 2009, version 1.3.12 |
160 | * - worked around "const" possibly redefined in config.h |
161 | * |
162 | * Dec 2009, version 1.3.13 |
163 | * - fixed the return code of dorestore() |
164 | * |
165 | * Dec 2009, version 1.3.14 |
166 | * - adapted to opensolaris |
167 | * |
168 | * Jan 2010, version 1.3.15 |
169 | * - more adaptations to opensolaris |
170 | * - removed the fix for return code of dorestore() |
171 | * |
172 | * Jan 2010, version 1.3.16 |
173 | * - repeated the fix for return code of dorestore() |
174 | * |
175 | * Mar 2010, version 1.3.17 |
176 | * - fixed #ifdef'd code for selftest |
177 | */ |
178 | |
179 | /* |
180 | * This program is free software; you can redistribute it and/or modify |
181 | * it under the terms of the GNU General Public License as published by |
182 | * the Free Software Foundation; either version 2 of the License, or |
183 | * (at your option) any later version. |
184 | * |
185 | * This program is distributed in the hope that it will be useful, |
186 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
187 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
188 | * GNU General Public License for more details. |
189 | * |
190 | * You should have received a copy of the GNU General Public License |
191 | * along with this program (in the main directory of the NTFS-3G |
192 | * distribution in the file COPYING); if not, write to the Free Software |
193 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
194 | */ |
195 | |
196 | /* |
197 | * General parameters which may have to be adapted to needs |
198 | */ |
199 | |
200 | #define AUDT_VERSION "1.3.17" |
201 | |
202 | #define GET_FILE_SECURITY "ntfs_get_file_security" |
203 | #define SET_FILE_SECURITY "ntfs_set_file_security" |
204 | #define GET_FILE_ATTRIBUTES "ntfs_get_file_attributes" |
205 | #define SET_FILE_ATTRIBUTES "ntfs_set_file_attributes" |
206 | #define READ_DIRECTORY "ntfs_read_directory" |
207 | #define READ_SDS "ntfs_read_sds" |
208 | #define READ_SII "ntfs_read_sii" |
209 | #define READ_SDH "ntfs_read_sdh" |
210 | #define GET_USER "ntfs_get_user" |
211 | #define GET_GROUP "ntfs_get_group" |
212 | #define GET_USID "ntfs_get_usid" |
213 | #define GET_GSID "ntfs_get_gsid" |
214 | #define INIT_FILE_SECURITY "ntfs_initialize_file_security" |
215 | #define LEAVE_FILE_SECURITY "ntfs_leave_file_security" |
216 | |
217 | /* |
218 | * External declarations |
219 | */ |
220 | |
221 | #include <stdio.h> |
222 | #include <time.h> |
223 | #include <string.h> |
224 | #include <stdlib.h> |
225 | #ifdef HAVE_SYS_TYPES_H |
226 | #include <sys/types.h> |
227 | #endif |
228 | |
229 | #include <fcntl.h> |
230 | #include <errno.h> |
231 | #include <stdarg.h> |
232 | |
233 | /* |
234 | * integration into secaudit, check whether Win32, |
235 | * may have to be adapted to compiler or something else |
236 | */ |
237 | |
238 | #ifndef WIN32 |
239 | #if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) |
240 | #define WIN32 1 |
241 | #endif |
242 | #endif |
243 | |
244 | /* |
245 | * integration into secaudit/Win32 |
246 | */ |
247 | #ifdef WIN32 |
248 | #include <windows.h> |
249 | #define __LITTLE_ENDIAN 1234 |
250 | #define __BYTE_ORDER __LITTLE_ENDIAN |
251 | #else |
252 | /* |
253 | * integration into secaudit/STSC |
254 | */ |
255 | #ifdef STSC |
256 | #include <stat.h> |
257 | #undef __BYTE_ORDER |
258 | #define __BYTE_ORDER __BIG_ENDIAN |
259 | #else |
260 | /* |
261 | * integration into secaudit/Linux |
262 | */ |
263 | |
264 | #include <sys/stat.h> |
265 | #ifdef HAVE_ENDIAN_H |
266 | #include <endian.h> |
267 | #endif |
268 | #ifdef HAVE_MACHINE_ENDIAN_H |
269 | #include <machine/endian.h> |
270 | #endif |
271 | #include <unistd.h> |
272 | #include <dlfcn.h> |
273 | #endif /* STSC */ |
274 | #endif /* WIN32 */ |
275 | #include "secaudit.h" |
276 | |
277 | #ifndef WIN32 |
278 | |
279 | #ifndef STSC |
280 | |
281 | #if !defined(HAVE_CONFIG_H) && POSIXACLS |
282 | /* require <sys/xattr.h> if not integrated into ntfs-3g package */ |
283 | #define HAVE_SETXATTR 1 |
284 | #endif |
285 | |
286 | #ifdef HAVE_CONFIG_H |
287 | #ifdef _FILE_OFFSET_BITS |
288 | #undef _FILE_OFFSET_BITS /* work around "_FILE_OFFSET_BITS" possibly already defined */ |
289 | #endif |
290 | /* <sys/xattr.h> according to config.h if integrated into ntfs-3g package */ |
291 | #include "config.h" |
292 | #ifdef const /* work around "const" possibly redefined in config.h */ |
293 | #undef const |
294 | #endif |
295 | #ifndef POSIXACLS |
296 | #define POSIXACLS 0 |
297 | #endif |
298 | #endif /* HAVE_CONFIG_H */ |
299 | |
300 | #ifdef HAVE_SETXATTR |
301 | #include <sys/xattr.h> |
302 | #else |
303 | #warning "The extended attribute package is not available" |
304 | #endif /* HAVE_SETXATTR */ |
305 | |
306 | #endif /* STSC */ |
307 | |
308 | #define MS_NONE 0 /* no flag for mounting the device */ |
309 | #define MS_RDONLY 1 /* flag for mounting the device read-only */ |
310 | |
311 | struct CALLBACK; |
312 | |
313 | typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, |
314 | int length, int type, long long pos, u64 mft_ref, |
315 | unsigned int dt_type); |
316 | |
317 | #if USESTUBS | defined(STSC) |
318 | |
319 | int ntfs_get_file_security(void *scapi, |
320 | const char *path, DWORD selection, |
321 | char *buf, DWORD buflen, LPDWORD psize); |
322 | BOOL ntfs_set_file_security(void *scapi, |
323 | const char *path, DWORD selection, const char *attr); |
324 | int ntfs_get_file_attributes(void *scapi, |
325 | const char *path); |
326 | BOOL ntfs_set_file_attributes(void *scapi, |
327 | const char *path, DWORD attrib); |
328 | BOOL ntfs_read_directory(void *scapi, |
329 | const char *path, dircallback callback, void *context); |
330 | int ntfs_read_sds(void *scapi, |
331 | char *buf, DWORD buflen, DWORD offset); |
332 | void *ntfs_read_sii(void *scapi, void *entry); |
333 | void *ntfs_read_sdh(void *scapi, void *entry); |
334 | |
335 | int ntfs_get_usid(void *scapi, uid_t uid, char *buf); |
336 | int ntfs_get_gsid(void *scapi, gid_t gid, char *buf); |
337 | int ntfs_get_user(void *scapi, const char *usid); |
338 | int ntfs_get_group(void *scapi, const char *gsid); |
339 | |
340 | void *ntfs_initialize_file_security(const char *device, int flags); |
341 | BOOL ntfs_leave_file_security(void *scapi); |
342 | |
343 | #else |
344 | |
345 | typedef int (*type_get_file_security)(void *scapi, |
346 | const char *path, DWORD selection, |
347 | char *buf, DWORD buflen, LPDWORD psize); |
348 | typedef BOOL (*type_set_file_security)(void *scapi, |
349 | const char *path, DWORD selection, const char *attr); |
350 | typedef int (*type_get_file_attributes)(void *scapi, |
351 | const char *path); |
352 | typedef BOOL (*type_set_file_attributes)(void *scapi, |
353 | const char *path, DWORD attrib); |
354 | typedef BOOL (*type_read_directory)(void *scapi, |
355 | const char *path, dircallback callback, void *context); |
356 | typedef int (*type_read_sds)(void *scapi, |
357 | char *buf, DWORD buflen, DWORD offset); |
358 | typedef void *(*type_read_sii)(void *scapi, void *entry); |
359 | typedef void *(*type_read_sdh)(void *scapi, void *entry); |
360 | |
361 | typedef int (*type_get_usid)(void *scapi, uid_t uid, char *buf); |
362 | typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf); |
363 | typedef int (*type_get_user)(void *scapi, const char *usid); |
364 | typedef int (*type_get_group)(void *scapi, const char *gsid); |
365 | |
366 | typedef void *(*type_initialize_file_security)(const char *device, int flags); |
367 | typedef BOOL (*type_leave_file_security)(void *scapi); |
368 | |
369 | type_get_file_security ntfs_get_file_security; |
370 | type_set_file_security ntfs_set_file_security; |
371 | type_get_file_attributes ntfs_get_file_attributes; |
372 | type_set_file_attributes ntfs_set_file_attributes; |
373 | type_read_directory ntfs_read_directory; |
374 | type_read_sds ntfs_read_sds; |
375 | type_read_sii ntfs_read_sii; |
376 | type_read_sdh ntfs_read_sdh; |
377 | |
378 | type_get_usid ntfs_get_usid; |
379 | type_get_gsid ntfs_get_gsid; |
380 | type_get_user ntfs_get_user; |
381 | type_get_group ntfs_get_group; |
382 | |
383 | type_initialize_file_security ntfs_initialize_file_security; |
384 | type_leave_file_security ntfs_leave_file_security; |
385 | |
386 | |
387 | #endif /* USESTUBS | defined(STSC) */ |
388 | #endif /* WIN32 */ |
389 | |
390 | /* |
391 | * Prototypes for local functions |
392 | */ |
393 | |
394 | BOOL open_security_api(void); |
395 | BOOL close_security_api(void); |
396 | #ifndef WIN32 |
397 | BOOL open_volume(const char*, int flags); |
398 | BOOL close_volume(const char*); |
399 | #endif |
400 | unsigned int get2l(const char*, int); |
401 | unsigned long get4l(const char*, int); |
402 | u64 get6l(const char*, int); |
403 | u64 get6h(const char*, int); |
404 | u64 get8l(const char*, int); |
405 | void set2l(char*, unsigned int); |
406 | void set4l(char*, unsigned long); |
407 | void hexdump(const char*, int, int); |
408 | u32 hash(const le32*, int); |
409 | unsigned int utf8size(const char*, int); |
410 | unsigned int makeutf8(char*, const char*, int); |
411 | unsigned int utf16size(const char*); |
412 | unsigned int makeutf16(char*, const char*); |
413 | unsigned int utf16len(const char*); |
414 | void printname(FILE*, const char*); |
415 | void printerror(FILE*); |
416 | BOOL guess_dir(const char*); |
417 | void showsid(const char*, int, int); |
418 | void showusid(const char*, int); |
419 | void showgsid(const char*, int); |
420 | void showheader(const char*, int); |
421 | void showace(const char*, int, int, int); |
422 | void showacl(const char*, int, int, int); |
423 | void showdacl(const char*, int, int); |
424 | void showsacl(const char*, int, int); |
425 | void showall(const char*, int); |
426 | void showposix(const struct POSIX_SECURITY*); |
427 | int linux_permissions(const char*, BOOL); |
428 | uid_t linux_owner(const char*); |
429 | gid_t linux_group(const char*); |
430 | int basicread(void*, char*, size_t, off_t); |
431 | int dummyread(void*, char*, size_t, off_t); |
432 | int local_build_mapping(struct MAPPING *[], const char*); |
433 | void newblock(s32); |
434 | void freeblocks(void); |
435 | u32 getmsbhex(const char*); |
436 | u32 getlsbhex(const char*); |
437 | BOOL ishexdump(const char*, int, int); |
438 | void showhex(FILE*); |
439 | void showfull(const char*, BOOL); |
440 | BOOL applyattr(const char*, const char*, BOOL, int, s32); |
441 | BOOL restore(FILE*); |
442 | BOOL dorestore(const char*, FILE*); |
443 | u32 merge_rights(const struct POSIX_SECURITY*, BOOL); |
444 | void tryposix(struct POSIX_SECURITY*); |
445 | void check_samples(void); |
446 | void basictest(int, BOOL, const SID*, const SID*); |
447 | void posixtest(int, BOOL, const SID*, const SID*); |
448 | void selftests(void); |
449 | unsigned int getfull(char*, const char*); |
450 | BOOL updatefull(const char *name, DWORD flags, char *attr); |
451 | BOOL setfull(const char*, int, BOOL); |
452 | BOOL singleshow(const char*); |
453 | void showmounted(const char*); |
454 | BOOL recurseshow(const char*); |
455 | BOOL singleset(const char*, int); |
456 | BOOL recurseset(const char*, int); |
457 | #ifdef WIN32 |
458 | BOOL backup(const char*); |
459 | BOOL listfiles(const char*); |
460 | #if POSIXACLS |
461 | BOOL iterate(RECURSE, const char*, const struct POSIX_SECURITY*); |
462 | #else |
463 | BOOL iterate(RECURSE, const char*, mode_t); |
464 | #endif |
465 | #else |
466 | BOOL backup(const char*, const char*); |
467 | BOOL listfiles(const char*, const char*); |
468 | #endif |
469 | #if POSIXACLS |
470 | BOOL setfull_posix(const char *, const struct POSIX_SECURITY*, BOOL); |
471 | struct POSIX_SECURITY *linux_permissions_posix(const char*, BOOL); |
472 | BOOL recurseset_posix(const char*, const struct POSIX_SECURITY*); |
473 | BOOL singleset_posix(const char*, const struct POSIX_SECURITY*); |
474 | struct POSIX_SECURITY *encode_posix_acl(const char*); |
475 | #endif |
476 | static void stdfree(void*); |
477 | |
478 | BOOL valid_sds(const char*, unsigned int, unsigned int, |
479 | unsigned int, u32, BOOL); |
480 | BOOL valid_sii(const char*, u32); |
481 | BOOL valid_sdh(const char*, u32, u32); |
482 | int consist_sds(const char*, unsigned int, unsigned int, BOOL); |
483 | int consist_sii(const char*); |
484 | int consist_sdh(const char*); |
485 | int audit_sds(BOOL); |
486 | int audit_sii(void); |
487 | int audit_sdh(void); |
488 | void audit_summary(void); |
489 | BOOL audit(const char*); |
490 | int getoptions(int, char*[]); |
491 | |
492 | #ifndef WIN32 |
493 | |
494 | /* |
495 | * Structures for collecting directory contents (Linux only) |
496 | */ |
497 | |
498 | struct LINK { |
499 | struct LINK *next; |
500 | char name[1]; |
501 | } ; |
502 | |
503 | struct CALLBACK { |
504 | struct LINK *head; |
505 | const char *dir; |
506 | } ; |
507 | |
508 | int callback(struct CALLBACK *context, char *ntfsname, |
509 | int length, int type, long long pos, u64 mft_ref, |
510 | unsigned int dt_type); |
511 | #endif |
512 | |
513 | /* |
514 | * Global constants |
515 | */ |
516 | |
517 | #define BANNER "secaudit " AUDT_VERSION " : NTFS security data auditing" |
518 | |
519 | #if SELFTESTS & !USESTUBS |
520 | |
521 | /* |
522 | * Dummy mapping file (self tests only) |
523 | */ |
524 | |
525 | #define DUMMYAUTH "S-1-5-21-3141592653-589793238-462843383-" |
526 | char dummymapping[] = "500::" DUMMYAUTH "1000\n" |
527 | "501::" DUMMYAUTH "1001\n" |
528 | "502::" DUMMYAUTH "1002\n" |
529 | "503::" DUMMYAUTH "1003\n" |
530 | "516::" DUMMYAUTH "1016\n" |
531 | ":500:" DUMMYAUTH "513\r\n" |
532 | ":511:S-1-5-21-1607551490-981732888-1819828000-513\n" |
533 | ":516:" DUMMYAUTH "1012\r\n" |
534 | "::" DUMMYAUTH "10000\n"; |
535 | |
536 | /* |
537 | * SID for world (S-1-1-0) |
538 | */ |
539 | |
540 | static const char worldsidbytes[] = { |
541 | 1, /* revision */ |
542 | 1, /* auth count */ |
543 | 0, 0, 0, 0, 0, 1, /* base */ |
544 | 0, 0, 0, 0 /* 1st level */ |
545 | } ; |
546 | static const SID *worldsid = (const SID*)worldsidbytes; |
547 | |
548 | /* |
549 | * SID for administrator |
550 | */ |
551 | |
552 | static const char adminsidbytes[] = { |
553 | 1, /* revision */ |
554 | 2, /* auth count */ |
555 | 0, 0, 0, 0, 0, 5, /* base */ |
556 | 32, 0, 0, 0, /* 1st level */ |
557 | 32, 2, 0, 0 /* 2nd level */ |
558 | }; |
559 | |
560 | static const SID *adminsid = (const SID*)adminsidbytes; |
561 | |
562 | /* |
563 | * SID for system |
564 | */ |
565 | |
566 | static const char systemsidbytes[] = { |
567 | 1, /* revision */ |
568 | 1, /* auth count */ |
569 | 0, 0, 0, 0, 0, 5, /* base */ |
570 | 18, 0, 0, 0 /* 1st level */ |
571 | }; |
572 | |
573 | static const SID *systemsid = (const SID*)systemsidbytes; |
574 | |
575 | #endif |
576 | |
577 | /* |
578 | * Global variables |
579 | */ |
580 | |
581 | BOOL opt_a; /* audit security data */ |
582 | BOOL opt_b; /* backup NTFS ACLs */ |
583 | BOOL opt_e; /* restore extra (currently windows attribs) */ |
584 | BOOL opt_h; /* display an hexadecimal descriptor in a file */ |
585 | BOOL opt_r; /* recursively apply to subdirectories */ |
586 | BOOL opt_s; /* restore NTFS ACLs */ |
587 | #if SELFTESTS & !USESTUBS |
588 | BOOL opt_t; /* run self-tests */ |
589 | #endif |
590 | int opt_v; /* verbose or very verbose*/ |
591 | struct SECURITY_DATA *securdata[(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ)]; |
592 | #if FORCEMASK |
593 | BOOL opt_m; /* force a mask - dangerous */ |
594 | u32 forcemsk /* mask to force */ |
595 | #endif |
596 | unsigned int errors; /* number of severe errors */ |
597 | unsigned int warnings; /* number of non-severe errors */ |
598 | |
599 | struct CHKALLOC *firstalloc; |
600 | struct SECURITY_CONTEXT context; |
601 | MAPTYPE mappingtype; |
602 | |
603 | #ifdef STSC |
604 | #define static |
605 | #endif |
606 | |
607 | #ifndef WIN32 |
608 | |
609 | void *ntfs_handle; |
610 | void *ntfs_context = (void*)NULL; |
611 | |
612 | /* |
613 | * Open and close the security API (platform dependent) |
614 | */ |
615 | |
616 | BOOL open_security_api(void) |
617 | { |
618 | #if USESTUBS | defined(STSC) |
619 | return (TRUE); |
620 | #else |
621 | char *error; |
622 | BOOL err; |
623 | const char *libfile; |
624 | |
625 | err = TRUE; |
626 | libfile = getenv(ENVNTFS3G); |
627 | if (!libfile) |
628 | libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE); |
629 | ntfs_handle = dlopen(libfile,RTLD_LAZY); |
630 | if (ntfs_handle) { |
631 | ntfs_initialize_file_security = (type_initialize_file_security) |
632 | dlsym(ntfs_handle,INIT_FILE_SECURITY); |
633 | error = dlerror(); |
634 | if (error) |
635 | fprintf(stderr," %s\n",error); |
636 | else { |
637 | ntfs_leave_file_security = (type_leave_file_security) |
638 | dlsym(ntfs_handle,LEAVE_FILE_SECURITY); |
639 | ntfs_get_file_security = (type_get_file_security) |
640 | dlsym(ntfs_handle,GET_FILE_SECURITY); |
641 | ntfs_set_file_security = (type_set_file_security) |
642 | dlsym(ntfs_handle,SET_FILE_SECURITY); |
643 | ntfs_get_file_attributes = (type_get_file_attributes) |
644 | dlsym(ntfs_handle,GET_FILE_ATTRIBUTES); |
645 | ntfs_set_file_attributes = (type_set_file_attributes) |
646 | dlsym(ntfs_handle,SET_FILE_ATTRIBUTES); |
647 | ntfs_read_directory = (type_read_directory) |
648 | dlsym(ntfs_handle,READ_DIRECTORY); |
649 | ntfs_read_sds = (type_read_sds) |
650 | dlsym(ntfs_handle,READ_SDS); |
651 | ntfs_read_sii = (type_read_sii) |
652 | dlsym(ntfs_handle,READ_SII); |
653 | ntfs_read_sdh = (type_read_sdh) |
654 | dlsym(ntfs_handle,READ_SDH); |
655 | ntfs_get_user = (type_get_user) |
656 | dlsym(ntfs_handle,GET_USER); |
657 | ntfs_get_group = (type_get_group) |
658 | dlsym(ntfs_handle,GET_GROUP); |
659 | ntfs_get_usid = (type_get_usid) |
660 | dlsym(ntfs_handle,GET_USID); |
661 | ntfs_get_gsid = (type_get_gsid) |
662 | dlsym(ntfs_handle,GET_GSID); |
663 | err = !ntfs_initialize_file_security |
664 | || !ntfs_leave_file_security |
665 | || !ntfs_get_file_security |
666 | || !ntfs_set_file_security |
667 | || !ntfs_get_file_attributes |
668 | || !ntfs_set_file_attributes |
669 | || !ntfs_read_directory |
670 | || !ntfs_read_sds |
671 | || !ntfs_read_sii |
672 | || !ntfs_read_sdh |
673 | || !ntfs_get_user |
674 | || !ntfs_get_group |
675 | || !ntfs_get_usid |
676 | || !ntfs_get_gsid; |
677 | |
678 | if (error) |
679 | fprintf(stderr,"ntfs-3g API not available\n"); |
680 | } |
681 | } else { |
682 | fprintf(stderr,"Could not open ntfs-3g library\n"); |
683 | fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n"); |
684 | fprintf(stderr,"to appropriate path and retry\n"); |
685 | } |
686 | return (!err); |
687 | #endif /* USESTUBS | defined(STSC) */ |
688 | } |
689 | |
690 | BOOL close_security_api(void) |
691 | { |
692 | #if USESTUBS | defined(STSC) |
693 | return (0); |
694 | #else |
695 | return (!dlclose(ntfs_handle)); |
696 | #endif /* USESTUBS | defined(STSC) */ |
697 | } |
698 | |
699 | /* |
700 | * Open and close a volume (platform dependent) |
701 | * Assumes a single volume is opened |
702 | */ |
703 | |
704 | BOOL open_volume(const char *volume, int flags) |
705 | { |
706 | BOOL ok; |
707 | |
708 | ok = FALSE; |
709 | if (!ntfs_context) { |
710 | ntfs_context = (*ntfs_initialize_file_security)(volume,flags); |
711 | if (ntfs_context) { |
712 | if (*(u32*)ntfs_context != MAGIC_API) { |
713 | fprintf(stderr,"Versions of ntfs-3g and secaudit" |
714 | " are not compatible\n"); |
715 | } else { |
716 | fprintf(stderr,"\"%s\" opened\n",volume); |
717 | mappingtype = MAPEXTERN; |
718 | ok = TRUE; |
719 | } |
720 | } else { |
721 | fprintf(stderr,"Could not open \"%s\"\n",volume); |
722 | fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume); |
723 | } |
724 | } else |
725 | fprintf(stderr,"A volume is already open\n"); |
726 | return (ok); |
727 | } |
728 | |
729 | BOOL close_volume(const char *volume) |
730 | { |
731 | BOOL r; |
732 | |
733 | r = (*ntfs_leave_file_security)(ntfs_context); |
734 | if (r) |
735 | fprintf(stderr,"\"%s\" closed\n",volume); |
736 | else |
737 | fprintf(stderr,"Could not close \"%s\"\n",volume); |
738 | ntfs_context = (void*)NULL; |
739 | return (r); |
740 | } |
741 | |
742 | #endif /* WIN32 */ |
743 | |
744 | /* |
745 | * Extract small or big endian data from an array of bytes |
746 | */ |
747 | |
748 | unsigned int get2l(const char *attr, int p) |
749 | { |
750 | int i; |
751 | unsigned int v; |
752 | |
753 | v = 0; |
754 | for (i=0; i<2; i++) |
755 | v += (attr[p+i] & 255) << (8*i); |
756 | return (v); |
757 | } |
758 | |
759 | unsigned long get4l(const char *attr, int p) |
760 | { |
761 | int i; |
762 | unsigned long v; |
763 | |
764 | v = 0; |
765 | for (i=0; i<4; i++) |
766 | v += ((long)(attr[p+i] & 255)) << (8*i); |
767 | return (v); |
768 | } |
769 | |
770 | u64 get6l(const char *attr, int p) |
771 | { |
772 | int i; |
773 | u64 v; |
774 | |
775 | v = 0; |
776 | for (i=0; i<6; i++) |
777 | v += ((long long)(attr[p+i] & 255)) << (8*i); |
778 | return (v); |
779 | } |
780 | |
781 | u64 get6h(const char *attr, int p) |
782 | { |
783 | int i; |
784 | u64 v; |
785 | |
786 | v = 0; |
787 | for (i=0; i<6; i++) |
788 | v = (v << 8) + (attr[p+i] & 255); |
789 | return (v); |
790 | } |
791 | |
792 | u64 get8l(const char *attr, int p) |
793 | { |
794 | int i; |
795 | u64 v; |
796 | |
797 | v = 0; |
798 | for (i=0; i<8; i++) |
799 | v += ((long long)(attr[p+i] & 255)) << (8*i); |
800 | return (v); |
801 | } |
802 | |
803 | /* |
804 | * Set small or big endian data into an array of bytes |
805 | */ |
806 | |
807 | void set2l(char *p, unsigned int v) |
808 | { |
809 | int i; |
810 | |
811 | for (i=0; i<2; i++) |
812 | p[i] = ((v >> 8*i) & 255); |
813 | } |
814 | |
815 | void set4l(char *p, unsigned long v) |
816 | { |
817 | int i; |
818 | |
819 | for (i=0; i<4; i++) |
820 | p[i] = ((v >> 8*i) & 255); |
821 | } |
822 | |
823 | |
824 | /* |
825 | * hexadecimal dump of an array of bytes |
826 | */ |
827 | |
828 | void hexdump(const char *attr, int size, int level) |
829 | { |
830 | int i,j; |
831 | |
832 | for (i=0; i<size; i+=16) { |
833 | if (level) |
834 | printf("%*c",level,' '); |
835 | printf("%06x ",i); |
836 | for (j=i; (j<(i+16)) && (j<size); j++) |
837 | printf((j & 3 ? "%02x" : " %02x"),attr[j] & 255); |
838 | printf("\n"); |
839 | } |
840 | } |
841 | |
842 | u32 hash(const le32 *buf, int size /* bytes */) |
843 | { |
844 | u32 h; |
845 | int i; |
846 | |
847 | h = 0; |
848 | for (i=0; 4*i<size; i++) |
849 | h = le32_to_cpu(buf[i]) + (h << 3) + ((h >> 29) & 7); |
850 | return (h); |
851 | } |
852 | |
853 | /* |
854 | * Evaluate the size of UTS-8 conversion of a UTF-16LE text |
855 | * trailing '\0' not accounted for |
856 | * Returns 0 for invalid input |
857 | */ |
858 | |
859 | unsigned int utf8size(const char *utf16, int length) |
860 | { |
861 | int i; |
862 | unsigned int size; |
863 | enum { BASE, SURR, ERR } state; |
864 | |
865 | size = 0; |
866 | state = BASE; |
867 | for (i=0; i<2*length; i+=2) { |
868 | switch (state) { |
869 | case BASE : |
870 | if (utf16[i+1] & 0xf8) { |
871 | if ((utf16[i+1] & 0xf8) == 0xd8) |
872 | state = (utf16[i+1] & 4 ? ERR : SURR); |
873 | else |
874 | #if NOREVBOM |
875 | if (((utf16[i+1] & 0xff) == 0xff) |
876 | && ((utf16[i] & 0xfe) == 0xfe)) |
877 | state = ERR; |
878 | else |
879 | size += 3; |
880 | #else |
881 | size += 3; |
882 | #endif |
883 | } else |
884 | if ((utf16[i] & 0x80) || utf16[i+1]) |
885 | size += 2; |
886 | else |
887 | size++; |
888 | break; |
889 | case SURR : |
890 | if ((utf16[i+1] & 0xfc) == 0xdc) { |
891 | state = BASE; |
892 | size += 4; |
893 | } else |
894 | state = ERR; |
895 | break; |
896 | case ERR : |
897 | break; |
898 | } |
899 | } |
900 | if (state != BASE) |
901 | size = 0; |
902 | return (size); |
903 | } |
904 | |
905 | /* |
906 | * Convert a UTF-16LE text to UTF-8 |
907 | * Note : wcstombs() not used because on Linux it fails for characters |
908 | * not present in current locale |
909 | * Returns size or zero for invalid input |
910 | */ |
911 | |
912 | unsigned int makeutf8(char *utf8, const char *utf16, int length) |
913 | { |
914 | int i; |
915 | unsigned int size; |
916 | unsigned int rem; |
917 | enum { BASE, SURR, ERR } state; |
918 | |
919 | size = 0; |
920 | rem = 0; |
921 | state = BASE; |
922 | for (i=0; i<2*length; i+=2) { |
923 | switch (state) { |
924 | case BASE : |
925 | if (utf16[i+1] & 0xf8) { |
926 | if ((utf16[i+1] & 0xf8) == 0xd8) { |
927 | if (utf16[i+1] & 4) |
928 | state = ERR; |
929 | else { |
930 | utf8[size++] = 0xf0 + (utf16[i+1] & 7) |
931 | + ((utf16[i] & 0xc0) == 0xc0); |
932 | utf8[size++] = 0x80 + (((utf16[i] + 64) >> 2) & 63); |
933 | rem = utf16[i] & 3; |
934 | state = SURR; |
935 | } |
936 | } else { |
937 | #if NOREVBOM |
938 | if (((utf16[i+1] & 0xff) == 0xff) |
939 | && ((utf16[i] & 0xfe) == 0xfe)) |
940 | state = ERR; |
941 | else { |
942 | utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); |
943 | utf8[size++] = 0x80 |
944 | + ((utf16[i+1] & 15) << 2) |
945 | + ((utf16[i] >> 6) & 3); |
946 | utf8[size++] = 0x80 + (utf16[i] & 63); |
947 | } |
948 | #else |
949 | utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); |
950 | utf8[size++] = 0x80 |
951 | + ((utf16[i+1] & 15) << 2) |
952 | + ((utf16[i] >> 6) & 3); |
953 | utf8[size++] = 0x80 + (utf16[i] & 63); |
954 | #endif |
955 | } |
956 | } else |
957 | if ((utf16[i] & 0x80) || utf16[i+1]) { |
958 | utf8[size++] = 0xc0 |
959 | + ((utf16[i+1] & 15) << 2) |
960 | + ((utf16[i] >> 6) & 3); |
961 | utf8[size++] = 0x80 + (utf16[i] & 63); |
962 | } else |
963 | utf8[size++] = utf16[i]; |
964 | break; |
965 | case SURR : |
966 | if ((utf16[i+1] & 0xfc) == 0xdc) { |
967 | utf8[size++] = 0x80 + (rem << 4) |
968 | + ((utf16[i+1] & 3) << 2) |
969 | + ((utf16[i] >> 6) & 3); |
970 | utf8[size++] = 0x80 + (utf16[i] & 63); |
971 | state = BASE; |
972 | } else |
973 | state = ERR; |
974 | break; |
975 | case ERR : |
976 | break; |
977 | } |
978 | } |
979 | utf8[size] = 0; |
980 | if (state != BASE) |
981 | state = ERR; |
982 | return (state == ERR ? 0 : size); |
983 | } |
984 | |
985 | #ifdef WIN32 |
986 | |
987 | /* |
988 | * Evaluate the size of UTF-16LE conversion of a UTF-8 text |
989 | * (basic conversions only) |
990 | * trailing '\0' not accounted for |
991 | */ |
992 | |
993 | unsigned int utf16size(const char *utf8) |
994 | { |
995 | unsigned int size; |
996 | const char *p; |
997 | int c; |
998 | unsigned int code; |
999 | enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, ERR } state; |
1000 | |
1001 | p = utf8; |
1002 | size = 0; |
1003 | state = BASE; |
1004 | while (*p) { |
1005 | c = *p++ & 255; |
1006 | switch (state) { |
1007 | case BASE : |
1008 | if (!(c & 0x80)) |
1009 | size++; |
1010 | else |
1011 | if (c < 0xc2) |
1012 | state = ERR; |
1013 | else |
1014 | if (c < 0xe0) |
1015 | state = TWO; |
1016 | else |
1017 | if (c < 0xf0) { |
1018 | if (c == 0xe0) |
1019 | state = THREE2; |
1020 | else |
1021 | if (c == 0xed) |
1022 | state = THREE3; |
1023 | else |
1024 | state = THREE; |
1025 | } else |
1026 | if (c < 0xf8) { |
1027 | state = FOUR; |
1028 | code = c & 7; |
1029 | } else |
1030 | state = ERR; |
1031 | break; |
1032 | case TWO : |
1033 | if ((c & 0xc0) != 0x80) |
1034 | state = ERR; |
1035 | else { |
1036 | size++; |
1037 | state = BASE; |
1038 | } |
1039 | break; |
1040 | case THREE : |
1041 | if ((c & 0xc0) != 0x80) |
1042 | state = ERR; |
1043 | else |
1044 | state = TWO; |
1045 | break; |
1046 | case THREE2 : |
1047 | if ((c & 0xe0) != 0xa0) |
1048 | state = ERR; |
1049 | else |
1050 | state = TWO; |
1051 | break; |
1052 | case THREE3 : |
1053 | if ((c & 0xe0) != 0x80) |
1054 | state = ERR; |
1055 | else |
1056 | state = TWO; |
1057 | break; |
1058 | case FOUR : |
1059 | if ((((code << 6) + (c & 63)) > 0x10f) |
1060 | || (((code << 6) + (c & 63)) < 0x10)) |
1061 | state = ERR; |
1062 | else { |
1063 | size++; |
1064 | state = THREE; |
1065 | } |
1066 | break; |
1067 | case ERR : |
1068 | break; |
1069 | } |
1070 | } |
1071 | if (state != BASE) size = 0; |
1072 | return (size); |
1073 | } |
1074 | |
1075 | /* |
1076 | * Convert a UTF8 text to UTF-16LE |
1077 | * (basic conversions only) |
1078 | * Note : mbstowcs() not used because on Linux it fails for characters |
1079 | * not present in current locale |
1080 | */ |
1081 | |
1082 | unsigned int makeutf16(char *target, const char *utf8) |
1083 | { |
1084 | unsigned int size; |
1085 | unsigned int code; |
1086 | const char *p; |
1087 | int c; |
1088 | enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, FOUR2, FOUR3, ERR } state; |
1089 | |
1090 | p = utf8; |
1091 | size = 0; |
1092 | c = 0; |
1093 | state = BASE; |
1094 | while (*p) { |
1095 | c = *p++ & 255; |
1096 | switch (state) { |
1097 | case BASE : |
1098 | if (!(c & 0x80)) { |
1099 | target[2*size] = c; |
1100 | target[2*size + 1] = 0; |
1101 | size++; |
1102 | } else { |
1103 | if (c < 0xc2) |
1104 | state = ERR; |
1105 | else |
1106 | if (c < 0xe0) { |
1107 | code = c & 31; |
1108 | state = TWO; |
1109 | } else |
1110 | if (c < 0xf0) { |
1111 | code = c & 15; |
1112 | if (c == 0xe0) |
1113 | state = THREE2; |
1114 | else |
1115 | if (c == 0xed) |
1116 | state = THREE3; |
1117 | else |
1118 | state = THREE; |
1119 | } else |
1120 | if (c < 0xf8) { |
1121 | code = c & 7; |
1122 | state = FOUR; |
1123 | } else |
1124 | state = ERR; |
1125 | } |
1126 | break; |
1127 | case TWO : |
1128 | #if NOREVBOM |
1129 | if (((c & 0xc0) != 0x80) |
1130 | || ((code == 0x3ff) && (c >= 0xbe))) |
1131 | #else |
1132 | if ((c & 0xc0) != 0x80) |
1133 | #endif |
1134 | state = ERR; |
1135 | else { |
1136 | target[2*size] = ((code & 3) << 6) + (c & 63); |
1137 | target[2*size + 1] = ((code >> 2) & 255); |
1138 | size++; |
1139 | state = BASE; |
1140 | } |
1141 | break; |
1142 | case THREE : |
1143 | if ((c & 0xc0) != 0x80) |
1144 | state = ERR; |
1145 | else { |
1146 | code = ((code & 15) << 6) + (c & 63); |
1147 | state = TWO; |
1148 | } |
1149 | break; |
1150 | case THREE2 : |
1151 | if ((c & 0xe0) != 0xa0) |
1152 | state = ERR; |
1153 | else { |
1154 | code = ((code & 15) << 6) + (c & 63); |
1155 | state = TWO; |
1156 | } |
1157 | break; |
1158 | case THREE3 : |
1159 | if ((c & 0xe0) != 0x80) |
1160 | state = ERR; |
1161 | else { |
1162 | code = ((code & 15) << 6) + (c & 63); |
1163 | state = TWO; |
1164 | } |
1165 | break; |
1166 | case FOUR : |
1167 | if ((c & 0xc0) != 0x80) |
1168 | state = ERR; |
1169 | else { |
1170 | code = (code << 6) + (c & 63); |
1171 | state = FOUR2; |
1172 | } |
1173 | break; |
1174 | case FOUR2 : |
1175 | if ((c & 0xc0) != 0x80) |
1176 | state = ERR; |
1177 | else { |
1178 | code = (code << 6) + (c & 63); |
1179 | state = FOUR3; |
1180 | } |
1181 | break; |
1182 | case FOUR3 : |
1183 | if ((code > 0x43ff) |
1184 | || (code < 0x400) |
1185 | || ((c & 0xc0) != 0x80)) |
1186 | state = ERR; |
1187 | else { |
1188 | target[2*size] = ((code - 0x400) >> 4) & 255; |
1189 | target[2*size+1] = 0xd8 + (((code - 0x400) >> 12) & 3); |
1190 | target[2*size+2] = ((code & 3) << 6) + (c & 63); |
1191 | target[2*size+3] = 0xdc + ((code >> 2) & 3); |
1192 | size += 2; |
1193 | state = BASE; |
1194 | } |
1195 | break; |
1196 | case ERR : |
1197 | break; |
1198 | } |
1199 | } |
1200 | if (state != BASE) |
1201 | size = 0; |
1202 | target[2*size] = 0; |
1203 | target[2*size + 1] = 0; |
1204 | return (size); |
1205 | } |
1206 | |
1207 | unsigned int utf16len(const char *str) |
1208 | { |
1209 | unsigned int len; |
1210 | |
1211 | len = 0; |
1212 | while (str[2*len] || str[2*len+1]) len++; |
1213 | return (len); |
1214 | } |
1215 | |
1216 | #endif |
1217 | |
1218 | /* |
1219 | * Print a file name |
1220 | * on Windows it prints UTF-16LE names as UTF-8 |
1221 | */ |
1222 | |
1223 | void printname(FILE *file, const char *name) |
1224 | { |
1225 | #ifdef WIN32 |
1226 | char utf8name[MAXFILENAME]; |
1227 | |
1228 | makeutf8(utf8name,name,utf16len(name)); |
1229 | fprintf(file,"%s",utf8name); |
1230 | #else |
1231 | fprintf(file,"%s",name); |
1232 | #endif |
1233 | } |
1234 | |
1235 | /* |
1236 | * Print the last error code |
1237 | */ |
1238 | |
1239 | void printerror(FILE *file) |
1240 | { |
1241 | #ifdef WIN32 |
1242 | int err; |
1243 | const char *txt; |
1244 | |
1245 | err = GetLastError(); |
1246 | switch (err) { |
1247 | case 5 : |
1248 | txt = "Access to security descriptor was denied"; |
1249 | break; |
1250 | case 1307 : |
1251 | txt = "This SID may not be assigned as the owner of this object"; |
1252 | break; |
1253 | case 1308 : |
1254 | txt = "This SID may not be assigned as the group of this object"; |
1255 | break; |
1256 | case 1314 : |
1257 | txt = "You do not have the privilege to change this SID"; |
1258 | break; |
1259 | default : |
1260 | txt = (const char*)NULL; |
1261 | break; |
1262 | } |
1263 | if (txt) |
1264 | fprintf(file,"Error %d : %s\n",err,txt); |
1265 | else |
1266 | fprintf(file,"Error %d\n",err); |
1267 | #else |
1268 | #ifdef STSC |
1269 | if (errno) fprintf(file,"Error code %d\n",errno); |
1270 | #else |
1271 | if (errno) fprintf(file,"Error code %d : %s\n",errno,strerror(errno)); |
1272 | #endif |
1273 | #endif |
1274 | } |
1275 | |
1276 | /* |
1277 | * Guess whether a security attribute is intended for a directory |
1278 | * based on the presence of inheritable ACE |
1279 | * (not 100% reliable) |
1280 | */ |
1281 | |
1282 | BOOL guess_dir(const char *attr) |
1283 | { |
1284 | int off; |
1285 | int isdir; |
1286 | int cnt; |
1287 | int i; |
1288 | int x; |
1289 | |
1290 | isdir = 0; |
1291 | off = get4l(attr,16); |
1292 | if (off) { |
1293 | cnt = get2l(attr,off+4); |
1294 | x = 8; |
1295 | for (i=0; i<cnt; i++) { |
1296 | if (attr[off + x + 1] & 3) |
1297 | isdir = 1; |
1298 | x += get2l(attr,off + x + 2); |
1299 | } |
1300 | } |
1301 | return (isdir); |
1302 | } |
1303 | |
1304 | /* |
1305 | * Display a SID |
1306 | * See http://msdn2.microsoft.com/en-us/library/aa379649.aspx |
1307 | */ |
1308 | |
1309 | void showsid(const char *attr, int off, int level) |
1310 | { |
1311 | int cnt; |
1312 | int i; |
1313 | BOOL known; |
1314 | u64 auth; |
1315 | unsigned long first; |
1316 | unsigned long second; |
1317 | unsigned long last; |
1318 | char marker; |
1319 | |
1320 | if (opt_b) |
1321 | marker = '#'; |
1322 | else |
1323 | marker = ' '; |
1324 | cnt = attr[off+1] & 255; |
1325 | auth = get6h(attr,off+2); |
1326 | first = get4l(attr,off+8); |
1327 | known = FALSE; |
1328 | if ((attr[off] == 1) /* revision */ |
1329 | && (auth < 100)) |
1330 | switch (cnt) { |
1331 | case 0 : /* no level (error) */ |
1332 | break; |
1333 | case 1 : /* single level */ |
1334 | switch (auth) { |
1335 | case 0 : |
1336 | if (first == 0) { |
1337 | known = TRUE; |
1338 | printf("%*cNull SID\n",-level,marker); |
1339 | } |
1340 | break; |
1341 | case 1 : |
1342 | if (first == 0) { |
1343 | known = TRUE; |
1344 | printf("%*cWorld SID\n",-level,marker); |
1345 | } |
1346 | break; |
1347 | case 3 : |
1348 | switch (first) { |
1349 | case 0 : |
1350 | known = TRUE; |
1351 | printf("%*cCreator owner SID\n",-level,marker); |
1352 | break; |
1353 | case 1 : |
1354 | known = TRUE; |
1355 | printf("%*cCreator group SID\n",-level,marker); |
1356 | break; |
1357 | } |
1358 | break; |
1359 | case 5 : |
1360 | switch (first) { |
1361 | case 7 : |
1362 | known = TRUE; |
1363 | printf("%*cAnonymous logon SID\n",-level,marker); |
1364 | break; |
1365 | case 11 : |
1366 | known = TRUE; |
1367 | printf("%*cAuthenticated user SID\n",-level,marker); |
1368 | break; |
1369 | case 13 : |
1370 | known = TRUE; |
1371 | printf("%*cLocal service SID\n",-level,marker); |
1372 | break; |
1373 | case 14 : |
1374 | known = TRUE; |
1375 | printf("%*cNetwork service SID\n",-level,marker); |
1376 | break; |
1377 | case 18 : |
1378 | known = TRUE; |
1379 | printf("%*cNT System SID\n",-level,marker); |
1380 | break; |
1381 | } |
1382 | break; |
1383 | } |
1384 | break; |
1385 | case 2 : /* double level */ |
1386 | second = get4l(attr,off+12); |
1387 | switch (auth) { |
1388 | case 5 : |
1389 | if (first == 32) { |
1390 | known = TRUE; |
1391 | switch (second) { |
1392 | case 544 : |
1393 | printf("%*cLocal admins SID\n",-level,marker); |
1394 | break; |
1395 | case 545 : |
1396 | printf("%*cLocal users SID\n",-level,marker); |
1397 | break; |
1398 | case 546 : |
1399 | printf("%*cLocal guests SID\n",-level,marker); |
1400 | break; |
1401 | default : |
1402 | printf("%*cSome domain SID\n",-level,marker); |
1403 | break; |
1404 | } |
1405 | } |
1406 | break; |
1407 | } |
1408 | default : /* three levels or more */ |
1409 | second = get4l(attr,off+12); |
1410 | last = get4l(attr,off+4+4*cnt); |
1411 | switch (auth) { |
1412 | case 5 : |
1413 | if (first == 21) { |
1414 | known = TRUE; |
1415 | switch (last) |
1416 | { |
1417 | case 512 : |
1418 | printf("%*cLocal admins SID\n",-level,marker); |
1419 | break; |
1420 | case 513 : |
1421 | printf("%*cLocal users SID\n",-level,marker); |
1422 | break; |
1423 | case 514 : |
1424 | printf("%*cLocal guests SID\n",-level,marker); |
1425 | break; |
1426 | default : |
1427 | printf("%*cLocal user-%lu SID\n",-level,marker,last); |
1428 | break; |
1429 | } |
1430 | } |
1431 | break; |
1432 | } |
1433 | } |
1434 | if (!known) |
1435 | printf("%*cUnknown SID\n",-level,marker); |
1436 | printf("%*chex S-%d-",-level,marker,attr[off] & 255); |
1437 | printf("%llx",auth); |
1438 | for (i=0; i<cnt; i++) |
1439 | printf("-%lx",get4l(attr,off+8+4*i)); |
1440 | printf("\n"); |
1441 | printf("%*cdec S-%d-",-level,marker,attr[off] & 255); |
1442 | printf("%llu",auth); |
1443 | for (i=0; i<cnt; i++) |
1444 | printf("-%lu",get4l(attr,off+8+4*i)); |
1445 | printf("\n"); |
1446 | } |
1447 | |
1448 | void showusid(const char *attr, int level) |
1449 | { |
1450 | int off; |
1451 | char marker; |
1452 | |
1453 | if (opt_b) |
1454 | marker = '#'; |
1455 | else |
1456 | marker = ' '; |
1457 | if (level) |
1458 | printf("%*c",-level,marker); |
1459 | printf("User SID\n"); |
1460 | off = get4l(attr,4); |
1461 | showsid(attr,off,level+4); |
1462 | } |
1463 | |
1464 | void showgsid(const char *attr, int level) |
1465 | { |
1466 | int off; |
1467 | char marker; |
1468 | |
1469 | if (opt_b) |
1470 | marker = '#'; |
1471 | else |
1472 | marker = ' '; |
1473 | if (level) |
1474 | printf("%*c",-level,marker); |
1475 | printf("Group SID\n"); |
1476 | off = get4l(attr,8); |
1477 | showsid(attr,off,level+4); |
1478 | } |
1479 | |
1480 | void showheader(const char *attr, int level) |
1481 | { |
1482 | int flags; |
1483 | char marker; |
1484 | |
1485 | if (opt_b) |
1486 | marker = '#'; |
1487 | else |
1488 | marker = ' '; |
1489 | if (level) |
1490 | printf("%*c",-level,marker); |
1491 | printf("Global header\n"); |
1492 | printf("%*crevision %d\n",-level-4,marker,attr[0]); |
1493 | flags = get2l(attr,2); |
1494 | printf("%*cflags 0x%x\n",-level-4,marker,flags); |
1495 | if (flags & 1) |
1496 | printf("%*c owner is defaulted\n",-level-4,marker); |
1497 | if (flags & 2) |
1498 | printf("%*c group is defaulted\n",-level-4,marker); |
1499 | if (flags & 4) |
1500 | printf("%*c DACL present\n",-level-4,marker); |
1501 | if (flags & 8) |
1502 | printf("%*c DACL is defaulted\n",-level-4,marker); |
1503 | if (flags & 0x10) |
1504 | printf("%*c SACL present\n",-level-4,marker); |
1505 | if (flags & 0x20) |
1506 | printf("%*c SACL is defaulted\n",-level-4,marker); |
1507 | if (flags & 0x100) |
1508 | printf("%*c DACL inheritance is requested\n",-level-4,marker); |
1509 | if (flags & 0x200) |
1510 | printf("%*c SACL inheritance is requested\n",-level-4,marker); |
1511 | if (flags & 0x400) |
1512 | printf("%*c DACL was inherited automatically\n",-level-4,marker); |
1513 | if (flags & 0x800) |
1514 | printf("%*c SACL was inherited automatically\n",-level-4,marker); |
1515 | if (flags & 0x1000) |
1516 | printf("%*c DACL cannot be modified by inheritable ACEs\n",-level-4,marker); |
1517 | if (flags & 0x2000) |
1518 | printf("%*c SACL cannot be modified by inheritable ACEs\n",-level-4,marker); |
1519 | if (flags & 0x8000) |
1520 | printf("%*c self relative descriptor\n",-level-4,marker); |
1521 | if (flags & 0x43eb) |
1522 | printf("%*c unknown flags 0x%x present\n",-level-4,marker, |
1523 | flags & 0x43eb); |
1524 | printf("%*cOff USID 0x%x\n",-level-4,marker,(int)get4l(attr,4)); |
1525 | printf("%*cOff GSID 0x%x\n",-level-4,marker,(int)get4l(attr,8)); |
1526 | printf("%*cOff SACL 0x%x\n",-level-4,marker,(int)get4l(attr,12)); |
1527 | printf("%*cOff DACL 0x%x\n",-level-4,marker,(int)get4l(attr,16)); |
1528 | } |
1529 | |
1530 | void showace(const char *attr, int off, int isdir, int level) |
1531 | { |
1532 | int flags; |
1533 | u32 rights; |
1534 | char marker; |
1535 | |
1536 | if (opt_b) |
1537 | marker = '#'; |
1538 | else |
1539 | marker = ' '; |
1540 | printf("%*ctype %d\n",-level,marker,attr[off]); |
1541 | switch (attr[off]) { |
1542 | case 0 : |
1543 | printf("%*cAccess allowed\n",-level-4,marker); |
1544 | break; |
1545 | case 1 : |
1546 | printf("%*cAccess denied\n",-level-4,marker); |
1547 | break; |
1548 | case 2 : |
1549 | printf("%*cSystem audit\n",-level-4,marker); |
1550 | break; |
1551 | default : |
1552 | printf("%*cunknown\n",-level-4,marker); |
1553 | break; |
1554 | } |
1555 | flags = attr[off+1] & 255; |
1556 | printf("%*cflags 0x%x\n",-level,marker,flags); |
1557 | if (flags & 1) |
1558 | printf("%*cObject inherits ACE\n",-level-4,marker); |
1559 | if (flags & 2) |
1560 | printf("%*cContainer inherits ACE\n",-level-4,marker); |
1561 | if (flags & 4) |
1562 | printf("%*cDon\'t propagate inherits ACE\n",-level-4,marker); |
1563 | if (flags & 8) |
1564 | printf("%*cInherit only ACE\n",-level-4,marker); |
1565 | if (flags & 0x40) |
1566 | printf("%*cAudit on success\n",-level-4,marker); |
1567 | if (flags & 0x80) |
1568 | printf("%*cAudit on failure\n",-level-4,marker); |
1569 | |
1570 | printf("%*cSize 0x%x\n",-level,marker,get2l(attr,off+2)); |
1571 | |
1572 | rights = get4l(attr,off+4); |
1573 | printf("%*cAcc rgts 0x%lx\n",-level,marker,(long)rights); |
1574 | printf("%*cObj specific acc rgts 0x%lx\n",-level-4,marker,(long)rights & 65535); |
1575 | if (isdir) /* a directory */ { |
1576 | if (rights & 0x01) |
1577 | printf("%*cList directory\n",-level-8,marker); |
1578 | if (rights & 0x02) |
1579 | printf("%*cAdd file\n",-level-8,marker); |
1580 | if (rights & 0x04) |
1581 | printf("%*cAdd subdirectory\n",-level-8,marker); |
1582 | if (rights & 0x08) |
1583 | printf("%*cRead EA\n",-level-8,marker); |
1584 | if (rights & 0x10) |
1585 | printf("%*cWrite EA\n",-level-8,marker); |
1586 | if (rights & 0x20) |
1587 | printf("%*cTraverse\n",-level-8,marker); |
1588 | if (rights & 0x40) |
1589 | printf("%*cDelete child\n",-level-8,marker); |
1590 | if (rights & 0x80) |
1591 | printf("%*cRead attributes\n",-level-8,marker); |
1592 | if (rights & 0x100) |
1593 | printf("%*cWrite attributes\n",-level-8,marker); |
1594 | } |
1595 | else { |
1596 | /* see FILE_READ_DATA etc in winnt.h */ |
1597 | if (rights & 0x01) |
1598 | printf("%*cRead data\n",-level-8,marker); |
1599 | if (rights & 0x02) |
1600 | printf("%*cWrite data\n",-level-8,marker); |
1601 | if (rights & 0x04) |
1602 | printf("%*cAppend data\n",-level-8,marker); |
1603 | if (rights & 0x08) |
1604 | printf("%*cRead EA\n",-level-8,marker); |
1605 | if (rights & 0x10) |
1606 | printf("%*cWrite EA\n",-level-8,marker); |
1607 | if (rights & 0x20) |
1608 | printf("%*cExecute\n",-level-8,marker); |
1609 | if (rights & 0x80) |
1610 | printf("%*cRead attributes\n",-level-8,marker); |
1611 | if (rights & 0x100) |
1612 | printf("%*cWrite attributes\n",-level-8,marker); |
1613 | } |
1614 | printf("%*cstandard acc rgts 0x%lx\n",-level-4,marker,(long)(rights >> 16) & 127); |
1615 | if (rights & 0x10000) |
1616 | printf("%*cDelete\n",-level-8,marker); |
1617 | if (rights & 0x20000) |
1618 | printf("%*cRead control\n",-level-8,marker); |
1619 | if (rights & 0x40000) |
1620 | printf("%*cWrite DAC\n",-level-8,marker); |
1621 | if (rights & 0x80000) |
1622 | printf("%*cWrite owner\n",-level-8,marker); |
1623 | if (rights & 0x100000) |
1624 | printf("%*cSynchronize\n",-level-8,marker); |
1625 | if (rights & 0x800000) |
1626 | printf("%*cCan access security ACL\n",-level-4,marker); |
1627 | if (rights & 0x10000000) |
1628 | printf("%*cGeneric all\n",-level-4,marker); |
1629 | if (rights & 0x20000000) |
1630 | printf("%*cGeneric execute\n",-level-4,marker); |
1631 | if (rights & 0x40000000) |
1632 | printf("%*cGeneric write\n",-level-4,marker); |
1633 | if (rights & 0x80000000) |
1634 | printf("%*cGeneric read\n",-level-4,marker); |
1635 | |
1636 | printf("%*cSID at 0x%x\n",-level,marker,off+8); |
1637 | showsid(attr,off+8,level+4); |
1638 | printf("%*cSummary :",-level,marker); |
1639 | if (attr[off] == 0) |
1640 | printf(" grant"); |
1641 | if (attr[off] == 1) |
1642 | printf(" deny"); |
1643 | if (rights & le32_to_cpu(FILE_GREAD | FILE_GWRITE | FILE_GEXEC)) { |
1644 | printf(" "); |
1645 | if (rights & le32_to_cpu(FILE_GREAD)) |
1646 | printf("r"); |
1647 | if (rights & le32_to_cpu(FILE_GWRITE)) |
1648 | printf("w"); |
1649 | if (rights & le32_to_cpu(FILE_GEXEC)) |
1650 | printf("x"); |
1651 | } else |
1652 | printf(" none"); |
1653 | if (flags & 11) |
1654 | printf(" inherited"); |
1655 | if (!(flags & 8)) { |
1656 | int sz; |
1657 | |
1658 | printf(" applied"); |
1659 | sz = attr[off+9]*4 + 8; |
1660 | if (!memcmp(&attr[off+8],&attr[get4l(attr,4)],sz)) |
1661 | printf(" to owner"); |
1662 | if (!memcmp(&attr[off+8],&attr[get4l(attr,8)],sz)) |
1663 | printf(" to group"); |
1664 | } |
1665 | printf("\n"); |
1666 | |
1667 | } |
1668 | |
1669 | void showacl(const char *attr, int off, int isdir, int level) |
1670 | { |
1671 | int i; |
1672 | int cnt; |
1673 | int size; |
1674 | int x; |
1675 | char marker; |
1676 | |
1677 | if (opt_b) |
1678 | marker = '#'; |
1679 | else |
1680 | marker = ' '; |
1681 | size = get2l(attr,off+2); |
1682 | printf("%*crevision %d\n",-level,marker,attr[off]); |
1683 | printf("%*cACL size %d\n",-level,marker,size); |
1684 | cnt = get2l(attr,off+4); |
1685 | printf("%*cACE cnt %d\n",-level,marker,cnt); |
1686 | x = 8; |
1687 | for (i=0; (i<cnt) && (x < size); i++) { |
1688 | printf("%*cACE %d at 0x%x\n",-level,marker,i + 1,off+x); |
1689 | showace(attr,off + x,isdir,level+4); |
1690 | x += get2l(attr,off + x + 2); |
1691 | } |
1692 | } |
1693 | |
1694 | void showdacl(const char *attr, int isdir, int level) |
1695 | { |
1696 | int off; |
1697 | char marker; |
1698 | |
1699 | if (opt_b) |
1700 | marker = '#'; |
1701 | else |
1702 | marker = ' '; |
1703 | off = get4l(attr,16); |
1704 | if (off) { |
1705 | if (level) |
1706 | printf("%*c",-level,marker); |
1707 | printf("DACL\n"); |
1708 | showacl(attr,off,isdir,level+4); |
1709 | } else { |
1710 | if (level) |
1711 | printf("%*c",-level,marker); |
1712 | printf("No DACL\n"); |
1713 | } |
1714 | } |
1715 | |
1716 | void showsacl(const char *attr, int isdir, int level) |
1717 | { |
1718 | int off; |
1719 | char marker; |
1720 | |
1721 | if (opt_b) |
1722 | marker = '#'; |
1723 | else |
1724 | marker = ' '; |
1725 | off = get4l(attr,12); |
1726 | if (off) { |
1727 | if (level) |
1728 | printf("%*c",-level,marker); |
1729 | printf("SACL\n"); |
1730 | showacl(attr,off,isdir,level+4); |
1731 | } |
1732 | else { |
1733 | if (level) |
1734 | printf("%*c",-level,marker); |
1735 | printf("No SACL\n"); |
1736 | } |
1737 | } |
1738 | |
1739 | void showall(const char *attr, int level) |
1740 | { |
1741 | BOOL isdir; |
1742 | |
1743 | isdir = guess_dir(attr); |
1744 | showheader(attr,level); |
1745 | showusid(attr,level); |
1746 | showgsid(attr,level); |
1747 | showdacl(attr,isdir,level); |
1748 | showsacl(attr,isdir,level); |
1749 | } |
1750 | |
1751 | #if POSIXACLS |
1752 | /* |
1753 | * Display a Posix descriptor |
1754 | */ |
1755 | |
1756 | void showposix(const struct POSIX_SECURITY *pxdesc) |
1757 | { |
1758 | char txperm[4]; |
1759 | const char *txtag; |
1760 | const char *txtype; |
1761 | const struct POSIX_ACL *acl; |
1762 | const struct POSIX_ACE *pxace; |
1763 | int acccnt; |
1764 | int defcnt; |
1765 | int firstdef; |
1766 | int perms; |
1767 | u16 tag; |
1768 | s32 id; |
1769 | int k,l; |
1770 | |
1771 | if (pxdesc) { |
1772 | acccnt = pxdesc->acccnt; |
1773 | defcnt = pxdesc->defcnt; |
1774 | firstdef = pxdesc->firstdef; |
1775 | acl = &pxdesc->acl; |
1776 | printf("Posix descriptor :\n"); |
1777 | printf(" acccnt %d\n",acccnt); |
1778 | printf(" defcnt %d\n",defcnt); |
1779 | printf(" firstdef %d\n",firstdef); |
1780 | printf(" mode : 0%03o\n",(int)pxdesc->mode); |
1781 | printf(" tagsset : 0x%02x\n",(int)pxdesc->tagsset); |
1782 | printf("Posix ACL :\n"); |
1783 | printf(" version %d\n",(int)acl->version); |
1784 | printf(" flags 0x%02x\n",(int)acl->flags); |
1785 | for (k=0; k<(acccnt + defcnt); k++) { |
1786 | if (k < acccnt) |
1787 | l = k; |
1788 | else |
1789 | l = firstdef + k - acccnt; |
1790 | pxace = &acl->ace[l]; |
1791 | tag = pxace->tag; |
1792 | perms = pxace->perms; |
1793 | if (tag == POSIX_ACL_SPECIAL) { |
1794 | txperm[0] = (perms & S_ISVTX ? 's' : '-'); |
1795 | txperm[1] = (perms & S_ISUID ? 'u' : '-'); |
1796 | txperm[2] = (perms & S_ISGID ? 'g' : '-'); |
1797 | } else { |
1798 | txperm[0] = (perms & 4 ? 'r' : '-'); |
1799 | txperm[1] = (perms & 2 ? 'w' : '-'); |
1800 | txperm[2] = (perms & 1 ? 'x' : '-'); |
1801 | } |
1802 | txperm[3] = 0; |
1803 | if (k >= acccnt) |
1804 | txtype = "default"; |
1805 | else |
1806 | txtype = "access "; |
1807 | switch (tag) { |
1808 | case POSIX_ACL_USER : |
1809 | txtag = "USER "; |
1810 | break; |
1811 | case POSIX_ACL_USER_OBJ : |
1812 | txtag = "USR-O"; |
1813 | break; |
1814 | case POSIX_ACL_GROUP : |
1815 | txtag = "GROUP"; |
1816 | break; |
1817 | case POSIX_ACL_GROUP_OBJ : |
1818 | txtag = "GRP-O"; |
1819 | break; |
1820 | case POSIX_ACL_MASK : |
1821 | txtag = "MASK "; |
1822 | break; |
1823 | case POSIX_ACL_OTHER : |
1824 | txtag = "OTHER"; |
1825 | break; |
1826 | case POSIX_ACL_SPECIAL : |
1827 | txtag = "SPECL"; |
1828 | break; |
1829 | default : |
1830 | txtag = "UNKWN"; |
1831 | break; |
1832 | } |
1833 | id = pxace->id; |
1834 | printf("ace %d : %s %s %4ld perms 0%03o %s\n", |
1835 | l,txtype,txtag,(long)id, |
1836 | perms,txperm); |
1837 | } |
1838 | } else |
1839 | printf("** NULL ACL\n"); |
1840 | } |
1841 | |
1842 | #endif /* POSIXACLS */ |
1843 | |
1844 | #if defined(WIN32) | defined(STSC) |
1845 | |
1846 | #else |
1847 | |
1848 | /* |
1849 | * Relay to get usid as defined during mounting |
1850 | */ |
1851 | |
1852 | const SID *relay_find_usid(const struct MAPPING *usermapping __attribute__((unused)), |
1853 | uid_t uid, SID *defusid) |
1854 | { |
1855 | return (ntfs_get_usid(ntfs_context,uid,(char*)defusid) ? |
1856 | defusid : (SID*)NULL); |
1857 | } |
1858 | |
1859 | /* |
1860 | * Relay to get gsid as defined during mounting |
1861 | */ |
1862 | |
1863 | const SID *relay_find_gsid(const struct MAPPING *groupmapping __attribute__((unused)), |
1864 | uid_t gid, SID *defgsid) |
1865 | { |
1866 | return (ntfs_get_usid(ntfs_context,gid,(char*)defgsid) ? |
1867 | defgsid : (SID*)NULL); |
1868 | } |
1869 | |
1870 | /* |
1871 | * Relay to get uid as defined during mounting |
1872 | */ |
1873 | |
1874 | uid_t relay_find_user(const struct MAPPING *mapping __attribute__((unused)), |
1875 | const SID *usid) |
1876 | { |
1877 | int uid; |
1878 | |
1879 | uid = ntfs_get_user(ntfs_context,(const char*)usid); |
1880 | return (uid < 0 ? 0 : uid); |
1881 | } |
1882 | |
1883 | /* |
1884 | * Relay to get gid as defined during mounting |
1885 | */ |
1886 | |
1887 | gid_t relay_find_group(const struct MAPPING *mapping __attribute__((unused)), |
1888 | const SID *gsid) |
1889 | { |
1890 | int gid; |
1891 | |
1892 | gid = ntfs_get_group(ntfs_context,(const char*)gsid); |
1893 | return (gid < 0 ? 0 : gid); |
1894 | } |
1895 | |
1896 | #endif |
1897 | |
1898 | #if defined(WIN32) | defined(STSC) |
1899 | |
1900 | /* |
1901 | * Dummy get uid from user name, out of a Linux environment |
1902 | */ |
1903 | |
1904 | struct passwd *getpwnam(const char *user) |
1905 | { |
1906 | ntfs_log_error("Cannot interpret id \"%s\"", user); |
1907 | ntfs_log_error("please use numeric uids in UserMapping file\n"); |
1908 | return ((struct passwd*)NULL); |
1909 | } |
1910 | |
1911 | /* |
1912 | * Dummy get gid from group name, out of a Linux environment |
1913 | */ |
1914 | |
1915 | struct group *getgrnam(const char *group) |
1916 | { |
1917 | ntfs_log_error("Cannot interpret id \"%s\"", group); |
1918 | ntfs_log_error("please use numeric gids in UserMapping file\n"); |
1919 | return ((struct group*)NULL); |
1920 | } |
1921 | |
1922 | #endif /* defined(WIN32) | defined(STSC) */ |
1923 | |
1924 | #if POSIXACLS |
1925 | |
1926 | struct POSIX_SECURITY *linux_permissions_posix(const char *attr, BOOL isdir) |
1927 | { |
1928 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
1929 | #if OWNERFROMACL |
1930 | const SID *osid; |
1931 | #endif |
1932 | const SID *usid; |
1933 | const SID *gsid; |
1934 | struct POSIX_SECURITY *posix_desc; |
1935 | |
1936 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
1937 | gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
1938 | #if OWNERFROMACL |
1939 | osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
1940 | usid = ntfs_acl_owner((const char*)attr); |
1941 | #if SELFTESTS & !USESTUBS |
1942 | if (!opt_t && !ntfs_same_sid(usid,osid)) |
1943 | printf("== Linux owner is different from Windows owner\n"); |
1944 | #else |
1945 | if (!ntfs_same_sid(usid,osid)) |
1946 | printf("== Linux owner is different from Windows owner\n"); |
1947 | #endif |
1948 | #else |
1949 | usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
1950 | #endif |
1951 | posix_desc = ntfs_build_permissions_posix(context.mapping, |
1952 | (const char*)attr, usid, gsid, isdir); |
1953 | if (!posix_desc) { |
1954 | printf("** Failed to build a Posix descriptor\n"); |
1955 | errors++; |
1956 | } |
1957 | return (posix_desc); |
1958 | } |
1959 | |
1960 | #endif /* POSIXACLS */ |
1961 | |
1962 | int linux_permissions(const char *attr, BOOL isdir) |
1963 | { |
1964 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
1965 | #if OWNERFROMACL |
1966 | const SID *osid; |
1967 | #endif |
1968 | const SID *usid; |
1969 | const SID *gsid; |
1970 | int perm; |
1971 | |
1972 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
1973 | gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
1974 | #if OWNERFROMACL |
1975 | osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
1976 | usid = ntfs_acl_owner((const char*)attr); |
1977 | #if SELFTESTS & !USESTUBS |
1978 | if (!opt_t && !ntfs_same_sid(usid,osid)) |
1979 | printf("== Linux owner is different from Windows owner\n"); |
1980 | #else |
1981 | if (!ntfs_same_sid(usid,osid)) |
1982 | printf("== Linux owner is different from Windows owner\n"); |
1983 | #endif |
1984 | #else |
1985 | usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
1986 | #endif |
1987 | perm = ntfs_build_permissions((const char*)attr, usid, gsid, isdir); |
1988 | if (perm < 0) { |
1989 | printf("** Failed to build permissions\n"); |
1990 | errors++; |
1991 | } |
1992 | return (perm); |
1993 | } |
1994 | |
1995 | uid_t linux_owner(const char *attr) |
1996 | { |
1997 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
1998 | const SID *usid; |
1999 | uid_t uid; |
2000 | |
2001 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
2002 | #if OWNERFROMACL |
2003 | usid = ntfs_acl_owner((const char*)attr); |
2004 | #else |
2005 | usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
2006 | #endif |
2007 | #if defined(WIN32) | defined(STSC) |
2008 | uid = ntfs_find_user(context.mapping[MAPUSERS],usid); |
2009 | #else |
2010 | if (mappingtype == MAPEXTERN) |
2011 | uid = relay_find_user(context.mapping[MAPUSERS],usid); |
2012 | else |
2013 | uid = ntfs_find_user(context.mapping[MAPUSERS],usid); |
2014 | #endif |
2015 | return (uid); |
2016 | } |
2017 | |
2018 | gid_t linux_group(const char *attr) |
2019 | { |
2020 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
2021 | const SID *gsid; |
2022 | gid_t gid; |
2023 | |
2024 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
2025 | gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
2026 | #if defined(WIN32) | defined(STSC) |
2027 | gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); |
2028 | #else |
2029 | if (mappingtype == MAPEXTERN) |
2030 | gid = relay_find_group(context.mapping[MAPGROUPS],gsid); |
2031 | else |
2032 | gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); |
2033 | #endif |
2034 | return (gid); |
2035 | } |
2036 | |
2037 | void newblock(s32 key) |
2038 | { |
2039 | struct SECURITY_DATA *psecurdata; |
2040 | int i; |
2041 | |
2042 | if ((key > 0) && (key < MAXSECURID) && !securdata[key >> SECBLKSZ]) { |
2043 | securdata[key >> SECBLKSZ] = |
2044 | (struct SECURITY_DATA*)malloc((1 << SECBLKSZ)*sizeof(struct SECURITY_DATA)); |
2045 | if (securdata[key >> SECBLKSZ]) |
2046 | for (i=0; i<(1 << SECBLKSZ); i++) { |
2047 | psecurdata = &securdata[key >> SECBLKSZ][i]; |
2048 | psecurdata->filecount = 0; |
2049 | psecurdata->mode = 0; |
2050 | psecurdata->flags = 0; |
2051 | psecurdata->attr = (char*)NULL; |
2052 | } |
2053 | } |
2054 | } |
2055 | |
2056 | void freeblocks(void) |
2057 | { |
2058 | int i,j; |
2059 | struct SECURITY_DATA *psecurdata; |
2060 | |
2061 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
2062 | if (securdata[i]) { |
2063 | for (j=0; j<(1 << SECBLKSZ); j++) { |
2064 | psecurdata = &securdata[i][j]; |
2065 | if (psecurdata->attr) |
2066 | free(psecurdata->attr); |
2067 | } |
2068 | free(securdata[i]); |
2069 | } |
2070 | } |
2071 | |
2072 | /* |
2073 | * Basic read from a user mapping file (Win32) |
2074 | */ |
2075 | |
2076 | int basicread(void *fileid, char *buf, size_t size, |
2077 | off_t pos __attribute__((unused))) |
2078 | { |
2079 | return (read(*(int*)fileid, buf, size)); |
2080 | } |
2081 | |
2082 | #if SELFTESTS & !USESTUBS |
2083 | |
2084 | /* |
2085 | * Read a dummy mapping file for tests |
2086 | */ |
2087 | |
2088 | int dummyread(void *fileid __attribute__((unused)), |
2089 | char *buf, size_t size, off_t pos) |
2090 | { |
2091 | size_t sz; |
2092 | |
2093 | if (pos >= (off_t)(sizeof(dummymapping) - 1)) |
2094 | sz = 0; |
2095 | else |
2096 | if ((size + pos) >= (sizeof(dummymapping) - 1)) |
2097 | sz = sizeof(dummymapping) - 1 - pos; |
2098 | else |
2099 | sz = size; |
2100 | if (sz > 0) |
2101 | memcpy(buf,&dummymapping[pos],sz); |
2102 | return (sz); |
2103 | } |
2104 | |
2105 | #endif /* POSIXACLS & SELFTESTS & !USESTUBS */ |
2106 | |
2107 | /* |
2108 | * Build the user mapping |
2109 | * - according to a mapping file if defined (or default present), |
2110 | * - or try default single user mapping if possible |
2111 | * |
2112 | * The mapping is specific to a mounted device |
2113 | * No locking done, mounting assumed non multithreaded |
2114 | * |
2115 | * returns zero if mapping is successful |
2116 | * (failure should not be interpreted as an error) |
2117 | */ |
2118 | |
2119 | int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) |
2120 | { |
2121 | #ifdef WIN32 |
2122 | char mapfile[sizeof(MAPDIR) + sizeof(MAPFILE) + 6]; |
2123 | #else |
2124 | char *mapfile; |
2125 | char *p; |
2126 | #endif |
2127 | int fd; |
2128 | struct MAPLIST *item; |
2129 | struct MAPLIST *firstitem = (struct MAPLIST*)NULL; |
2130 | struct MAPPING *usermapping; |
2131 | struct MAPPING *groupmapping; |
2132 | |
2133 | /* be sure not to map anything until done */ |
2134 | mapping[MAPUSERS] = (struct MAPPING*)NULL; |
2135 | mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
2136 | |
2137 | if (usermap_path) { |
2138 | #ifdef WIN32 |
2139 | /* TODO : check whether the device can store acls */ |
2140 | strcpy(mapfile,"x:\\" MAPDIR "\\" MAPFILE); |
2141 | if (((le16*)usermap_path)[1] == ':') |
2142 | mapfile[0] = usermap_path[0]; |
2143 | else |
2144 | mapfile[0] = getdrive() + 'A' - 1; |
2145 | fd = open(mapfile,O_RDONLY); |
2146 | #else |
2147 | fd = 0; |
2148 | mapfile = (char*)malloc(MAXFILENAME); |
2149 | if (mapfile) { |
2150 | /* build a full path to locate the mapping file */ |
2151 | if ((usermap_path[0] != '/') |
2152 | && getcwd(mapfile,MAXFILENAME)) { |
2153 | strcat(mapfile,"/"); |
2154 | strcat(mapfile,usermap_path); |
2155 | } else |
2156 | strcpy(mapfile,usermap_path); |
2157 | p = strrchr(mapfile,'/'); |
2158 | if (p) |
2159 | do { |
2160 | strcpy(p,"/" MAPDIR "/" MAPFILE); |
2161 | fd = open(mapfile,O_RDONLY); |
2162 | if (fd <= 0) { |
2163 | *p = 0; |
2164 | p = strrchr(mapfile,'/'); |
2165 | if (p == mapfile) |
2166 | p = (char*)NULL; |
2167 | } |
2168 | } while ((fd <= 0) && p); |
2169 | free(mapfile); |
2170 | if (!p) { |
2171 | printf("** Could not find the user mapping file\n"); |
2172 | if (usermap_path[0] != '/') |
2173 | printf(" Retry with full path of file\n"); |
2174 | errors++; |
2175 | } |
2176 | } |
2177 | #endif |
2178 | if (fd > 0) { |
2179 | firstitem = ntfs_read_mapping(basicread, (void*)&fd); |
2180 | close(fd); |
2181 | } |
2182 | } else { |
2183 | #if SELFTESTS & !USESTUBS |
2184 | firstitem = ntfs_read_mapping(dummyread, (void*)NULL); |
2185 | #endif |
2186 | } |
2187 | |
2188 | if (firstitem) { |
2189 | usermapping = ntfs_do_user_mapping(firstitem); |
2190 | groupmapping = ntfs_do_group_mapping(firstitem); |
2191 | if (usermapping && groupmapping) { |
2192 | mapping[MAPUSERS] = usermapping; |
2193 | mapping[MAPGROUPS] = groupmapping; |
2194 | } else |
2195 | ntfs_log_error("There were no valid user or no valid group\n"); |
2196 | /* now we can free the memory copy of input text */ |
2197 | /* and rely on internal representation */ |
2198 | while (firstitem) { |
2199 | item = firstitem->next; |
2200 | #if USESTUBS |
2201 | stdfree(firstitem); /* allocated within library */ |
2202 | #else |
2203 | free(firstitem); |
2204 | #endif |
2205 | firstitem = item; |
2206 | } |
2207 | } |
2208 | if (mapping[MAPUSERS]) |
2209 | mappingtype = MAPLOCAL; |
2210 | return (!mapping[MAPUSERS]); |
2211 | } |
2212 | |
2213 | /* |
2214 | * Get an hexadecimal number (source with MSB first) |
2215 | */ |
2216 | |
2217 | u32 getmsbhex(const char *text) |
2218 | { |
2219 | u32 v; |
2220 | int b; |
2221 | BOOL ok; |
2222 | |
2223 | v = 0; |
2224 | ok = TRUE; |
2225 | do { |
2226 | b = *text++; |
2227 | if ((b >= '0') && (b <= '9')) |
2228 | v = (v << 4) + b - '0'; |
2229 | else |
2230 | if ((b >= 'a') && (b <= 'f')) |
2231 | v = (v << 4) + b - 'a' + 10; |
2232 | else |
2233 | if ((b >= 'A') && (b <= 'F')) |
2234 | v = (v << 4) + b - 'A' + 10; |
2235 | else ok = FALSE; |
2236 | } while (ok); |
2237 | return (v); |
2238 | } |
2239 | |
2240 | |
2241 | /* |
2242 | * Get an hexadecimal number (source with LSB first) |
2243 | * An odd number of digits might yield a strange result |
2244 | */ |
2245 | |
2246 | u32 getlsbhex(const char *text) |
2247 | { |
2248 | u32 v; |
2249 | int b; |
2250 | BOOL ok; |
2251 | int pos; |
2252 | |
2253 | v = 0; |
2254 | ok = TRUE; |
2255 | pos = 0; |
2256 | do { |
2257 | b = *text++; |
2258 | if ((b >= '0') && (b <= '9')) |
2259 | v |= (u32)(b - '0') << (pos ^ 4); |
2260 | else |
2261 | if ((b >= 'a') && (b <= 'f')) |
2262 | v |= (u32)(b - 'a' + 10) << (pos ^ 4); |
2263 | else |
2264 | if ((b >= 'A') && (b <= 'F')) |
2265 | v |= (u32)(b - 'A' + 10) << (pos ^ 4); |
2266 | else ok = FALSE; |
2267 | pos += 4; |
2268 | } while (ok); |
2269 | return (v); |
2270 | } |
2271 | |
2272 | |
2273 | /* |
2274 | * Check whether a line looks like an hex dump |
2275 | */ |
2276 | |
2277 | BOOL ishexdump(const char *line, int first, int lth) |
2278 | { |
2279 | BOOL ok; |
2280 | int i; |
2281 | int b; |
2282 | |
2283 | ok = (first >= 0) && (lth >= (first + 16)); |
2284 | for (i=0; ((first+i)<lth) && ok; i++) { |
2285 | b = line[first + i]; |
2286 | if ((i == 6) |
2287 | || (i == 7) |
2288 | || (i == 16) |
2289 | || (i == 25) |
2290 | || (i == 34) |
2291 | || (i == 43)) |
2292 | ok = (b == ' ') || (b == '\n'); |
2293 | else |
2294 | ok = ((b >= '0') && (b <= '9')) |
2295 | || ((b >= 'a') && (b <= 'f')) |
2296 | || ((b >= 'A') && (b <= 'F')); |
2297 | } |
2298 | return (ok); |
2299 | } |
2300 | |
2301 | |
2302 | /* |
2303 | * Display security descriptors from a file |
2304 | * This is typically to convert a verbose output to a very verbose one |
2305 | */ |
2306 | |
2307 | void showhex(FILE *fd) |
2308 | { |
2309 | static char attr[MAXATTRSZ]; |
2310 | char line[MAXLINE+1]; |
2311 | #if POSIXACLS |
2312 | struct POSIX_SECURITY *pxdesc; |
2313 | #endif |
2314 | int lth; |
2315 | int first; |
2316 | unsigned int pos; |
2317 | unsigned char b; |
2318 | u32 v; |
2319 | int c; |
2320 | int isdir; |
2321 | int mode; |
2322 | unsigned int off; |
2323 | int i; |
2324 | BOOL isdump; |
2325 | BOOL done; |
2326 | |
2327 | b = 0; |
2328 | pos = 0; |
2329 | off = 0; |
2330 | done = FALSE; |
2331 | do { |
2332 | /* input a (partial) line without displaying */ |
2333 | lth = 0; |
2334 | first = -1; |
2335 | do { |
2336 | c = getc(fd); |
2337 | if ((c != ' ') && (first < 0)) |
2338 | first = lth; |
2339 | if (c == EOF) |
2340 | done = TRUE; |
2341 | else |
2342 | if (c != '\r') |
2343 | line[lth++] = c; |
2344 | } while (!done && (c != '\n') && (lth < MAXLINE)); |
2345 | /* check whether this looks like an hexadecimal dump */ |
2346 | isdump = ishexdump(line, first, lth); |
2347 | if (isdump) off = getmsbhex(&line[first]); |
2348 | /* line is not an hexadecimal dump */ |
2349 | /* display what we have in store */ |
2350 | if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { |
2351 | printf(" Computed hash : 0x%08lx\n", |
2352 | (unsigned long)hash((le32*)attr, |
2353 | ntfs_attr_size(attr))); |
2354 | isdir = guess_dir(attr); |
2355 | printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); |
2356 | showheader(attr,4); |
2357 | showusid(attr,4); |
2358 | showgsid(attr,4); |
2359 | showdacl(attr,isdir,4); |
2360 | showsacl(attr,isdir,4); |
2361 | mode = linux_permissions(attr,isdir); |
2362 | printf("Interpreted Unix mode 0%03o\n",mode); |
2363 | #if POSIXACLS |
2364 | /* |
2365 | * Posix display not possible when user |
2366 | * mapping is not available (option -h) |
2367 | */ |
2368 | if (mappingtype != MAPNONE) { |
2369 | pxdesc = linux_permissions_posix(attr,isdir); |
2370 | if (pxdesc) { |
2371 | showposix(pxdesc); |
2372 | free(pxdesc); |
2373 | } |
2374 | } |
2375 | #endif |
2376 | pos = 0; |
2377 | } |
2378 | if (isdump && !off) |
2379 | pos = off; |
2380 | /* line looks like an hexadecimal dump */ |
2381 | /* decode it into attribute */ |
2382 | if (isdump && (off == pos)) { |
2383 | for (i=first+8; i<lth; i+=9) { |
2384 | v = getlsbhex(&line[i]); |
2385 | *(le32*)&attr[pos] = cpu_to_le32(v); |
2386 | pos += 4; |
2387 | } |
2388 | } |
2389 | /* display (full) current line */ |
2390 | if (lth) printf("! "); |
2391 | for (i=0; i<lth; i++) { |
2392 | c = line[i]; |
2393 | putchar(c); |
2394 | } |
2395 | while (!done && (c != '\n')) { |
2396 | c = getc(fd); |
2397 | if (c == EOF) |
2398 | done = TRUE; |
2399 | else |
2400 | putchar(c); |
2401 | } |
2402 | } while (!done); |
2403 | } |
2404 | |
2405 | BOOL applyattr(const char *fullname, const char *attr, |
2406 | BOOL withattr, int attrib, s32 key) |
2407 | { |
2408 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
2409 | struct SECURITY_DATA *psecurdata; |
2410 | const char *curattr; |
2411 | char *newattr; |
2412 | int selection; |
2413 | BOOL bad; |
2414 | BOOL badattrib; |
2415 | BOOL err; |
2416 | |
2417 | err = FALSE; |
2418 | psecurdata = (struct SECURITY_DATA*)NULL; |
2419 | curattr = (const char*)NULL; |
2420 | newattr = (char*)NULL; |
2421 | if ((key > 0) && (key < MAXSECURID)) { |
2422 | if (!securdata[key >> SECBLKSZ]) |
2423 | newblock(key); |
2424 | if (securdata[key >> SECBLKSZ]) { |
2425 | psecurdata = &securdata[key >> SECBLKSZ] |
2426 | [key & ((1 << SECBLKSZ) - 1)]; |
2427 | } |
2428 | } |
2429 | |
2430 | /* If we have a usable attrib value. Try applying */ |
2431 | badattrib = FALSE; |
2432 | if (opt_e && (attrib != INVALID_FILE_ATTRIBUTES)) { |
2433 | #ifdef WIN32 |
2434 | badattrib = !SetFileAttributesW((LPCWSTR)fullname, attrib); |
2435 | #else |
2436 | badattrib = !ntfs_set_file_attributes(ntfs_context, fullname, attrib); |
2437 | #endif |
2438 | if (badattrib) { |
2439 | printf("** Could not set Windows attrib of "); |
2440 | printname(stdout,fullname); |
2441 | printf(" to 0x%x\n", attrib); |
2442 | printerror(stdout); |
2443 | warnings++; |
2444 | } |
2445 | } |
2446 | |
2447 | if (withattr) { |
2448 | if (psecurdata) { |
2449 | newattr = (char*)malloc(ntfs_attr_size(attr)); |
2450 | if (newattr) { |
2451 | memcpy(newattr,attr,ntfs_attr_size(attr)); |
2452 | psecurdata->attr = newattr; |
2453 | } |
2454 | } |
2455 | curattr = attr; |
2456 | } else |
2457 | /* |
2458 | * No explicit attr in backup, use attr defined |
2459 | * previously for the same id |
2460 | */ |
2461 | if (psecurdata) |
2462 | curattr = psecurdata->attr; |
2463 | |
2464 | |
2465 | if (curattr) { |
2466 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)curattr; |
2467 | #ifdef WIN32 |
2468 | /* SACL currently not set, need some special privilege */ |
2469 | selection = OWNER_SECURITY_INFORMATION |
2470 | | GROUP_SECURITY_INFORMATION |
2471 | | DACL_SECURITY_INFORMATION; |
2472 | bad = !SetFileSecurityW((LPCWSTR)fullname, |
2473 | selection, (char*)curattr); |
2474 | if (bad) |
2475 | switch (GetLastError()) { |
2476 | case 1307 : |
2477 | case 1314 : |
2478 | printf("** Could not set owner of "); |
2479 | printname(stdout,fullname); |
2480 | printf(", retrying with no owner setting\n"); |
2481 | warnings++; |
2482 | bad = !SetFileSecurityW((LPCWSTR)fullname, |
2483 | selection & ~OWNER_SECURITY_INFORMATION, (char*)curattr); |
2484 | break; |
2485 | default : |
2486 | break; |
2487 | } |
2488 | #else |
2489 | selection = OWNER_SECURITY_INFORMATION |
2490 | | GROUP_SECURITY_INFORMATION |
2491 | | DACL_SECURITY_INFORMATION |
2492 | | SACL_SECURITY_INFORMATION; |
2493 | bad = !ntfs_set_file_security(ntfs_context,fullname, |
2494 | selection, (const char*)curattr); |
2495 | #endif |
2496 | if (bad) { |
2497 | printf("** Could not set the ACL of "); |
2498 | printname(stdout,fullname); |
2499 | printf("\n"); |
2500 | printerror(stdout); |
2501 | err = TRUE; |
2502 | } else |
2503 | if (opt_v) { |
2504 | if (opt_e && !badattrib) |
2505 | printf("ACL and attrib have been applied to "); |
2506 | else |
2507 | printf("ACL has been applied to "); |
2508 | printname(stdout,fullname); |
2509 | printf("\n"); |
2510 | |
2511 | } |
2512 | } else { |
2513 | printf("** There was no valid ACL for "); |
2514 | printname(stdout,fullname); |
2515 | printf("\n"); |
2516 | err = TRUE; |
2517 | } |
2518 | return (!err); |
2519 | } |
2520 | |
2521 | /* |
2522 | * Restore security descriptors from a file |
2523 | */ |
2524 | |
2525 | BOOL restore(FILE *fd) |
2526 | { |
2527 | static char attr[MAXATTRSZ]; |
2528 | char line[MAXFILENAME+25]; |
2529 | char fullname[MAXFILENAME+25]; |
2530 | SECURITY_DESCRIPTOR_RELATIVE *phead; |
2531 | int lth; |
2532 | int first; |
2533 | unsigned int pos; |
2534 | unsigned int size; |
2535 | unsigned char b; |
2536 | int c; |
2537 | int isdir; |
2538 | int mode; |
2539 | s32 key; |
2540 | BOOL isdump; |
2541 | unsigned int off; |
2542 | u32 v; |
2543 | u32 oldhash; |
2544 | int i; |
2545 | int count; |
2546 | int attrib; |
2547 | BOOL withattr; |
2548 | BOOL done; |
2549 | |
2550 | b = 0; |
2551 | pos = 0; |
2552 | size = 0; |
2553 | off = 0; |
2554 | done = FALSE; |
2555 | withattr = FALSE; |
2556 | oldhash = 0; |
2557 | key = 0; |
2558 | errors = 0; |
2559 | count = 0; |
2560 | fullname[0] = 0; |
2561 | attrib = INVALID_FILE_ATTRIBUTES; |
2562 | do { |
2563 | /* input a (partial) line without processing */ |
2564 | lth = 0; |
2565 | first = -1; |
2566 | do { |
2567 | c = getc(fd); |
2568 | if ((c != ' ') && (first < 0)) |
2569 | first = lth; |
2570 | if (c == EOF) |
2571 | done = TRUE; |
2572 | else |
2573 | if (c != '\r') |
2574 | line[lth++] = c; |
2575 | } while (!done && (c != '\n') && (lth < (MAXFILENAME + 24))); |
2576 | /* check whether this looks like an hexadecimal dump */ |
2577 | isdump = ishexdump(line, first, lth); |
2578 | if (isdump) off = getmsbhex(&line[first]); |
2579 | /* line is not an hexadecimal dump */ |
2580 | /* apply what we have in store */ |
2581 | if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { |
2582 | withattr = TRUE; |
2583 | if (opt_v >= 2) { |
2584 | printf(" Computed hash : 0x%08lx\n", |
2585 | (unsigned long)hash((le32*)attr, |
2586 | ntfs_attr_size(attr))); |
2587 | isdir = guess_dir(attr); |
2588 | printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); |
2589 | showheader(attr,4); |
2590 | showusid(attr,4); |
2591 | showgsid(attr,4); |
2592 | showdacl(attr,isdir,4); |
2593 | showsacl(attr,isdir,4); |
2594 | mode = linux_permissions(attr,isdir); |
2595 | printf("Interpreted Unix mode 0%03o\n",mode); |
2596 | } |
2597 | size = pos; |
2598 | pos = 0; |
2599 | } |
2600 | if (isdump && !off) |
2601 | pos = off; |
2602 | /* line looks like an hexadecimal dump */ |
2603 | /* decode it into attribute */ |
2604 | if (isdump && (off == pos)) { |
2605 | for (i=first+8; i<lth; i+=9) { |
2606 | v = getlsbhex(&line[i]); |
2607 | *(le32*)&attr[pos] = cpu_to_le32(v); |
2608 | pos += 4; |
2609 | } |
2610 | } |
2611 | /* display (full) current line unless dump or verbose */ |
2612 | if (!isdump || opt_v) { |
2613 | if(lth) printf("! "); |
2614 | for (i=0; i<lth; i++) { |
2615 | c = line[i]; |
2616 | putchar(c); |
2617 | } |
2618 | } |
2619 | while (!done && (c != '\n')) { |
2620 | c = getc(fd); |
2621 | if (c == EOF) |
2622 | done = TRUE; |
2623 | else |
2624 | if (!isdump || opt_v) |
2625 | putchar(c); |
2626 | } |
2627 | |
2628 | line[lth] = 0; |
2629 | while ((lth > 0) |
2630 | && ((line[lth-1] == '\n') || (line[lth-1] == '\r'))) |
2631 | line[--lth] = 0; |
2632 | if (!strncmp(line,"Computed hash : 0x",18)) |
2633 | oldhash = getmsbhex(&line[18]); |
2634 | if (!strncmp(line,"Security key : 0x",17)) |
2635 | key = getmsbhex(&line[17]); |
2636 | if (!strncmp(line,"Windows attrib : 0x",19)) |
2637 | attrib = getmsbhex(&line[19]); |
2638 | if (done |
2639 | || !strncmp(line,"File ",5) |
2640 | || !strncmp(line,"Directory ",10)) { |
2641 | /* |
2642 | * New file or directory (or end of file) : |
2643 | * apply attribute just collected |
2644 | * or apply attribute defined from current key |
2645 | */ |
2646 | |
2647 | if (withattr |
2648 | && oldhash |
2649 | && (hash((const le32*)attr,ntfs_attr_size(attr)) != oldhash)) { |
2650 | printf("** ACL rejected, its hash is not as expected\n"); |
2651 | errors++; |
2652 | } else |
2653 | if (fullname[0]) { |
2654 | phead = (SECURITY_DESCRIPTOR_RELATIVE*)attr; |
2655 | /* set the request for auto-inheritance */ |
2656 | if (phead->control & SE_DACL_AUTO_INHERITED) |
2657 | phead->control |= SE_DACL_AUTO_INHERIT_REQ; |
2658 | if (!applyattr(fullname,attr,withattr, |
2659 | attrib,key)) |
2660 | errors++; |
2661 | else |
2662 | count++; |
2663 | } |
2664 | /* save current file or directory name */ |
2665 | withattr = FALSE; |
2666 | key = 0; |
2667 | oldhash = 0; |
2668 | attrib = INVALID_FILE_ATTRIBUTES; |
2669 | if (!done) { |
2670 | #ifdef WIN32 |
2671 | if (!strncmp(line,"File ",5)) |
2672 | makeutf16(fullname,&line[5]); |
2673 | else |
2674 | makeutf16(fullname,&line[10]); |
2675 | #else |
2676 | if (!strncmp(line,"File ",5)) |
2677 | strcpy(fullname,&line[5]); |
2678 | else |
2679 | strcpy(fullname,&line[10]); |
2680 | #endif |
2681 | } |
2682 | } |
2683 | } while (!done); |
2684 | printf("%d ACLs have been applied\n",count); |
2685 | return (FALSE); |
2686 | } |
2687 | |
2688 | /* |
2689 | * Open the security API in rw mode for an ACL restoration |
2690 | */ |
2691 | |
2692 | #ifdef WIN32 |
2693 | #else |
2694 | BOOL dorestore(const char *volume, FILE *fd) |
2695 | { |
2696 | BOOL err; |
2697 | |
2698 | err = FALSE; |
2699 | if (!getuid()) { |
2700 | if (open_security_api()) { |
2701 | if (open_volume(volume,MS_NONE)) { |
2702 | if (restore(fd)) err = TRUE; |
2703 | close_volume(volume); |
2704 | } else { |
2705 | fprintf(stderr,"Could not open volume %s\n",volume); |
2706 | printerror(stderr); |
2707 | err = TRUE; |
2708 | } |
2709 | close_security_api(); |
2710 | } else { |
2711 | fprintf(stderr,"Could not open security API\n"); |
2712 | printerror(stderr); |
2713 | err = TRUE; |
2714 | } |
2715 | } else { |
2716 | fprintf(stderr,"Restore is only possible as root\n"); |
2717 | err = TRUE; |
2718 | } |
2719 | return (err); |
2720 | } |
2721 | #endif /* WIN32 */ |
2722 | |
2723 | #if POSIXACLS & SELFTESTS & !USESTUBS |
2724 | |
2725 | /* |
2726 | * Merge Posix ACL rights into an u32 (self test only) |
2727 | * |
2728 | * Result format : -----rwxrwxrwxrwxrwx---rwxrwxrwx |
2729 | * U1 U2 G1 G2 M o g w |
2730 | * |
2731 | * Only two users (U1, U2) and two groups (G1, G2) taken into account |
2732 | */ |
2733 | u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) |
2734 | { |
2735 | const struct POSIX_ACE *pxace; |
2736 | int i; |
2737 | int users; |
2738 | int groups; |
2739 | int first; |
2740 | int last; |
2741 | u32 rights; |
2742 | |
2743 | rights = 0; |
2744 | users = 0; |
2745 | groups = 0; |
2746 | if (def) { |
2747 | first = pxdesc->firstdef; |
2748 | last = pxdesc->firstdef + pxdesc->defcnt - 1; |
2749 | } else { |
2750 | first = 0; |
2751 | last = pxdesc->acccnt - 1; |
2752 | } |
2753 | pxace = pxdesc->acl.ace; |
2754 | for (i=first; i<=last; i++) { |
2755 | switch (pxace[i].tag) { |
2756 | case POSIX_ACL_USER_OBJ : |
2757 | rights |= (pxace[i].perms & 7) << 6; |
2758 | break; |
2759 | case POSIX_ACL_USER : |
2760 | if (users < 2) |
2761 | rights |= ((u32)pxace[i].perms & 7) << (24 - 3*users); |
2762 | users++; |
2763 | break; |
2764 | case POSIX_ACL_GROUP_OBJ : |
2765 | rights |= (pxace[i].perms & 7) << 3; |
2766 | break; |
2767 | case POSIX_ACL_GROUP : |
2768 | if (groups < 2) |
2769 | rights |= ((u32)pxace[i].perms & 7) << (18 - 3*groups); |
2770 | groups++; |
2771 | break; |
2772 | case POSIX_ACL_MASK : |
2773 | rights |= ((u32)pxace[i].perms & 7) << 12; |
2774 | break; |
2775 | case POSIX_ACL_OTHER : |
2776 | rights |= (pxace[i].perms & 7); |
2777 | break; |
2778 | default : |
2779 | break; |
2780 | } |
2781 | } |
2782 | return (rights); |
2783 | } |
2784 | |
2785 | void tryposix(struct POSIX_SECURITY *pxdesc) |
2786 | { |
2787 | le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
2788 | { |
2789 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
2790 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
2791 | cpu_to_le32(AUTH3), cpu_to_le32(1016) |
2792 | } ; |
2793 | le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
2794 | { |
2795 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
2796 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
2797 | cpu_to_le32(AUTH3), cpu_to_le32(513) |
2798 | } ; |
2799 | |
2800 | char *attr; |
2801 | BOOL isdir; |
2802 | mode_t mode; |
2803 | struct POSIX_SECURITY *newpxdesc; |
2804 | struct POSIX_SECURITY *oldpxdesc; |
2805 | static char *oldattr = (char*)NULL; |
2806 | |
2807 | isdir = FALSE; |
2808 | if (oldattr) { |
2809 | oldpxdesc = linux_permissions_posix(oldattr, isdir); |
2810 | newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); |
2811 | if (!newpxdesc) |
2812 | newpxdesc = pxdesc; |
2813 | free(oldpxdesc); |
2814 | if (opt_v) { |
2815 | printf("merged descriptors :\n"); |
2816 | showposix(newpxdesc); |
2817 | } |
2818 | } else |
2819 | newpxdesc = pxdesc; |
2820 | attr = ntfs_build_descr_posix(context.mapping,newpxdesc, |
2821 | isdir,(SID*)owner_sid,(SID*)group_sid); |
2822 | if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { |
2823 | if (opt_v) |
2824 | hexdump(attr,ntfs_attr_size(attr),8); |
2825 | if (opt_v >= 2) { |
2826 | showheader(attr,4); |
2827 | showusid(attr,4); |
2828 | showgsid(attr,4); |
2829 | showdacl(attr,isdir,4); |
2830 | showsacl(attr,isdir,4); |
2831 | mode = linux_permissions(attr,isdir); |
2832 | printf("Interpreted Unix mode 0%03o\n",mode); |
2833 | printf("Interpreted back Posix descriptor :\n"); |
2834 | newpxdesc = linux_permissions_posix(attr,isdir); |
2835 | showposix(newpxdesc); |
2836 | free(newpxdesc); |
2837 | } |
2838 | if (oldattr) free(oldattr); |
2839 | oldattr = attr; |
2840 | } |
2841 | } |
2842 | |
2843 | static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, |
2844 | struct POSIX_SECURITY *pxdesc2) |
2845 | { |
2846 | BOOL same; |
2847 | int i; |
2848 | |
2849 | same = pxdesc1 |
2850 | && pxdesc2 |
2851 | && (pxdesc1->mode == pxdesc2->mode) |
2852 | && (pxdesc1->acccnt == pxdesc2->acccnt) |
2853 | && (pxdesc1->defcnt == pxdesc2->defcnt) |
2854 | && (pxdesc1->firstdef == pxdesc2->firstdef) |
2855 | && (pxdesc1->tagsset == pxdesc2->tagsset) |
2856 | && (pxdesc1->acl.version == pxdesc2->acl.version) |
2857 | && (pxdesc1->acl.flags == pxdesc2->acl.flags); |
2858 | i = 0; |
2859 | while (same && (i < pxdesc1->acccnt)) { |
2860 | same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) |
2861 | && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) |
2862 | && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); |
2863 | i++; |
2864 | } |
2865 | i = pxdesc1->firstdef; |
2866 | while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) { |
2867 | same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) |
2868 | && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) |
2869 | && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); |
2870 | i++; |
2871 | } |
2872 | return (same); |
2873 | } |
2874 | |
2875 | #endif /* POSIXACLS & SELFTESTS & !USESTUBS */ |
2876 | |
2877 | #if SELFTESTS & !USESTUBS |
2878 | |
2879 | /* |
2880 | * Build a dummy security descriptor |
2881 | * returns descriptor in allocated memory, must free() after use |
2882 | */ |
2883 | |
2884 | static char *build_dummy_descr(BOOL isdir __attribute__((unused)), |
2885 | const SID *usid, const SID *gsid, |
2886 | int cnt, |
2887 | /* seq of int allow, SID *sid, int flags, u32 mask */ |
2888 | ...) |
2889 | { |
2890 | char *attr; |
2891 | int attrsz; |
2892 | SECURITY_DESCRIPTOR_RELATIVE *pnhead; |
2893 | ACL *pacl; |
2894 | ACCESS_ALLOWED_ACE *pace; |
2895 | va_list ap; |
2896 | const SID *sid; |
2897 | u32 umask; |
2898 | le32 mask; |
2899 | int flags; |
2900 | BOOL allow; |
2901 | int pos; |
2902 | int usidsz; |
2903 | int gsidsz; |
2904 | int sidsz; |
2905 | int aclsz; |
2906 | int i; |
2907 | |
2908 | if (usid) |
2909 | usidsz = ntfs_sid_size(usid); |
2910 | else |
2911 | usidsz = 0; |
2912 | if (gsid) |
2913 | gsidsz = ntfs_sid_size(gsid); |
2914 | else |
2915 | gsidsz = 0; |
2916 | |
2917 | |
2918 | /* allocate enough space for the new security attribute */ |
2919 | attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ |
2920 | + usidsz + gsidsz /* usid and gsid */ |
2921 | + sizeof(ACL) /* acl header */ |
2922 | + cnt*40; |
2923 | |
2924 | attr = (char*)ntfs_malloc(attrsz); |
2925 | if (attr) { |
2926 | /* build the main header part */ |
2927 | pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) attr; |
2928 | pnhead->revision = SECURITY_DESCRIPTOR_REVISION; |
2929 | pnhead->alignment = 0; |
2930 | /* |
2931 | * The flag SE_DACL_PROTECTED prevents the ACL |
2932 | * to be changed in an inheritance after creation |
2933 | */ |
2934 | pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED |
2935 | | SE_SELF_RELATIVE; |
2936 | /* |
2937 | * Windows prefers ACL first, do the same to |
2938 | * get the same hash value and avoid duplication |
2939 | */ |
2940 | /* build the ACL header */ |
2941 | pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); |
2942 | pacl = (ACL*)&attr[pos]; |
2943 | pacl->revision = ACL_REVISION; |
2944 | pacl->alignment1 = 0; |
2945 | pacl->size = cpu_to_le16(0); /* fixed later */ |
2946 | pacl->ace_count = cpu_to_le16(cnt); |
2947 | pacl->alignment2 = cpu_to_le16(0); |
2948 | |
2949 | /* enter the ACEs */ |
2950 | |
2951 | pos += sizeof(ACL); |
2952 | aclsz = sizeof(ACL); |
2953 | va_start(ap,cnt); |
2954 | for (i=0; i<cnt; i++) { |
2955 | pace = (ACCESS_ALLOWED_ACE*)&attr[pos]; |
2956 | allow = va_arg(ap,int); |
2957 | sid = va_arg(ap,SID*); |
2958 | flags = va_arg(ap,int); |
2959 | umask = va_arg(ap,u32); |
2960 | mask = cpu_to_le32(umask); |
2961 | sidsz = ntfs_sid_size(sid); |
2962 | pace->type = (allow ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE); |
2963 | pace->flags = flags; |
2964 | pace->size = cpu_to_le16(sidsz + 8); |
2965 | pace->mask = mask; |
2966 | memcpy(&pace->sid,sid,sidsz); |
2967 | aclsz += sidsz + 8; |
2968 | pos += sidsz + 8; |
2969 | } |
2970 | va_end(ap); |
2971 | |
2972 | /* append usid and gsid if defined */ |
2973 | /* positions of ACL, USID and GSID into header */ |
2974 | pnhead->owner = cpu_to_le32(0); |
2975 | pnhead->group = cpu_to_le32(0); |
2976 | if (usid) { |
2977 | memcpy(&attr[pos], usid, usidsz); |
2978 | pnhead->owner = cpu_to_le32(pos); |
2979 | } |
2980 | if (gsid) { |
2981 | memcpy(&attr[pos + usidsz], gsid, gsidsz); |
2982 | pnhead->group = cpu_to_le32(pos + usidsz); |
2983 | } |
2984 | /* positions of DACL and SACL into header */ |
2985 | pnhead->sacl = cpu_to_le32(0); |
2986 | if (cnt) { |
2987 | pacl->size = cpu_to_le16(aclsz); |
2988 | pnhead->dacl = |
2989 | cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); |
2990 | } else |
2991 | pnhead->dacl = cpu_to_le32(0); |
2992 | if (!ntfs_valid_descr(attr,pos+usidsz+gsidsz)) { |
2993 | printf("** Bad sample descriptor\n"); |
2994 | free(attr); |
2995 | attr = (char*)NULL; |
2996 | errors++; |
2997 | } |
2998 | } else |
2999 | errno = ENOMEM; |
3000 | return (attr); |
3001 | } |
3002 | |
3003 | /* |
3004 | * Check a few samples with special conditions |
3005 | */ |
3006 | |
3007 | void check_samples() |
3008 | { |
3009 | char *descr = (char*)NULL; |
3010 | BOOL isdir = FALSE; |
3011 | mode_t perms; |
3012 | mode_t expect = 0; |
3013 | int cnt; |
3014 | u32 expectacc; |
3015 | u32 expectdef; |
3016 | #if POSIXACLS |
3017 | u32 accrights; |
3018 | u32 defrights; |
3019 | mode_t mixmode; |
3020 | struct POSIX_SECURITY *pxdesc; |
3021 | struct POSIX_SECURITY *pxsample; |
3022 | const char *txsample; |
3023 | #endif |
3024 | le32 owner1[] = /* S-1-5-21-1833069642-4243175381-1340018762-1003 */ |
3025 | { |
3026 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3027 | cpu_to_le32(1833069642), cpu_to_le32(4243175381), |
3028 | cpu_to_le32(1340018762), cpu_to_le32(1003) |
3029 | } ; |
3030 | le32 group1[] = /* S-1-5-21-1833069642-4243175381-1340018762-513 */ |
3031 | { |
3032 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3033 | cpu_to_le32(1833069642), cpu_to_le32(4243175381), |
3034 | cpu_to_le32(1340018762), cpu_to_le32(513) |
3035 | } ; |
3036 | le32 group2[] = /* S-1-5-21-1607551490-981732888-1819828000-513 */ |
3037 | { |
3038 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3039 | cpu_to_le32(1607551490), cpu_to_le32(981732888), |
3040 | cpu_to_le32(1819828000), cpu_to_le32(513) |
3041 | } ; |
3042 | le32 owner3[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
3043 | { |
3044 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3045 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
3046 | cpu_to_le32(AUTH3), cpu_to_le32(1016) |
3047 | } ; |
3048 | le32 group3[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
3049 | { |
3050 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3051 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
3052 | cpu_to_le32(AUTH3), cpu_to_le32(513) |
3053 | } ; |
3054 | |
3055 | #if POSIXACLS |
3056 | struct { |
3057 | struct POSIX_SECURITY head; |
3058 | struct POSIX_ACE ace[4]; |
3059 | } sampletry1 = |
3060 | { |
3061 | { 0645, 4, 0, 4, 0x35, |
3062 | { POSIX_VERSION, 0, 0 } |
3063 | }, |
3064 | { |
3065 | { 1, 6, -1 }, |
3066 | { 4, 5, -1 }, |
3067 | { 16, 4, -1 }, |
3068 | { 32, 5, -1 } |
3069 | } |
3070 | } ; |
3071 | |
3072 | struct { |
3073 | struct POSIX_SECURITY head; |
3074 | struct POSIX_ACE ace[6]; |
3075 | } sampletry3 = |
3076 | { |
3077 | { 0100, 6, 0, 6, 0x3f, |
3078 | { POSIX_VERSION, 0, 0 } |
3079 | }, |
3080 | { |
3081 | { 1, 1, -1 }, |
3082 | { 2, 3, 1000 }, |
3083 | { 4, 1, -1 }, |
3084 | { 8, 3, 1002 }, |
3085 | { 16, 0, -1 }, |
3086 | { 32, 0, -1 } |
3087 | } |
3088 | } ; |
3089 | |
3090 | struct { |
3091 | struct POSIX_SECURITY head; |
3092 | struct POSIX_ACE ace[8]; |
3093 | } sampletry4 = |
3094 | { |
3095 | { 0140, 8, 0, 8, 0x3f, |
3096 | { POSIX_VERSION, 0, 0 } |
3097 | }, |
3098 | { |
3099 | { 1, 1, -1 }, |
3100 | { 2, 3, 516 }, |
3101 | { 2, 6, 1000 }, |
3102 | { 4, 1, -1 }, |
3103 | { 8, 6, 500 }, |
3104 | { 8, 3, 1002 }, |
3105 | { 16, 4, -1 }, |
3106 | { 32, 0, -1 } |
3107 | } |
3108 | } ; |
3109 | |
3110 | struct { |
3111 | struct POSIX_SECURITY head; |
3112 | struct POSIX_ACE ace[6]; |
3113 | } sampletry5 = |
3114 | { |
3115 | { 0454, 6, 0, 6, 0x3f, |
3116 | { POSIX_VERSION, 0, 0 } |
3117 | }, |
3118 | { |
3119 | { 1, 4, -1 }, |
3120 | { 2, 5, 516 }, |
3121 | { 4, 4, -1 }, |
3122 | { 8, 6, 500 }, |
3123 | { 16, 5, -1 }, |
3124 | { 32, 4, -1 } |
3125 | } |
3126 | } ; |
3127 | |
3128 | struct { |
3129 | struct POSIX_SECURITY head; |
3130 | struct POSIX_ACE ace[8]; |
3131 | } sampletry6 = |
3132 | { |
3133 | { 0332, 8, 0, 8, 0x3f, |
3134 | { POSIX_VERSION, 0, 0 } |
3135 | }, |
3136 | { |
3137 | { 1, 3, -1 }, |
3138 | { 2, 1, 0 }, |
3139 | { 2, 2, 1000 }, |
3140 | { 4, 6, -1 }, |
3141 | { 8, 4, 0 }, |
3142 | { 8, 5, 1002 }, |
3143 | { 16, 3, -1 }, |
3144 | { 32, 2, -1 } |
3145 | } |
3146 | } ; |
3147 | |
3148 | struct { |
3149 | struct POSIX_SECURITY head; |
3150 | struct POSIX_ACE ace[4]; |
3151 | } sampletry8 = |
3152 | { |
3153 | { 0677, 4, 0, 4, 0x35, |
3154 | { POSIX_VERSION, 0, 0 } |
3155 | }, |
3156 | { |
3157 | { 1, 6, -1 }, |
3158 | { 4, 7, -1 }, |
3159 | { 16, 7, -1 }, |
3160 | { 32, 7, -1 } |
3161 | } |
3162 | } ; |
3163 | |
3164 | #endif /* POSIXACLS */ |
3165 | |
3166 | |
3167 | #if POSIXACLS |
3168 | for (cnt=1; cnt<=8; cnt++) { |
3169 | switch (cnt) { |
3170 | case 1 : |
3171 | pxsample = &sampletry1.head; |
3172 | txsample = "sampletry1-a"; |
3173 | isdir = FALSE; |
3174 | descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, |
3175 | isdir, (const SID*)owner3, (const SID*)group3); |
3176 | break; |
3177 | case 2 : |
3178 | pxsample = &sampletry1.head; |
3179 | txsample = "sampletry1-b"; |
3180 | isdir = FALSE; |
3181 | descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, |
3182 | isdir, (const SID*)adminsid, (const SID*)group3); |
3183 | break; |
3184 | case 3 : |
3185 | isdir = FALSE; |
3186 | pxsample = &sampletry3.head; |
3187 | txsample = "sampletry3"; |
3188 | descr = ntfs_build_descr_posix(context.mapping,pxsample, |
3189 | isdir, (const SID*)group3, (const SID*)group3); |
3190 | break; |
3191 | case 4 : |
3192 | isdir = FALSE; |
3193 | pxsample = &sampletry4.head; |
3194 | txsample = "sampletry4"; |
3195 | descr = ntfs_build_descr_posix(context.mapping,pxsample, |
3196 | isdir, (const SID*)owner3, (const SID*)group3); |
3197 | break; |
3198 | case 5 : |
3199 | isdir = FALSE; |
3200 | pxsample = &sampletry5.head; |
3201 | txsample = "sampletry5"; |
3202 | descr = ntfs_build_descr_posix(context.mapping,pxsample, |
3203 | isdir, (const SID*)owner3, (const SID*)group3); |
3204 | break; |
3205 | case 6 : |
3206 | isdir = FALSE; |
3207 | pxsample = &sampletry6.head; |
3208 | txsample = "sampletry6-a"; |
3209 | descr = ntfs_build_descr_posix(context.mapping,pxsample, |
3210 | isdir, (const SID*)owner3, (const SID*)group3); |
3211 | break; |
3212 | case 7 : |
3213 | isdir = FALSE; |
3214 | pxsample = &sampletry6.head; |
3215 | txsample = "sampletry6-b"; |
3216 | descr = ntfs_build_descr_posix(context.mapping,pxsample, |
3217 | isdir, (const SID*)adminsid, (const SID*)adminsid); |
3218 | break; |
3219 | case 8 : |
3220 | pxsample = &sampletry8.head; |
3221 | txsample = "sampletry8"; |
3222 | isdir = FALSE; |
3223 | descr = ntfs_build_descr_posix(context.mapping,&sampletry8.head, |
3224 | isdir, (const SID*)owner3, (const SID*)group3); |
3225 | break; |
3226 | default : |
3227 | pxsample = (struct POSIX_SECURITY*)NULL; |
3228 | txsample = (const char*)NULL; |
3229 | } |
3230 | /* check we get original back */ |
3231 | if (descr) |
3232 | pxdesc = linux_permissions_posix(descr, isdir); |
3233 | else |
3234 | pxdesc = (struct POSIX_SECURITY*)NULL; |
3235 | if (!descr || !pxdesc || !same_posix(pxsample,pxdesc)) { |
3236 | printf("** Error in %s\n",txsample); |
3237 | showposix(pxsample); |
3238 | showall(descr,0); |
3239 | showposix(pxdesc); |
3240 | errors++; |
3241 | } |
3242 | free(descr); |
3243 | free(pxdesc); |
3244 | } |
3245 | |
3246 | #endif /* POSIXACLS */ |
3247 | |
3248 | |
3249 | /* |
3250 | * Check a few samples built by Windows, |
3251 | * which cannot be generated by Linux |
3252 | */ |
3253 | |
3254 | for (cnt=1; cnt<=8; cnt++) { |
3255 | switch(cnt) { |
3256 | case 1 : /* hp/tmp */ |
3257 | isdir = TRUE; |
3258 | descr = build_dummy_descr(isdir, |
3259 | (const SID*)owner1, (const SID*)group1, |
3260 | 1, |
3261 | (int)TRUE, worldsid, (int)0x3, (u32)0x1f01ff); |
3262 | expectacc = expect = 0777; |
3263 | expectdef = 0; |
3264 | break; |
3265 | case 2 : /* swsetup */ |
3266 | isdir = TRUE; |
3267 | descr = build_dummy_descr(isdir, adminsid, (const SID*)group2, |
3268 | 2, |
3269 | (int)TRUE, worldsid, (int)0x0, (u32)0x1f01ff, |
3270 | (int)TRUE, worldsid, (int)0xb, (u32)0x1f01ff); |
3271 | expectacc = expect = 0777; |
3272 | expectdef = 0777; |
3273 | break; |
3274 | case 3 : /* Dr Watson */ |
3275 | isdir = TRUE; |
3276 | descr = build_dummy_descr(isdir, (const SID*)owner3, (const SID*)group3, |
3277 | 0); |
3278 | expectacc = expect = 0700; |
3279 | expectdef = 0; |
3280 | break; |
3281 | case 4 : |
3282 | isdir = FALSE; |
3283 | descr = build_dummy_descr(isdir, |
3284 | (const SID*)owner3, (const SID*)group3, |
3285 | 4, |
3286 | (int)TRUE, (const SID*)owner3, 0, |
3287 | le32_to_cpu(FILE_READ_DATA | OWNER_RIGHTS), |
3288 | (int)TRUE, (const SID*)group3, 0, |
3289 | le32_to_cpu(FILE_WRITE_DATA), |
3290 | (int)TRUE, (const SID*)group2, 0, |
3291 | le32_to_cpu(FILE_WRITE_DATA | FILE_READ_DATA), |
3292 | (int)TRUE, (const SID*)worldsid, 0, |
3293 | le32_to_cpu(FILE_EXECUTE)); |
3294 | expect = 0731; |
3295 | expectacc = 07070731; |
3296 | expectdef = 0; |
3297 | break; |
3298 | case 5 : /* Vista/JP */ |
3299 | isdir = TRUE; |
3300 | descr = build_dummy_descr(isdir, systemsid, systemsid, |
3301 | 6, |
3302 | (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
3303 | (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
3304 | (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
3305 | (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
3306 | (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
3307 | (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
3308 | expectacc = expect = 0700; |
3309 | expectdef = 0700; |
3310 | break; |
3311 | case 6 : /* Vista/JP2 */ |
3312 | isdir = TRUE; |
3313 | descr = build_dummy_descr(isdir, systemsid, systemsid, |
3314 | 7, |
3315 | (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
3316 | (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
3317 | (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
3318 | (int)TRUE, owner1, (int)0xb, (u32)0x1f01ff, |
3319 | (int)TRUE, systemsid, (int)0xb, (u32)0x1f01ff, |
3320 | (int)TRUE, adminsid, (int)0xb, (u32)0x1f01ff, |
3321 | (int)TRUE, owner3, (int)0x3, (u32)0x1200a9); |
3322 | expectacc = 0500070700; |
3323 | expectdef = 0700; |
3324 | expect = 0700; |
3325 | break; |
3326 | case 7 : /* WinXP/JP */ |
3327 | isdir = TRUE; |
3328 | descr = build_dummy_descr(isdir, adminsid, systemsid, |
3329 | 6, |
3330 | (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
3331 | (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
3332 | (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
3333 | (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
3334 | (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
3335 | (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
3336 | expectacc = expect = 0700; |
3337 | expectdef = 0700; |
3338 | break; |
3339 | case 8 : /* WinXP/JP2 */ |
3340 | isdir = TRUE; |
3341 | descr = build_dummy_descr(isdir, adminsid, systemsid, |
3342 | 6, |
3343 | (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
3344 | (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
3345 | (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
3346 | (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
3347 | (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
3348 | (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
3349 | expectacc = expect = 0700; |
3350 | expectdef = 0700; |
3351 | break; |
3352 | default : |
3353 | expectacc = expectdef = 0; |
3354 | break; |
3355 | } |
3356 | if (descr) { |
3357 | perms = linux_permissions(descr, isdir); |
3358 | if (perms != expect) { |
3359 | printf("** Error in sample %d, perms 0%03o expected 0%03o\n", |
3360 | cnt,perms,expect); |
3361 | showall(descr,0); |
3362 | errors++; |
3363 | } else { |
3364 | #if POSIXACLS |
3365 | pxdesc = linux_permissions_posix(descr, isdir); |
3366 | if (pxdesc) { |
3367 | accrights = merge_rights(pxdesc,FALSE); |
3368 | defrights = merge_rights(pxdesc,TRUE); |
3369 | if (!(pxdesc->tagsset & ~(POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER))) |
3370 | mixmode = expect; |
3371 | else |
3372 | mixmode = (expect & 07707) | ((accrights >> 9) & 070); |
3373 | if ((pxdesc->mode != mixmode) |
3374 | || (accrights != expectacc) |
3375 | || (defrights != expectdef)) { |
3376 | printf("** Error in sample %d : mode %03o expected 0%03o\n", |
3377 | cnt,pxdesc->mode,mixmode); |
3378 | printf(" Posix access rights 0%03lo expected 0%03lo\n", |
3379 | (long)accrights,(long)expectacc); |
3380 | printf(" default rights 0%03lo expected 0%03lo\n", |
3381 | (long)defrights,(long)expectdef); |
3382 | showall(descr,0); |
3383 | showposix(pxdesc); |
3384 | exit(1); |
3385 | } |
3386 | free(pxdesc); |
3387 | } |
3388 | #endif |
3389 | } |
3390 | free(descr); |
3391 | } |
3392 | } |
3393 | } |
3394 | |
3395 | |
3396 | /* |
3397 | * Check whether any basic permission setting is interpreted |
3398 | * back exactly as set |
3399 | */ |
3400 | |
3401 | void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) |
3402 | { |
3403 | char *attr; |
3404 | mode_t perm; |
3405 | mode_t gotback; |
3406 | u32 count; |
3407 | u32 acecount; |
3408 | u32 globhash; |
3409 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3410 | const ACL *pacl; |
3411 | enum { ERRNO, |
3412 | ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ |
3413 | ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ |
3414 | } err; |
3415 | u32 expectcnt[] = { |
3416 | 27800, 31896, |
3417 | 24064, 28160, |
3418 | 24064, 28160, |
3419 | 24064, 28160, |
3420 | 25416, 29512 |
3421 | } ; |
3422 | u32 expecthash[] = { |
3423 | 0x8f80865b, 0x7bc7960, |
3424 | 0x8fd9ecfe, 0xddd4db0, |
3425 | 0xa8b07400, 0xa189c20, |
3426 | 0xc5689a00, 0xb6c09000, |
3427 | 0x94bfb419, 0xa4311791 |
3428 | } ; |
3429 | #if POSIXACLS |
3430 | struct POSIX_SECURITY *pxdesc; |
3431 | char *pxattr; |
3432 | u32 pxcount; |
3433 | u32 pxacecount; |
3434 | u32 pxglobhash; |
3435 | #endif |
3436 | |
3437 | count = 0; |
3438 | acecount = 0; |
3439 | globhash = 0; |
3440 | #if POSIXACLS |
3441 | pxcount = 0; |
3442 | pxacecount = 0; |
3443 | pxglobhash = 0; |
3444 | #endif |
3445 | for (perm=0; (perm<=07777) && (errors < 10); perm++) { |
3446 | err = ERRNO; |
3447 | /* file owned by plain user and group */ |
3448 | attr = ntfs_build_descr(perm,isdir,owner,(const SID*)group); |
3449 | if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { |
3450 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
3451 | pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; |
3452 | acecount += le16_to_cpu(pacl->ace_count); |
3453 | globhash += hash((const le32*)attr,ntfs_attr_size(attr)); |
3454 | count++; |
3455 | #if POSIXACLS |
3456 | /* |
3457 | * Build a NTFS ACL from a mode, and |
3458 | * decode to a Posix ACL, expecting to |
3459 | * get the original mode back. |
3460 | */ |
3461 | pxdesc = linux_permissions_posix(attr, isdir); |
3462 | if (!pxdesc || (pxdesc->mode != perm)) { |
3463 | err = ERRAP; |
3464 | if (pxdesc) |
3465 | gotback = pxdesc->mode; |
3466 | else |
3467 | gotback = 0; |
3468 | } else { |
3469 | /* |
3470 | * Build a NTFS ACL from the Posix ACL, expecting to |
3471 | * get exactly the same NTFS ACL, then decode to a |
3472 | * mode, expecting to get the original mode back. |
3473 | */ |
3474 | pxattr = ntfs_build_descr_posix(context.mapping, |
3475 | pxdesc,isdir,owner, |
3476 | (const SID*)group); |
3477 | if (pxattr && !memcmp(pxattr,attr, |
3478 | ntfs_attr_size(attr))) { |
3479 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
3480 | pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; |
3481 | pxacecount += le16_to_cpu(pacl->ace_count); |
3482 | pxglobhash += hash((const le32*)attr,ntfs_attr_size(attr)); |
3483 | pxcount++; |
3484 | gotback = linux_permissions(pxattr, isdir); |
3485 | if (gotback != perm) |
3486 | err = ERRAM; |
3487 | else |
3488 | free(pxattr); |
3489 | } else |
3490 | err = ERRPA; |
3491 | free(attr); |
3492 | } |
3493 | free(pxdesc); |
3494 | #else |
3495 | gotback = linux_permissions(attr, isdir); |
3496 | if (gotback != perm) |
3497 | err = ERRAM; |
3498 | else |
3499 | free(attr); |
3500 | #endif /* POSIXACLS */ |
3501 | } else |
3502 | err = ERRMA; |
3503 | |
3504 | switch (err) { |
3505 | case ERRMA : |
3506 | printf("** no or wrong permission settings " |
3507 | "for kind %d perm %03o\n",kind,perm); |
3508 | if (attr && opt_v) |
3509 | hexdump(attr,ntfs_attr_size(attr),8); |
3510 | if (attr && (opt_v >= 2)) { |
3511 | showheader(attr,4); |
3512 | showusid(attr,4); |
3513 | showgsid(attr,4); |
3514 | showdacl(attr,isdir,4); |
3515 | showsacl(attr,isdir,4); |
3516 | } |
3517 | errors++; |
3518 | break; |
3519 | case ERRPA : |
3520 | printf("** no or wrong permission settings from PX " |
3521 | "for kind %d perm %03o\n",kind,perm); |
3522 | errors++; |
3523 | break; |
3524 | #if POSIXACLS |
3525 | case ERRAM : |
3526 | printf("** wrong permission settings, " |
3527 | "kind %d perm 0%03o, gotback %03o\n", |
3528 | kind, perm, gotback); |
3529 | if (opt_v) |
3530 | hexdump(pxattr,ntfs_attr_size(pxattr),8); |
3531 | if (opt_v >= 2) { |
3532 | showheader(pxattr,4); |
3533 | showusid(pxattr,4); |
3534 | showgsid(pxattr,4); |
3535 | showdacl(pxattr,isdir,4); |
3536 | showsacl(pxattr,isdir,4); |
3537 | } |
3538 | errors++; |
3539 | break; |
3540 | case ERRAP : |
3541 | /* continued */ |
3542 | #else |
3543 | case ERRAM : |
3544 | case ERRAP : |
3545 | #endif /* POSIXACLS */ |
3546 | printf("** wrong permission settings, " |
3547 | "kind %d perm 0%03o, gotback %03o\n", |
3548 | kind, perm, gotback); |
3549 | if (opt_v) |
3550 | hexdump(attr,ntfs_attr_size(attr),8); |
3551 | if (opt_v >= 2) { |
3552 | showheader(attr,4); |
3553 | showusid(attr,4); |
3554 | showgsid(attr,4); |
3555 | showdacl(attr,isdir,4); |
3556 | showsacl(attr,isdir,4); |
3557 | } |
3558 | errors++; |
3559 | free(attr); |
3560 | break; |
3561 | default : |
3562 | break; |
3563 | } |
3564 | } |
3565 | printf("%lu ACLs built from mode, %lu ACE built, mean count %lu.%02lu\n", |
3566 | (unsigned long)count,(unsigned long)acecount, |
3567 | (unsigned long)acecount/count,acecount*100L/count%100L); |
3568 | if (acecount != expectcnt[kind]) { |
3569 | printf("** Error : expected ACE count %lu\n", |
3570 | (unsigned long)expectcnt[kind]); |
3571 | errors++; |
3572 | } |
3573 | if (globhash != expecthash[kind]) { |
3574 | printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
3575 | (unsigned long)globhash, (unsigned long)expecthash[kind]); |
3576 | errors++; |
3577 | } |
3578 | #if POSIXACLS |
3579 | printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", |
3580 | (unsigned long)pxcount,(unsigned long)pxacecount, |
3581 | (unsigned long)pxacecount/pxcount,pxacecount*100L/pxcount%100L); |
3582 | if (pxacecount != expectcnt[kind]) { |
3583 | printf("** Error : expected ACE count %lu\n", |
3584 | (unsigned long)expectcnt[kind]); |
3585 | errors++; |
3586 | } |
3587 | if (pxglobhash != expecthash[kind]) { |
3588 | printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
3589 | (unsigned long)pxglobhash, (unsigned long)expecthash[kind]); |
3590 | errors++; |
3591 | } |
3592 | #endif /* POSIXACLS */ |
3593 | } |
3594 | |
3595 | #if POSIXACLS |
3596 | |
3597 | /* |
3598 | * Check whether Posix ACL settings are interpreted |
3599 | * back exactly as set |
3600 | */ |
3601 | |
3602 | void posixtest(int kind, BOOL isdir, |
3603 | const SID *owner, const SID *group) |
3604 | { |
3605 | struct POSIX_SECURITY *pxdesc; |
3606 | struct { |
3607 | struct POSIX_SECURITY pxdesc; |
3608 | struct POSIX_ACE aces[10]; |
3609 | } desc; |
3610 | int ownobj; |
3611 | int grpobj; |
3612 | int usr; |
3613 | int grp; |
3614 | int wrld; |
3615 | int mask; |
3616 | int mindes, maxdes; |
3617 | int minmsk, maxmsk; |
3618 | char *pxattr; |
3619 | u32 count; |
3620 | u32 acecount; |
3621 | u32 globhash; |
3622 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
3623 | const ACL *pacl; |
3624 | struct POSIX_SECURITY *gotback; |
3625 | enum { ERRNO, |
3626 | ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ |
3627 | ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ |
3628 | } err; |
3629 | u32 expectcnt[] = { |
3630 | #ifdef STSC |
3631 | 32400, 34992, |
3632 | 25920, 28512, |
3633 | 25920, 28512, |
3634 | 25920, 28512, |
3635 | 26460, 29052, |
3636 | 0, 0, |
3637 | 0, 0, |
3638 | 0, 0, |
3639 | 24516, 27108, |
3640 | 20736, 23328, |
3641 | 20736, 23328, |
3642 | 20736, 23328, |
3643 | 21060, 23652, |
3644 | #else |
3645 | 252720, 273456, |
3646 | 199584, 220320, |
3647 | 199584, 220320, |
3648 | 199584, 220320, |
3649 | 203904, 224640, |
3650 | 0, 0, |
3651 | 0, 0, |
3652 | 0, 0, |
3653 | 196452, 217188, |
3654 | 165888, 186624, |
3655 | 165888, 186624, |
3656 | 165888, 186624, |
3657 | 168480, 189216, |
3658 | #endif |
3659 | 0, 0, |
3660 | 0, 0, |
3661 | 0, 0, |
3662 | 16368, 18672, |
3663 | 0, 0, |
3664 | 13824, 0, |
3665 | 0, 0, |
3666 | 14640, 0 |
3667 | } ; |
3668 | u32 expecthash[] = { |
3669 | #ifdef STSC |
3670 | 0xf9f82115, 0x40666647, |
3671 | 0xde826d30, 0xa181b660, |
3672 | 0x952d4500, 0x8ac49450, |
3673 | 0xf80acee0, 0xbd9ec6c0, |
3674 | 0xfe09b868, 0xde24e84d, |
3675 | 0, 0, |
3676 | 0, 0, |
3677 | 0, 0, |
3678 | 0x2381438d, 0x3ab42dc6, |
3679 | 0x7cccf6f8, 0x108ad430, |
3680 | 0x5e448840, 0x83ab6c40, |
3681 | 0x9b037100, 0x8f7c3b40, |
3682 | 0x04a359dc, 0xa4619609, |
3683 | #else |
3684 | 0x1808a6cd, 0xd82f7c60, |
3685 | 0x5ad29e85, 0x518c7620, |
3686 | 0x188ce270, 0x7e44e590, |
3687 | 0x48a64800, 0x5bdf0030, |
3688 | 0x1c64aec6, 0x8b0168fa, |
3689 | 0, 0, |
3690 | 0, 0, |
3691 | 0, 0, |
3692 | 0x169fb80e, 0x382d9a59, |
3693 | 0xf9c28164, 0x1855d352, |
3694 | 0xf9685700, 0x44d16700, |
3695 | 0x587ebe90, 0xf7c51480, |
3696 | 0x2cb1b518, 0x52408df6, |
3697 | #endif |
3698 | 0, 0, |
3699 | 0, 0, |
3700 | 0, 0, |
3701 | 0x905f2e38, 0xd40c22f0, |
3702 | 0, 0, |
3703 | 0xdd76da00, 0, |
3704 | 0, 0, |
3705 | 0x718e34a0, 0 |
3706 | }; |
3707 | |
3708 | count = 0; |
3709 | acecount = 0; |
3710 | globhash = 0; |
3711 | /* fill headers */ |
3712 | pxdesc = &desc.pxdesc; |
3713 | pxdesc->mode = 0; |
3714 | pxdesc->defcnt = 0; |
3715 | if (kind & 32) { |
3716 | pxdesc->acccnt = 4; |
3717 | pxdesc->firstdef = 4; |
3718 | pxdesc->tagsset = 0x35; |
3719 | } else { |
3720 | pxdesc->acccnt = 6;; |
3721 | pxdesc->firstdef = 6; |
3722 | pxdesc->tagsset = 0x3f; |
3723 | } |
3724 | pxdesc->acl.version = POSIX_VERSION; |
3725 | pxdesc->acl.flags = 0; |
3726 | pxdesc->acl.filler = 0; |
3727 | /* prefill aces */ |
3728 | pxdesc->acl.ace[0].tag = POSIX_ACL_USER_OBJ; |
3729 | pxdesc->acl.ace[0].id = -1; |
3730 | if (kind & 32) { |
3731 | pxdesc->acl.ace[1].tag = POSIX_ACL_GROUP_OBJ; |
3732 | pxdesc->acl.ace[1].id = -1; |
3733 | pxdesc->acl.ace[2].tag = POSIX_ACL_MASK; |
3734 | pxdesc->acl.ace[2].id = -1; |
3735 | pxdesc->acl.ace[3].tag = POSIX_ACL_OTHER; |
3736 | pxdesc->acl.ace[3].id = -1; |
3737 | } else { |
3738 | pxdesc->acl.ace[1].tag = POSIX_ACL_USER; |
3739 | pxdesc->acl.ace[1].id = (kind & 16 ? 0 : 1000); |
3740 | pxdesc->acl.ace[2].tag = POSIX_ACL_GROUP_OBJ; |
3741 | pxdesc->acl.ace[2].id = -1; |
3742 | pxdesc->acl.ace[3].tag = POSIX_ACL_GROUP; |
3743 | pxdesc->acl.ace[3].id = (kind & 16 ? 0 : 1002); |
3744 | pxdesc->acl.ace[4].tag = POSIX_ACL_MASK; |
3745 | pxdesc->acl.ace[4].id = -1; |
3746 | pxdesc->acl.ace[5].tag = POSIX_ACL_OTHER; |
3747 | pxdesc->acl.ace[5].id = -1; |
3748 | } |
3749 | |
3750 | mindes = 3; |
3751 | maxdes = (kind & 32 ? mindes : 6); |
3752 | #ifdef STSC |
3753 | minmsk = (kind & 32 ? 0 : 3); |
3754 | maxmsk = (kind & 32 ? 7 : 3); |
3755 | #else |
3756 | minmsk = 0; |
3757 | maxmsk = 7; |
3758 | #endif |
3759 | for (mask=minmsk; mask<=maxmsk; mask++) |
3760 | for (ownobj=1; ownobj<7; ownobj++) |
3761 | for (grpobj=1; grpobj<7; grpobj++) |
3762 | for (wrld=0; wrld<8; wrld++) |
3763 | for (usr=mindes; usr<=maxdes; usr++) |
3764 | if (usr != 4) |
3765 | for (grp=mindes; grp<=maxdes; grp++) |
3766 | if (grp != 4) { |
3767 | pxdesc->mode = (ownobj << 6) | (mask << 3) | wrld; |
3768 | |
3769 | pxdesc->acl.ace[0].perms = ownobj; |
3770 | if (kind & 32) { |
3771 | pxdesc->acl.ace[1].perms = grpobj; |
3772 | pxdesc->acl.ace[2].perms = mask; |
3773 | pxdesc->acl.ace[3].perms = wrld; |
3774 | } else { |
3775 | pxdesc->acl.ace[1].perms = usr; |
3776 | pxdesc->acl.ace[2].perms = grpobj; |
3777 | pxdesc->acl.ace[3].perms = grp; |
3778 | pxdesc->acl.ace[4].perms = mask; |
3779 | pxdesc->acl.ace[5].perms = wrld; |
3780 | } |
3781 | |
3782 | err = ERRNO; |
3783 | gotback = (struct POSIX_SECURITY*)NULL; |
3784 | pxattr = ntfs_build_descr_posix(context.mapping, |
3785 | pxdesc,isdir,owner,group); |
3786 | if (pxattr && ntfs_valid_descr(pxattr, ntfs_attr_size(pxattr))) { |
3787 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)pxattr; |
3788 | pacl = (const ACL*)&pxattr[le32_to_cpu(phead->dacl)]; |
3789 | acecount += le16_to_cpu(pacl->ace_count); |
3790 | globhash += hash((const le32*)pxattr,ntfs_attr_size(pxattr)); |
3791 | count++; |
3792 | gotback = linux_permissions_posix(pxattr, isdir); |
3793 | if (gotback) { |
3794 | if (ntfs_valid_posix(gotback)) { |
3795 | if (!same_posix(pxdesc,gotback)) { |
3796 | printf("Non matching got back Posix ACL\n"); |
3797 | printf("input ACL\n"); |
3798 | showposix(pxdesc); |
3799 | printf("NTFS owner\n"); |
3800 | showusid(pxattr,4); |
3801 | printf("NTFS group\n"); |
3802 | showgsid(pxattr,4); |
3803 | printf("NTFS DACL\n"); |
3804 | showdacl(pxattr,isdir,4); |
3805 | printf("gotback ACL\n"); |
3806 | showposix(gotback); |
3807 | errors++; |
3808 | exit(1); |
3809 | } |
3810 | } else { |
3811 | printf("Got back an invalid Posix ACL\n"); |
3812 | errors++; |
3813 | } |
3814 | free(gotback); |
3815 | } else { |
3816 | printf("Could not get Posix ACL back\n"); |
3817 | errors++; |
3818 | } |
3819 | |
3820 | } else { |
3821 | printf("NTFS ACL incorrect or not build\n"); |
3822 | printf("input ACL\n"); |
3823 | showposix(pxdesc); |
3824 | printf("NTFS DACL\n"); |
3825 | if (pxattr) |
3826 | showdacl(pxattr,isdir,4); |
3827 | else |
3828 | printf(" (none)\n"); |
3829 | if (gotback) { |
3830 | printf("gotback ACL\n"); |
3831 | showposix(gotback); |
3832 | } else |
3833 | printf("no gotback ACL\n"); |
3834 | errors++; |
3835 | } |
3836 | if (pxattr) |
3837 | free(pxattr); |
3838 | } |
3839 | printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", |
3840 | (unsigned long)count,(unsigned long)acecount, |
3841 | (unsigned long)acecount/count,acecount*100L/count%100L); |
3842 | if (acecount != expectcnt[kind]) { |
3843 | printf("** Error ! expected ACE count %lu\n", |
3844 | (unsigned long)expectcnt[kind]); |
3845 | errors++; |
3846 | } |
3847 | if (globhash != expecthash[kind]) { |
3848 | printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
3849 | (unsigned long)globhash, (unsigned long)expecthash[kind]); |
3850 | errors++; |
3851 | } |
3852 | } |
3853 | |
3854 | #endif /* POSIXACLS */ |
3855 | |
3856 | void selftests(void) |
3857 | { |
3858 | le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
3859 | { |
3860 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3861 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
3862 | cpu_to_le32(AUTH3), cpu_to_le32(1016) |
3863 | } ; |
3864 | le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
3865 | { |
3866 | cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), |
3867 | cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), |
3868 | cpu_to_le32(AUTH3), cpu_to_le32(513) |
3869 | } ; |
3870 | #if POSIXACLS |
3871 | #ifdef STSC |
3872 | unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
3873 | 16, 17, 18, 20, 22, 24, |
3874 | 32, 33, 36, 40 } ; |
3875 | #else |
3876 | unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
3877 | 16, 17, 18, 20, 22, 24, 19, 21, 23, 25, |
3878 | 32, 33, 36, 40 } ; |
3879 | #endif |
3880 | unsigned int k; |
3881 | #endif /* POSIXACLS */ |
3882 | int kind; |
3883 | const SID *owner; |
3884 | const SID *group; |
3885 | BOOL isdir; |
3886 | |
3887 | #if POSIXACLS |
3888 | local_build_mapping(context.mapping, (const char*)NULL); |
3889 | #endif |
3890 | /* first check samples */ |
3891 | mappingtype = MAPDUMMY; |
3892 | check_samples(); |
3893 | if (errors) exit(1); |
3894 | /* |
3895 | * kind is oring of : |
3896 | * 1 : directory |
3897 | * 2 : owner is root |
3898 | * 4 : group is root |
3899 | * 8 : group is owner |
3900 | * 16 : root is designated user/group |
3901 | * 32 : mask present with no designated user/group |
3902 | */ |
3903 | for (kind=0; (kind<10) && (errors<10); kind++) { |
3904 | isdir = kind & 1; |
3905 | if (kind & 8) |
3906 | owner = (const SID*)group_sid; |
3907 | else |
3908 | owner = (kind & 2 ? adminsid : (const SID*)owner_sid); |
3909 | group = (kind & 4 ? adminsid : (const SID*)group_sid); |
3910 | basictest(kind, isdir, owner, group); |
3911 | } |
3912 | #if POSIXACLS |
3913 | for (k=0; (k<sizeof(kindlist)) && (errors<10); k++) { |
3914 | kind = kindlist[k]; |
3915 | isdir = kind & 1; |
3916 | if (kind & 8) |
3917 | owner = (const SID*)group_sid; |
3918 | else |
3919 | owner = (kind & 2 ? adminsid : (const SID*)owner_sid); |
3920 | group = (kind & 4 ? adminsid : (const SID*)group_sid); |
3921 | posixtest(kind, isdir, owner, group); |
3922 | } |
3923 | ntfs_free_mapping(context.mapping); |
3924 | #endif |
3925 | if (errors >= 10) |
3926 | printf("** too many errors, test aborted\n"); |
3927 | } |
3928 | #endif /* SELFTESTS & !USESTUBS */ |
3929 | |
3930 | #ifdef WIN32 |
3931 | |
3932 | /* |
3933 | * Get the security descriptor of a file (Windows version) |
3934 | */ |
3935 | |
3936 | unsigned int getfull(char *attr, const char *fullname) |
3937 | { |
3938 | static char part[MAXATTRSZ]; |
3939 | BIGSID ownsid; |
3940 | int xowner; |
3941 | int ownersz; |
3942 | u16 ownerfl; |
3943 | ULONG attrsz; |
3944 | ULONG partsz; |
3945 | BOOL overflow; |
3946 | |
3947 | attrsz = 0; |
3948 | partsz = 0; |
3949 | overflow = FALSE; |
3950 | if (GetFileSecurityW((LPCWSTR)fullname,OWNER_SECURITY_INFORMATION, |
3951 | (char*)part,MAXATTRSZ,&partsz)) { |
3952 | xowner = get4l(part,4); |
3953 | if (xowner) { |
3954 | ownerfl = get2l(part,2); |
3955 | ownersz = ntfs_sid_size((SID*)&part[xowner]); |
3956 | if (ownersz <= (int)sizeof(BIGSID)) |
3957 | memcpy(ownsid,&part[xowner],ownersz); |
3958 | else |
3959 | overflow = TRUE; |
3960 | } else { |
3961 | ownerfl = 0; |
3962 | ownersz = 0; |
3963 | } |
3964 | /* |
3965 | * SACL : just feed in or clean |
3966 | */ |
3967 | if (!GetFileSecurityW((LPCWSTR)fullname,SACL_SECURITY_INFORMATION, |
3968 | (char*)attr,MAXATTRSZ,&attrsz)) { |
3969 | attrsz = 20; |
3970 | set4l(attr,0); |
3971 | attr[0] = SECURITY_DESCRIPTOR_REVISION; |
3972 | set4l(&attr[12],0); |
3973 | if (opt_v >= 2) |
3974 | printf(" No SACL\n"); |
3975 | } |
3976 | /* |
3977 | * append DACL and merge its flags |
3978 | */ |
3979 | partsz = 0; |
3980 | set4l(&attr[16],0); |
3981 | if (GetFileSecurityW((LPCWSTR)fullname,DACL_SECURITY_INFORMATION, |
3982 | (char*)part,MAXATTRSZ,&partsz)) { |
3983 | if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
3984 | memcpy(&attr[attrsz],&part[20],partsz-20); |
3985 | set4l(&attr[16],(partsz > 20 ? attrsz : 0)); |
3986 | set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
3987 | & const_le16_to_cpu(SE_DACL_PROTECTED |
3988 | | SE_DACL_AUTO_INHERITED |
3989 | | SE_DACL_PRESENT))); |
3990 | attrsz += partsz - 20; |
3991 | } else |
3992 | overflow = TRUE; |
3993 | } else |
3994 | if (partsz > MAXATTRSZ) |
3995 | overflow = TRUE; |
3996 | else { |
3997 | if (opt_b) |
3998 | printf("# No discretionary access control list\n"); |
3999 | else |
4000 | printf(" No discretionary access control list\n"); |
4001 | warnings++; |
4002 | } |
4003 | |
4004 | /* |
4005 | * append owner and merge its flag |
4006 | */ |
4007 | if (xowner && !overflow) { |
4008 | memcpy(&attr[attrsz],ownsid,ownersz); |
4009 | set4l(&attr[4],attrsz); |
4010 | set2l(&attr[2],get2l(attr,2) |
4011 | | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); |
4012 | attrsz += ownersz; |
4013 | } else |
4014 | set4l(&attr[4],0); |
4015 | /* |
4016 | * append group |
4017 | */ |
4018 | partsz = 0; |
4019 | set4l(&attr[8],0); |
4020 | if (GetFileSecurityW((LPCWSTR)fullname,GROUP_SECURITY_INFORMATION, |
4021 | (char*)part,MAXATTRSZ,&partsz)) { |
4022 | if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
4023 | memcpy(&attr[attrsz],&part[20],partsz-20); |
4024 | set4l(&attr[8],(partsz > 20 ? attrsz : 0)); |
4025 | set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
4026 | & const_le16_to_cpu(SE_GROUP_DEFAULTED))); |
4027 | attrsz += partsz - 20; |
4028 | } else |
4029 | overflow = TRUE; |
4030 | } else |
4031 | if (partsz > MAXATTRSZ) |
4032 | overflow = TRUE; |
4033 | else { |
4034 | printf("** No group SID\n"); |
4035 | warnings++; |
4036 | } |
4037 | set2l(&attr[2],get2l(attr,2) |
4038 | | const_le16_to_cpu(SE_SELF_RELATIVE)); |
4039 | if (overflow) { |
4040 | printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); |
4041 | warnings++; |
4042 | attrsz = 0; |
4043 | } else |
4044 | if (!ntfs_valid_descr((char*)attr,attrsz)) { |
4045 | printf("** Descriptor for "); |
4046 | printname(stdout,fullname); |
4047 | printf(" is not valid\n"); |
4048 | errors++; |
4049 | attrsz = 0; |
4050 | } |
4051 | |
4052 | } else { |
4053 | printf("** Could not get owner of "); |
4054 | printname(stdout,fullname); |
4055 | printf(", partsz %d\n",partsz); |
4056 | printerror(stdout); |
4057 | warnings++; |
4058 | attrsz = 0; |
4059 | } |
4060 | return (attrsz); |
4061 | } |
4062 | |
4063 | /* |
4064 | * Update a security descriptor (Windows version) |
4065 | */ |
4066 | |
4067 | BOOL updatefull(const char *name, DWORD flags, char *attr) |
4068 | { |
4069 | BOOL bad; |
4070 | |
4071 | bad = !SetFileSecurityW((LPCWSTR)name, flags, attr); |
4072 | if (bad |
4073 | && (flags & OWNER_SECURITY_INFORMATION) |
4074 | && (GetLastError() == 1307)) { |
4075 | printf("** Could not set owner of "); |
4076 | printname(stdout,name); |
4077 | printf(", retrying with no owner setting\n"); |
4078 | warnings++; |
4079 | bad = !SetFileSecurityW((LPCWSTR)name, |
4080 | flags & ~OWNER_SECURITY_INFORMATION, (char*)attr); |
4081 | } |
4082 | if (bad) { |
4083 | printf("** Could not change attributes of "); |
4084 | printname(stdout,name); |
4085 | printf("\n"); |
4086 | printerror(stdout); |
4087 | errors++; |
4088 | } |
4089 | return (!bad); |
4090 | } |
4091 | |
4092 | #else |
4093 | |
4094 | /* |
4095 | * Get the security descriptor of a file (Linux version) |
4096 | */ |
4097 | |
4098 | unsigned int getfull(char *attr, const char *fullname) |
4099 | { |
4100 | static char part[MAXATTRSZ]; |
4101 | BIGSID ownsid; |
4102 | int xowner; |
4103 | int ownersz; |
4104 | u16 ownerfl; |
4105 | u32 attrsz; |
4106 | u32 partsz; |
4107 | BOOL overflow; |
4108 | |
4109 | attrsz = 0; |
4110 | partsz = 0; |
4111 | overflow = FALSE; |
4112 | if (ntfs_get_file_security(ntfs_context,fullname, |
4113 | OWNER_SECURITY_INFORMATION, |
4114 | (char*)part,MAXATTRSZ,&partsz)) { |
4115 | xowner = get4l(part,4); |
4116 | if (xowner) { |
4117 | ownerfl = get2l(part,2); |
4118 | ownersz = ntfs_sid_size((SID*)&part[xowner]); |
4119 | if (ownersz <= (int)sizeof(BIGSID)) |
4120 | memcpy(ownsid,&part[xowner],ownersz); |
4121 | else |
4122 | overflow = TRUE; |
4123 | } else { |
4124 | ownerfl = 0; |
4125 | ownersz = 0; |
4126 | } |
4127 | /* |
4128 | * SACL : just feed in or clean |
4129 | */ |
4130 | if (!ntfs_get_file_security(ntfs_context,fullname, |
4131 | SACL_SECURITY_INFORMATION, |
4132 | (char*)attr,MAXATTRSZ,&attrsz)) { |
4133 | attrsz = 20; |
4134 | set4l(attr,0); |
4135 | attr[0] = SECURITY_DESCRIPTOR_REVISION; |
4136 | set4l(&attr[12],0); |
4137 | if (opt_v >= 2) |
4138 | printf(" No SACL\n"); |
4139 | } |
4140 | /* |
4141 | * append DACL and merge its flags |
4142 | */ |
4143 | partsz = 0; |
4144 | set4l(&attr[16],0); |
4145 | if (ntfs_get_file_security(ntfs_context,fullname, |
4146 | DACL_SECURITY_INFORMATION, |
4147 | (char*)part,MAXATTRSZ,&partsz)) { |
4148 | if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
4149 | memcpy(&attr[attrsz],&part[20],partsz-20); |
4150 | set4l(&attr[16],(partsz > 20 ? attrsz : 0)); |
4151 | set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
4152 | & const_le16_to_cpu(SE_DACL_PROTECTED |
4153 | | SE_DACL_AUTO_INHERITED |
4154 | | SE_DACL_PRESENT))); |
4155 | attrsz += partsz - 20; |
4156 | } else |
4157 | overflow = TRUE; |
4158 | } else |
4159 | if (partsz > MAXATTRSZ) |
4160 | overflow = TRUE; |
4161 | else { |
4162 | if (opt_b) |
4163 | printf("# No discretionary access control list\n"); |
4164 | else |
4165 | printf(" No discretionary access control list\n"); |
4166 | warnings++; |
4167 | } |
4168 | |
4169 | /* |
4170 | * append owner and merge its flag |
4171 | */ |
4172 | if (xowner && !overflow) { |
4173 | memcpy(&attr[attrsz],ownsid,ownersz); |
4174 | set4l(&attr[4],attrsz); |
4175 | set2l(&attr[2],get2l(attr,2) |
4176 | | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); |
4177 | attrsz += ownersz; |
4178 | } else |
4179 | set4l(&attr[4],0); |
4180 | /* |
4181 | * append group |
4182 | */ |
4183 | partsz = 0; |
4184 | set4l(&attr[8],0); |
4185 | if (ntfs_get_file_security(ntfs_context,fullname, |
4186 | GROUP_SECURITY_INFORMATION, |
4187 | (char*)part,MAXATTRSZ,&partsz)) { |
4188 | if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
4189 | memcpy(&attr[attrsz],&part[20],partsz-20); |
4190 | set4l(&attr[8],(partsz > 20 ? attrsz : 0)); |
4191 | set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
4192 | & const_le16_to_cpu(SE_GROUP_DEFAULTED))); |
4193 | attrsz += partsz - 20; |
4194 | } else |
4195 | overflow = TRUE; |
4196 | } else |
4197 | if (partsz > MAXATTRSZ) |
4198 | overflow = TRUE; |
4199 | else { |
4200 | printf("** No group SID\n"); |
4201 | warnings++; |
4202 | } |
4203 | if (overflow) { |
4204 | printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); |
4205 | warnings++; |
4206 | attrsz = 0; |
4207 | } else |
4208 | if (!ntfs_valid_descr((char*)attr,attrsz)) { |
4209 | printf("** Descriptor for %s is not valid\n",fullname); |
4210 | errors++; |
4211 | attrsz = 0; |
4212 | } |
4213 | |
4214 | } else { |
4215 | printf("** Could not get owner of %s\n",fullname); |
4216 | warnings++; |
4217 | attrsz = 0; |
4218 | } |
4219 | return (attrsz); |
4220 | } |
4221 | |
4222 | /* |
4223 | * Update a security descriptor (Linux version) |
4224 | */ |
4225 | |
4226 | BOOL updatefull(const char *name, DWORD flags, char *attr) |
4227 | { |
4228 | BOOL ok; |
4229 | |
4230 | ok = !ntfs_set_file_security(ntfs_context, name, flags, attr); |
4231 | if (ok) { |
4232 | printf("** Could not change attributes of %s\n",name); |
4233 | printerror(stdout); |
4234 | errors++; |
4235 | } |
4236 | return (ok); |
4237 | } |
4238 | |
4239 | |
4240 | #endif |
4241 | |
4242 | #if POSIXACLS |
4243 | |
4244 | /* |
4245 | * Set all the parameters associated to a file |
4246 | */ |
4247 | |
4248 | BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, |
4249 | BOOL isdir) |
4250 | { |
4251 | static char attr[MAXATTRSZ]; |
4252 | struct POSIX_SECURITY *oldpxdesc; |
4253 | struct POSIX_SECURITY *newpxdesc; |
4254 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
4255 | char *newattr; |
4256 | int err; |
4257 | unsigned int attrsz; |
4258 | int newattrsz; |
4259 | const SID *usid; |
4260 | const SID *gsid; |
4261 | #if OWNERFROMACL |
4262 | const SID *osid; |
4263 | #endif |
4264 | |
4265 | printf("%s ",(isdir ? "Directory" : "File")); |
4266 | printname(stdout,fullname); |
4267 | if (pxdesc->acccnt) |
4268 | printf("\n"); |
4269 | else |
4270 | printf(" mode 0%03o\n",pxdesc->mode); |
4271 | |
4272 | err = FALSE; |
4273 | attrsz = getfull(attr, fullname); |
4274 | if (attrsz) { |
4275 | oldpxdesc = linux_permissions_posix(attr, isdir); |
4276 | if (opt_v >= 2) { |
4277 | printf("Posix equivalent of old ACL :\n"); |
4278 | showposix(oldpxdesc); |
4279 | } |
4280 | if (oldpxdesc) { |
4281 | if (!pxdesc->defcnt |
4282 | && !(pxdesc->tagsset & |
4283 | (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK))) { |
4284 | if (!ntfs_merge_mode_posix(oldpxdesc,pxdesc->mode)) |
4285 | newpxdesc = oldpxdesc; |
4286 | else { |
4287 | newpxdesc = (struct POSIX_SECURITY*)NULL; |
4288 | free(oldpxdesc); |
4289 | } |
4290 | } else { |
4291 | newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); |
4292 | free(oldpxdesc); |
4293 | } |
4294 | if (opt_v) { |
4295 | printf("New Posix ACL :\n"); |
4296 | showposix(newpxdesc); |
4297 | } |
4298 | } else |
4299 | newpxdesc = (struct POSIX_SECURITY*)NULL; |
4300 | if (newpxdesc) { |
4301 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
4302 | gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
4303 | #if OWNERFROMACL |
4304 | osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
4305 | usid = ntfs_acl_owner((const char*)attr); |
4306 | if (!ntfs_same_sid(usid,osid)) |
4307 | printf("== Windows owner might change\n"); |
4308 | #else |
4309 | usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
4310 | #endif |
4311 | newattr = ntfs_build_descr_posix(context.mapping, |
4312 | newpxdesc,isdir,usid,gsid); |
4313 | free(newpxdesc); |
4314 | } else |
4315 | newattr = (char*)NULL; |
4316 | if (newattr) { |
4317 | newattrsz = ntfs_attr_size(newattr); |
4318 | if (opt_v) { |
4319 | printf("New NTFS security descriptor\n"); |
4320 | hexdump(newattr,newattrsz,4); |
4321 | } |
4322 | if (opt_v >= 2) { |
4323 | printf("Expected hash : 0x%08lx\n", |
4324 | (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); |
4325 | showheader(newattr,0); |
4326 | showusid(newattr,0); |
4327 | showgsid(newattr,0); |
4328 | showdacl(newattr,isdir,0); |
4329 | showsacl(newattr,isdir,0); |
4330 | } |
4331 | |
4332 | #ifdef WIN32 |
4333 | /* |
4334 | * avoid getting a set owner error on Windows |
4335 | * owner should not be changed anyway |
4336 | */ |
4337 | if (!updatefull(fullname, |
4338 | DACL_SECURITY_INFORMATION |
4339 | | GROUP_SECURITY_INFORMATION |
4340 | | OWNER_SECURITY_INFORMATION, |
4341 | newattr)) |
4342 | #else |
4343 | if (!updatefull(fullname, |
4344 | DACL_SECURITY_INFORMATION |
4345 | | GROUP_SECURITY_INFORMATION |
4346 | | OWNER_SECURITY_INFORMATION, |
4347 | newattr)) |
4348 | #endif |
4349 | err = TRUE; |
4350 | /* |
4351 | { |
4352 | struct POSIX_SECURITY *interp; |
4353 | printf("Reinterpreted new Posix :\n"); |
4354 | interp = linux_permissions_posix(newattr,isdir); |
4355 | showposix(interp); |
4356 | free(interp); |
4357 | } |
4358 | */ |
4359 | free(newattr); |
4360 | } else |
4361 | err = TRUE; |
4362 | } else |
4363 | err = TRUE; |
4364 | return (!err); |
4365 | } |
4366 | |
4367 | #endif |
4368 | |
4369 | BOOL setfull(const char *fullname, int mode, BOOL isdir) |
4370 | { |
4371 | static char attr[MAXATTRSZ]; |
4372 | const SECURITY_DESCRIPTOR_RELATIVE *phead; |
4373 | char *newattr; |
4374 | int err; |
4375 | unsigned int attrsz; |
4376 | int newattrsz; |
4377 | const SID *usid; |
4378 | const SID *gsid; |
4379 | #if OWNERFROMACL |
4380 | const SID *osid; |
4381 | #endif |
4382 | |
4383 | printf("%s ",(isdir ? "Directory" : "File")); |
4384 | printname(stdout,fullname); |
4385 | printf(" mode 0%03o\n",mode); |
4386 | attrsz = getfull(attr, fullname); |
4387 | err = FALSE; |
4388 | if (attrsz) { |
4389 | phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
4390 | gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
4391 | #if OWNERFROMACL |
4392 | osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
4393 | usid = ntfs_acl_owner((const char*)attr); |
4394 | if (!ntfs_same_sid(usid,osid)) |
4395 | printf("== Windows owner might change\n"); |
4396 | #else |
4397 | usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
4398 | #endif |
4399 | newattr = ntfs_build_descr(mode,isdir,usid,gsid); |
4400 | if (newattr) { |
4401 | newattrsz = ntfs_attr_size(newattr); |
4402 | if (opt_v) { |
4403 | printf("Security descriptor\n"); |
4404 | hexdump(newattr,newattrsz,4); |
4405 | } |
4406 | if (opt_v >= 2) { |
4407 | printf("Expected hash : 0x%08lx\n", |
4408 | (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); |
4409 | showheader(newattr,0); |
4410 | showusid(newattr,0); |
4411 | showgsid(newattr,0); |
4412 | showdacl(newattr,isdir,0); |
4413 | showsacl(newattr,isdir,0); |
4414 | } |
4415 | |
4416 | #ifdef WIN32 |
4417 | /* |
4418 | * avoid getting a set owner error on Windows |
4419 | * owner should not be changed anyway |
4420 | */ |
4421 | if (!updatefull(fullname, |
4422 | DACL_SECURITY_INFORMATION |
4423 | | GROUP_SECURITY_INFORMATION |
4424 | | OWNER_SECURITY_INFORMATION, |
4425 | newattr)) |
4426 | #else |
4427 | if (!updatefull(fullname, |
4428 | DACL_SECURITY_INFORMATION |
4429 | | GROUP_SECURITY_INFORMATION |
4430 | | OWNER_SECURITY_INFORMATION, |
4431 | newattr)) |
4432 | #endif |
4433 | err = TRUE; |
4434 | free(newattr); |
4435 | } |
4436 | |
4437 | } else |
4438 | err = TRUE; |
4439 | return (err); |
4440 | } |
4441 | |
4442 | #ifdef WIN32 |
4443 | |
4444 | /* |
4445 | * Check whether a directory with reparse data is a junction |
4446 | * or a symbolic link |
4447 | */ |
4448 | |
4449 | BOOL islink(const char *filename) |
4450 | { |
4451 | WIN32_FIND_DATAW found; |
4452 | HANDLE search; |
4453 | BOOL link; |
4454 | |
4455 | link = FALSE; |
4456 | search = FindFirstFileW((LPCWSTR)filename, &found); |
4457 | if (search != INVALID_HANDLE_VALUE) { |
4458 | link = (found.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) |
4459 | || (found.dwReserved0 == IO_REPARSE_TAG_SYMLINK); |
4460 | FindClose(search); |
4461 | } |
4462 | return (link); |
4463 | } |
4464 | |
4465 | #if POSIXACLS |
4466 | BOOL iterate(RECURSE call, const char *fullname, const struct POSIX_SECURITY *pxdesc) |
4467 | #else |
4468 | BOOL iterate(RECURSE call, const char *fullname, mode_t mode) |
4469 | #endif |
4470 | { |
4471 | WIN32_FIND_DATAW found; |
4472 | HANDLE search; |
4473 | BOOL err; |
4474 | unsigned int len; |
4475 | char *filter; |
4476 | char *inner; |
4477 | |
4478 | err = FALSE; |
4479 | filter = (char*)malloc(MAXFILENAME); |
4480 | inner = (char*)malloc(MAXFILENAME); |
4481 | if (filter && inner) { |
4482 | len = utf16len(fullname); |
4483 | memcpy(filter, fullname, 2*len); |
4484 | makeutf16(&filter[2*len],"\\*.*"); |
4485 | search = FindFirstFileW((LPCWSTR)filter, &found); |
4486 | if (search != INVALID_HANDLE_VALUE) { |
4487 | do { |
4488 | if (found.cFileName[0] != UNICODE('.')) { |
4489 | memcpy(inner, fullname, 2*len); |
4490 | inner[2*len] = '\\'; |
4491 | inner[2*len+1] = 0; |
4492 | memcpy(&inner[2*len+2],found.cFileName, |
4493 | 2*utf16len((char*)found.cFileName)+2); |
4494 | if (opt_v) |
4495 | if (opt_b) |
4496 | printf("#\n#\n"); |
4497 | else |
4498 | printf("\n\n"); |
4499 | switch (call) { |
4500 | case RECSHOW : |
4501 | if (recurseshow(inner)) |
4502 | err = TRUE; |
4503 | break; |
4504 | #if POSIXACLS |
4505 | case RECSETPOSIX : |
4506 | if (recurseset_posix(inner,pxdesc)) |
4507 | err = TRUE; |
4508 | break; |
4509 | #else |
4510 | case RECSET : |
4511 | if (recurseset(inner,mode)) |
4512 | err = TRUE; |
4513 | break; |
4514 | #endif |
4515 | default : |
4516 | err = TRUE; |
4517 | } |
4518 | } |
4519 | } while (FindNextFileW(search, &found)); |
4520 | FindClose(search); |
4521 | } |
4522 | free(filter); |
4523 | free(inner); |
4524 | } else { |
4525 | printf("** Cannot process deeper : not enough memory\n"); |
4526 | errors++; |
4527 | err = TRUE; |
4528 | } |
4529 | return (err); |
4530 | } |
4531 | |
4532 | |
4533 | |
4534 | /* |
4535 | * Display all the parameters associated to a file (Windows version) |
4536 | */ |
4537 | |
4538 | void showfull(const char *fullname, BOOL isdir) |
4539 | { |
4540 | static char attr[MAXATTRSZ]; |
4541 | #if POSIXACLS |
4542 | struct POSIX_SECURITY *pxdesc; |
4543 | #endif |
4544 | ULONG attrsz; |
4545 | int mode; |
4546 | uid_t uid; |
4547 | gid_t gid; |
4548 | int attrib; |
4549 | int level; |
4550 | |
4551 | printf("%s ",(isdir ? "Directory" : "File")); |
4552 | printname(stdout,fullname); |
4553 | printf("\n"); |
4554 | |
4555 | /* get individual parameters, as when trying to get them */ |
4556 | /* all, and one (typically SACL) is missing, we get none, */ |
4557 | /* and concatenate them, to be able to compute the hash code */ |
4558 | |
4559 | attrsz = getfull(attr, fullname); |
4560 | if (attrsz) { |
4561 | if (opt_v || opt_b) { |
4562 | hexdump(attr,attrsz,8); |
4563 | printf("Computed hash : 0x%08lx\n", |
4564 | (unsigned long)hash((le32*)attr,attrsz)); |
4565 | } |
4566 | if (opt_v && opt_b) { |
4567 | printf("# %s ",(isdir ? "Directory" : "File")); |
4568 | printname(stdout,fullname); |
4569 | printf(" hash 0x%lx\n", |
4570 | (unsigned long)hash((le32*)attr,attrsz)); |
4571 | } |
4572 | attrib = GetFileAttributesW((LPCWSTR)fullname); |
4573 | if (attrib == INVALID_FILE_ATTRIBUTES) { |
4574 | printf("** Could not get file attrib\n"); |
4575 | errors++; |
4576 | } else |
4577 | printf("Windows attrib : 0x%x\n",attrib); |
4578 | if (ntfs_valid_descr(attr,attrsz)) { |
4579 | #if POSIXACLS |
4580 | pxdesc = linux_permissions_posix(attr,isdir); |
4581 | if (pxdesc) |
4582 | mode = pxdesc->mode; |
4583 | else |
4584 | mode = 0; |
4585 | #else |
4586 | mode = linux_permissions(attr,isdir); |
4587 | #endif |
4588 | if (opt_v >= 2) { |
4589 | level = (opt_b ? 4 : 0); |
4590 | showheader(attr,level); |
4591 | showusid(attr,level); |
4592 | showgsid(attr,level); |
4593 | showdacl(attr,isdir,level); |
4594 | showsacl(attr,isdir,level); |
4595 | } |
4596 | uid = linux_owner(attr); |
4597 | gid = linux_group(attr); |
4598 | if (opt_b) { |
4599 | printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", |
4600 | (int)uid,(int)gid,mode); |
4601 | } else { |
4602 | printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
4603 | (int)uid,(int)gid,mode); |
4604 | } |
4605 | #if POSIXACLS |
4606 | if (pxdesc) { |
4607 | if (!opt_b |
4608 | && (pxdesc->defcnt |
4609 | || (pxdesc->tagsset |
4610 | & (POSIX_ACL_USER |
4611 | | POSIX_ACL_GROUP |
4612 | | POSIX_ACL_MASK)))) |
4613 | showposix(pxdesc); |
4614 | free(pxdesc); |
4615 | } |
4616 | #endif |
4617 | } else |
4618 | if (opt_b) |
4619 | printf("# Descriptor fails sanity check\n"); |
4620 | else |
4621 | printf("Descriptor fails sanity check\n"); |
4622 | } |
4623 | } |
4624 | |
4625 | BOOL recurseshow(const char *fullname) |
4626 | { |
4627 | int attrib; |
4628 | int err; |
4629 | BOOL isdir; |
4630 | |
4631 | err = FALSE; |
4632 | attrib = GetFileAttributesW((LPCWSTR)fullname); |
4633 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4634 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
4635 | showfull(fullname,isdir); |
4636 | if (isdir |
4637 | && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
4638 | && islink(fullname))) { |
4639 | #if POSIXACLS |
4640 | err = iterate(RECSHOW, fullname, (struct POSIX_SECURITY*)NULL); |
4641 | #else |
4642 | err = iterate(RECSHOW, fullname, 0); |
4643 | #endif |
4644 | } |
4645 | } else { |
4646 | printf("** Could not access "); |
4647 | printname(stdout,fullname); |
4648 | printf("\n"); |
4649 | printerror(stdout); |
4650 | errors++; |
4651 | err = TRUE; |
4652 | } |
4653 | return (err); |
4654 | } |
4655 | |
4656 | |
4657 | BOOL singleshow(const char *fullname) |
4658 | { |
4659 | int attrib; |
4660 | int err; |
4661 | BOOL isdir; |
4662 | |
4663 | err = FALSE; |
4664 | attrib = GetFileAttributesW((LPCWSTR)fullname); |
4665 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4666 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
4667 | showfull(fullname,isdir); |
4668 | } else { |
4669 | printf("** Could not access "); |
4670 | printname(stdout,fullname); |
4671 | printf("\n"); |
4672 | printerror(stdout); |
4673 | errors++; |
4674 | err = TRUE; |
4675 | } |
4676 | return (err); |
4677 | } |
4678 | |
4679 | #if POSIXACLS |
4680 | |
4681 | BOOL recurseset_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc) |
4682 | { |
4683 | int attrib; |
4684 | int err; |
4685 | BOOL isdir; |
4686 | |
4687 | err = FALSE; |
4688 | attrib = GetFileAttributesW((LPCWSTR)fullname); |
4689 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4690 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
4691 | err = !setfull_posix(fullname,pxdesc,isdir); |
4692 | if (err) { |
4693 | printf("** Failed to update "); |
4694 | printname(stdout,fullname); |
4695 | printf("\n"); |
4696 | errors++; |
4697 | } else |
4698 | if (isdir |
4699 | && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
4700 | && islink(fullname))) |
4701 | iterate(RECSETPOSIX, fullname, pxdesc); |
4702 | } else { |
4703 | err = GetLastError(); |
4704 | printf("** Could not access "); |
4705 | printname(stdout,fullname); |
4706 | printf("\n"); |
4707 | printerror(stdout); |
4708 | err = TRUE; |
4709 | errors++; |
4710 | } |
4711 | return (err); |
4712 | } |
4713 | |
4714 | #else |
4715 | |
4716 | BOOL recurseset(const char *fullname, int mode) |
4717 | { |
4718 | int attrib; |
4719 | int err; |
4720 | BOOL isdir; |
4721 | |
4722 | err = FALSE; |
4723 | attrib = GetFileAttributesW((LPCWSTR)fullname); |
4724 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4725 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
4726 | setfull(fullname,mode,isdir); |
4727 | if (isdir |
4728 | && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
4729 | && islink(fullname))) |
4730 | iterate(RECSETPOSIX, fullname, mode); |
4731 | } else { |
4732 | err = GetLastError(); |
4733 | printf("** Could not access "); |
4734 | printname(stdout,fullname); |
4735 | printf("\n"); |
4736 | printerror(stdout); |
4737 | err = TRUE; |
4738 | errors++; |
4739 | } |
4740 | return (err); |
4741 | } |
4742 | |
4743 | #endif |
4744 | |
4745 | #if POSIXACLS |
4746 | |
4747 | BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
4748 | { |
4749 | BOOL isdir; |
4750 | BOOL err; |
4751 | int attrib; |
4752 | |
4753 | err = FALSE; |
4754 | attrib = GetFileAttributesW((LPCWSTR)path); |
4755 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4756 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); |
4757 | err = !setfull_posix(path,pxdesc,isdir); |
4758 | if (err) { |
4759 | printf("** Failed to update "); |
4760 | printname(stdout,path); |
4761 | printf("\n"); |
4762 | errors++; |
4763 | } |
4764 | } else { |
4765 | printf("** Could not access "); |
4766 | printname(stdout,path); |
4767 | printf("\n"); |
4768 | printerror(stdout); |
4769 | errors++; |
4770 | err = TRUE; |
4771 | } |
4772 | return (!err); |
4773 | } |
4774 | |
4775 | #endif |
4776 | |
4777 | BOOL singleset(const char *path, int mode) |
4778 | { |
4779 | BOOL isdir; |
4780 | BOOL err; |
4781 | int attrib; |
4782 | |
4783 | err = FALSE; |
4784 | attrib = GetFileAttributesW((LPCWSTR)path); |
4785 | if (attrib != INVALID_FILE_ATTRIBUTES) { |
4786 | isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); |
4787 | setfull(path,mode,isdir); |
4788 | } else { |
4789 | printf("** Could not access "); |
4790 | printname(stdout,path); |
4791 | printf("\n"); |
4792 | printerror(stdout); |
4793 | errors++; |
4794 | err = TRUE; |
4795 | } |
4796 | return (!err); |
4797 | } |
4798 | |
4799 | #else |
4800 | |
4801 | /* |
4802 | * Display all the parameters associated to a file (Linux version) |
4803 | */ |
4804 | |
4805 | void showfull(const char *fullname, BOOL isdir) |
4806 | { |
4807 | static char attr[MAXATTRSZ]; |
4808 | static char part[MAXATTRSZ]; |
4809 | #if POSIXACLS |
4810 | struct POSIX_SECURITY *pxdesc; |
4811 | #endif |
4812 | struct SECURITY_DATA *psecurdata; |
4813 | char *newattr; |
4814 | int securindex; |
4815 | int mode; |
4816 | int level; |
4817 | int attrib; |
4818 | u32 attrsz; |
4819 | u32 partsz; |
4820 | uid_t uid; |
4821 | gid_t gid; |
4822 | |
4823 | if (opt_v || opt_b) |
4824 | printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); |
4825 | |
4826 | /* get individual parameters, as when trying to get them */ |
4827 | /* all, and one (typically SACL) is missing, we get none */ |
4828 | /* and concatenate them, to be able to compute the checksum */ |
4829 | |
4830 | partsz = 0; |
4831 | securindex = ntfs_get_file_security(ntfs_context,fullname, |
4832 | OWNER_SECURITY_INFORMATION, |
4833 | (char*)part,MAXATTRSZ,&partsz); |
4834 | |
4835 | attrib = ntfs_get_file_attributes(ntfs_context, fullname); |
4836 | if (attrib == INVALID_FILE_ATTRIBUTES) { |
4837 | printf("** Could not get file attrib\n"); |
4838 | errors++; |
4839 | } |
4840 | if ((securindex < 0) |
4841 | || (securindex >= MAXSECURID) |
4842 | || ((securindex > 0) |
4843 | && ((!opt_r && !opt_b) |
4844 | || !securdata[securindex >> SECBLKSZ] |
4845 | || !securdata[securindex >> SECBLKSZ][securindex & ((1 << SECBLKSZ) - 1)].filecount))) |
4846 | { |
4847 | if (opt_v || opt_b) { |
4848 | if ((securindex < -1) || (securindex >= MAXSECURID)) |
4849 | printf("Security key : 0x%x out of range\n",securindex); |
4850 | else |
4851 | if (securindex == -1) |
4852 | printf("Security key : none\n"); |
4853 | else |
4854 | printf("Security key : 0x%x\n",securindex); |
4855 | } else { |
4856 | printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
4857 | if ((securindex < -1) || (securindex >= MAXSECURID)) |
4858 | printf(" : key 0x%x out of range\n",securindex); |
4859 | else |
4860 | if (securindex == -1) |
4861 | printf(" : no key\n"); |
4862 | else |
4863 | printf(" : key 0x%x\n",securindex); |
4864 | } |
4865 | |
4866 | attrsz = getfull(attr, fullname); |
4867 | if (attrsz) { |
4868 | psecurdata = (struct SECURITY_DATA*)NULL; |
4869 | if ((securindex < MAXSECURID) && (securindex > 0)) { |
4870 | if (!securdata[securindex >> SECBLKSZ]) |
4871 | newblock(securindex); |
4872 | if (securdata[securindex >> SECBLKSZ]) |
4873 | psecurdata = &securdata[securindex >> SECBLKSZ] |
4874 | [securindex & ((1 << SECBLKSZ) - 1)]; |
4875 | } |
4876 | if (opt_v && (opt_a || opt_b) && psecurdata) { |
4877 | newattr = (char*)malloc(attrsz); |
4878 | printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), |
4879 | fullname, |
4880 | (unsigned long)hash((le32*)attr,attrsz)); |
4881 | if (newattr) { |
4882 | memcpy(newattr,attr,attrsz); |
4883 | psecurdata->attr = newattr; |
4884 | } |
4885 | } |
4886 | if ((opt_v || opt_b) |
4887 | && ((securindex >= MAXSECURID) |
4888 | || (securindex <= 0) |
4889 | || !psecurdata |
4890 | || (!psecurdata->filecount |
4891 | && !psecurdata->flags))) { |
4892 | hexdump(attr,attrsz,8); |
4893 | printf("Computed hash : 0x%08lx\n", |
4894 | (unsigned long)hash((le32*)attr,attrsz)); |
4895 | } |
4896 | if (ntfs_valid_descr((char*)attr,attrsz)) { |
4897 | #if POSIXACLS |
4898 | pxdesc = linux_permissions_posix(attr,isdir); |
4899 | if (pxdesc) |
4900 | mode = pxdesc->mode; |
4901 | else |
4902 | mode = 0; |
4903 | #else |
4904 | mode = linux_permissions(attr,isdir); |
4905 | #endif |
4906 | attrib = ntfs_get_file_attributes(ntfs_context,fullname); |
4907 | if (opt_v >= 2) { |
4908 | level = (opt_b ? 4 : 0); |
4909 | showheader(attr,level); |
4910 | showusid(attr,level); |
4911 | showgsid(attr,level); |
4912 | showdacl(attr,isdir,level); |
4913 | showsacl(attr,isdir,level); |
4914 | } |
4915 | if (attrib != INVALID_FILE_ATTRIBUTES) |
4916 | printf("Windows attrib : 0x%x\n",attrib); |
4917 | uid = linux_owner(attr); |
4918 | gid = linux_group(attr); |
4919 | if (opt_b) { |
4920 | printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", |
4921 | (int)uid,(int)gid,mode); |
4922 | } else { |
4923 | printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
4924 | (int)uid,(int)gid,mode); |
4925 | } |
4926 | #if POSIXACLS |
4927 | if (pxdesc) { |
4928 | if (!opt_b |
4929 | && (pxdesc->defcnt |
4930 | || (pxdesc->tagsset |
4931 | & (POSIX_ACL_USER |
4932 | | POSIX_ACL_GROUP |
4933 | | POSIX_ACL_MASK)))) |
4934 | showposix(pxdesc); |
4935 | free(pxdesc); |
4936 | } |
4937 | #endif |
4938 | if ((opt_r || opt_b) && (securindex < MAXSECURID) |
4939 | && (securindex > 0) && psecurdata) { |
4940 | psecurdata->filecount++; |
4941 | psecurdata->mode = mode; |
4942 | } |
4943 | } else { |
4944 | printf("** Descriptor fails sanity check\n"); |
4945 | errors++; |
4946 | } |
4947 | } |
4948 | } else |
4949 | if (securindex > 0) { |
4950 | if (securdata[securindex >> SECBLKSZ]) { |
4951 | psecurdata = &securdata[securindex >> SECBLKSZ] |
4952 | [securindex & ((1 << SECBLKSZ) - 1)]; |
4953 | psecurdata->filecount++; |
4954 | if (opt_b || opt_r) { |
4955 | if (!opt_b && !opt_v) |
4956 | printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); |
4957 | printf("Security key : 0x%x mode %03o (already displayed)\n", |
4958 | securindex,psecurdata->mode); |
4959 | if (attrib != INVALID_FILE_ATTRIBUTES) |
4960 | printf("Windows attrib : 0x%x\n",attrib); |
4961 | } else { |
4962 | printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
4963 | printf(" : key 0x%x\n",securindex); |
4964 | } |
4965 | if ((opt_a || opt_b) && opt_v |
4966 | && psecurdata && psecurdata->attr) { |
4967 | printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), |
4968 | fullname, |
4969 | (unsigned long)hash((le32*)psecurdata->attr, |
4970 | ntfs_attr_size(psecurdata->attr))); |
4971 | } |
4972 | } |
4973 | } else { |
4974 | if (!opt_v && !opt_b) |
4975 | printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
4976 | printf(" (Failed)\n"); |
4977 | printf("** Could not get security data of %s, partsz %d\n", |
4978 | fullname,partsz); |
4979 | printerror(stdout); |
4980 | errors++; |
4981 | } |
4982 | } |
4983 | |
4984 | BOOL recurseshow(const char *path) |
4985 | { |
4986 | struct CALLBACK dircontext; |
4987 | struct LINK *current; |
4988 | BOOL isdir; |
4989 | BOOL err; |
4990 | |
4991 | err = FALSE; |
4992 | dircontext.head = (struct LINK*)NULL; |
4993 | dircontext.dir = path; |
4994 | isdir = ntfs_read_directory(ntfs_context, path, |
4995 | callback, &dircontext); |
4996 | if (isdir) { |
4997 | showfull(path,TRUE); |
4998 | if (opt_v) { |
4999 | if (opt_b) |
5000 | printf("#\n#\n"); |
5001 | else |
5002 | printf("\n\n"); |
5003 | } |
5004 | while (dircontext.head) { |
5005 | current = dircontext.head; |
5006 | if (recurseshow(current->name)) err = TRUE; |
5007 | dircontext.head = dircontext.head->next; |
5008 | free(current); |
5009 | } |
5010 | } else |
5011 | if (errno == ENOTDIR) { |
5012 | showfull(path,FALSE); |
5013 | if (opt_v) { |
5014 | if (opt_b) |
5015 | printf("#\n#\n"); |
5016 | else |
5017 | printf("\n\n"); |
5018 | } |
5019 | } else { |
5020 | printf("** Could not access %s\n",path); |
5021 | printerror(stdout); |
5022 | errors++; |
5023 | err = TRUE; |
5024 | } |
5025 | return (!err); |
5026 | } |
5027 | |
5028 | |
5029 | BOOL singleshow(const char *path) |
5030 | { |
5031 | BOOL isdir; |
5032 | BOOL err; |
5033 | |
5034 | err = FALSE; |
5035 | isdir = ntfs_read_directory(ntfs_context, path, |
5036 | callback, (struct CALLBACK*)NULL); |
5037 | if (isdir || (errno == ENOTDIR)) |
5038 | showfull(path,isdir); |
5039 | else { |
5040 | printf("** Could not access %s\n",path); |
5041 | printerror(stdout); |
5042 | errors++; |
5043 | err = TRUE; |
5044 | } |
5045 | return (err); |
5046 | } |
5047 | |
5048 | #ifdef HAVE_SETXATTR |
5049 | |
5050 | static ssize_t ntfs_getxattr(const char *path, const char *name, void *value, size_t size) |
5051 | { |
5052 | #if defined(__APPLE__) || defined(__DARWIN__) |
5053 | return getxattr(path, name, value, size, 0, 0); |
5054 | #else |
5055 | return getxattr(path, name, value, size); |
5056 | #endif |
5057 | } |
5058 | |
5059 | /* |
5060 | * Display all the parameters associated to a mounted file |
5061 | */ |
5062 | |
5063 | void showmounted(const char *fullname) |
5064 | { |
5065 | |
5066 | static char attr[MAXATTRSZ]; |
5067 | struct stat st; |
5068 | #if POSIXACLS |
5069 | struct POSIX_SECURITY *pxdesc; |
5070 | #endif |
5071 | BOOL mapped; |
5072 | int attrsz; |
5073 | int mode; |
5074 | uid_t uid; |
5075 | gid_t gid; |
5076 | u32 attrib; |
5077 | int level; |
5078 | BOOL isdir; |
5079 | |
5080 | if (!stat(fullname,&st)) { |
5081 | isdir = S_ISDIR(st.st_mode); |
5082 | printf("%s ",(isdir ? "Directory" : "File")); |
5083 | printname(stdout,fullname); |
5084 | printf("\n"); |
5085 | |
5086 | attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ); |
5087 | if (attrsz > 0) { |
5088 | if (opt_v) { |
5089 | hexdump(attr,attrsz,8); |
5090 | printf("Computed hash : 0x%08lx\n", |
5091 | (unsigned long)hash((le32*)attr,attrsz)); |
5092 | } |
5093 | if (ntfs_getxattr(fullname,"system.ntfs_attrib",&attrib,4) != 4) { |
5094 | printf("** Could not get file attrib\n"); |
5095 | errors++; |
5096 | } else |
5097 | printf("Windows attrib : 0x%x\n",(int)attrib); |
5098 | if (ntfs_valid_descr(attr,attrsz)) { |
5099 | mapped = !local_build_mapping(context.mapping,fullname); |
5100 | #if POSIXACLS |
5101 | if (mapped) { |
5102 | pxdesc = linux_permissions_posix(attr,isdir); |
5103 | if (pxdesc) |
5104 | mode = pxdesc->mode; |
5105 | else |
5106 | mode = 0; |
5107 | } else { |
5108 | pxdesc = (struct POSIX_SECURITY*)NULL; |
5109 | mode = linux_permissions(attr,isdir); |
5110 | printf("No user mapping : " |
5111 | "cannot display the Posix ACL\n"); |
5112 | } |
5113 | #else |
5114 | mode = linux_permissions(attr,isdir); |
5115 | #endif |
5116 | if (opt_v >= 2) { |
5117 | level = (opt_b ? 4 : 0); |
5118 | showheader(attr,level); |
5119 | showusid(attr,level); |
5120 | showgsid(attr,level); |
5121 | showdacl(attr,isdir,level); |
5122 | showsacl(attr,isdir,level); |
5123 | } |
5124 | if (mapped) { |
5125 | uid = linux_owner(attr); |
5126 | gid = linux_group(attr); |
5127 | printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
5128 | (int)uid,(int)gid,mode); |
5129 | } else { |
5130 | printf("Interpreted Unix mode 0%03o (owner and group are unmapped)\n", |
5131 | mode); |
5132 | } |
5133 | #if POSIXACLS |
5134 | if (pxdesc) { |
5135 | if ((pxdesc->defcnt |
5136 | || (pxdesc->tagsset |
5137 | & (POSIX_ACL_USER |
5138 | | POSIX_ACL_GROUP |
5139 | | POSIX_ACL_MASK)))) |
5140 | showposix(pxdesc); |
5141 | #if USESTUBS |
5142 | stdfree(pxdesc); /* allocated within library */ |
5143 | #else |
5144 | free(pxdesc); |
5145 | #endif |
5146 | } |
5147 | if (mapped) |
5148 | ntfs_free_mapping(context.mapping); |
5149 | #endif |
5150 | } else |
5151 | printf("Descriptor fails sanity check\n"); |
5152 | } else { |
5153 | printf("** Could not get the NTFS ACL, check whether file is on NTFS\n"); |
5154 | errors++; |
5155 | } |
5156 | } else |
5157 | printf("%s not found\n",fullname); |
5158 | } |
5159 | |
5160 | #else /* HAVE_SETXATTR */ |
5161 | |
5162 | void showmounted(const char *fullname __attribute__((unused))) |
5163 | { |
5164 | fprintf(stderr,"Not possible on this configuration\n"); |
5165 | } |
5166 | |
5167 | #endif /* HAVE_SETXATTR */ |
5168 | |
5169 | #if POSIXACLS |
5170 | |
5171 | BOOL recurseset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
5172 | { |
5173 | struct CALLBACK dircontext; |
5174 | struct LINK *current; |
5175 | BOOL isdir; |
5176 | BOOL err; |
5177 | |
5178 | err = FALSE; |
5179 | dircontext.head = (struct LINK*)NULL; |
5180 | dircontext.dir = path; |
5181 | isdir = ntfs_read_directory(ntfs_context, path, |
5182 | callback, &dircontext); |
5183 | if (isdir) { |
5184 | err = !setfull_posix(path,pxdesc,TRUE); |
5185 | if (err) { |
5186 | printf("** Failed to update %s\n",path); |
5187 | printerror(stdout); |
5188 | errors++; |
5189 | } else { |
5190 | if (opt_b) |
5191 | printf("#\n#\n"); |
5192 | else |
5193 | printf("\n\n"); |
5194 | while (dircontext.head) { |
5195 | current = dircontext.head; |
5196 | recurseset_posix(current->name,pxdesc); |
5197 | dircontext.head = dircontext.head->next; |
5198 | free(current); |
5199 | } |
5200 | } |
5201 | } else |
5202 | if (errno == ENOTDIR) { |
5203 | err = !setfull_posix(path,pxdesc,FALSE); |
5204 | if (err) { |
5205 | printf("** Failed to update %s\n",path); |
5206 | printerror(stdout); |
5207 | errors++; |
5208 | } |
5209 | } else { |
5210 | printf("** Could not access %s\n",path); |
5211 | printerror(stdout); |
5212 | errors++; |
5213 | err = TRUE; |
5214 | } |
5215 | return (!err); |
5216 | } |
5217 | |
5218 | #else |
5219 | |
5220 | BOOL recurseset(const char *path, int mode) |
5221 | { |
5222 | struct CALLBACK dircontext; |
5223 | struct LINK *current; |
5224 | BOOL isdir; |
5225 | BOOL err; |
5226 | |
5227 | err = FALSE; |
5228 | dircontext.head = (struct LINK*)NULL; |
5229 | dircontext.dir = path; |
5230 | isdir = ntfs_read_directory(ntfs_context, path, |
5231 | callback, &dircontext); |
5232 | if (isdir) { |
5233 | setfull(path,mode,TRUE); |
5234 | if (opt_b) |
5235 | printf("#\n#\n"); |
5236 | else |
5237 | printf("\n\n"); |
5238 | while (dircontext.head) { |
5239 | current = dircontext.head; |
5240 | recurseset(current->name,mode); |
5241 | dircontext.head = dircontext.head->next; |
5242 | free(current); |
5243 | } |
5244 | } else |
5245 | if (errno == ENOTDIR) |
5246 | setfull(path,mode,FALSE); |
5247 | else { |
5248 | printf("** Could not access %s\n",path); |
5249 | printerror(stdout); |
5250 | errors++; |
5251 | err = TRUE; |
5252 | } |
5253 | return (!err); |
5254 | } |
5255 | |
5256 | #endif |
5257 | |
5258 | #if POSIXACLS |
5259 | |
5260 | BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
5261 | { |
5262 | BOOL isdir; |
5263 | BOOL err; |
5264 | |
5265 | err = FALSE; |
5266 | isdir = ntfs_read_directory(ntfs_context, path, |
5267 | callback, (struct CALLBACK*)NULL); |
5268 | if (isdir || (errno == ENOTDIR)) { |
5269 | err = !setfull_posix(path,pxdesc,isdir); |
5270 | if (err) { |
5271 | printf("** Failed to update %s\n",path); |
5272 | printerror(stdout); |
5273 | errors++; |
5274 | } |
5275 | } else { |
5276 | printf("** Could not access %s\n",path); |
5277 | printerror(stdout); |
5278 | errors++; |
5279 | err = TRUE; |
5280 | } |
5281 | return (!err); |
5282 | } |
5283 | |
5284 | #endif |
5285 | |
5286 | BOOL singleset(const char *path, int mode) |
5287 | { |
5288 | BOOL isdir; |
5289 | BOOL err; |
5290 | |
5291 | err = FALSE; |
5292 | isdir = ntfs_read_directory(ntfs_context, path, |
5293 | callback, (struct CALLBACK*)NULL); |
5294 | if (isdir || (errno == ENOTDIR)) |
5295 | setfull(path,mode,isdir); |
5296 | else { |
5297 | printf("** Could not access %s\n",path); |
5298 | printerror(stdout); |
5299 | errors++; |
5300 | err = TRUE; |
5301 | } |
5302 | return (!err); |
5303 | } |
5304 | |
5305 | int callback(struct CALLBACK *dircontext, char *ntfsname, |
5306 | int length, int type, |
5307 | long long pos __attribute__((unused)), u64 mft_ref __attribute__((unused)), |
5308 | unsigned int dt_type __attribute__((unused))) |
5309 | { |
5310 | struct LINK *linkage; |
5311 | char *name; |
5312 | int newlth; |
5313 | int size; |
5314 | |
5315 | size = utf8size(ntfsname,length); |
5316 | if (dircontext |
5317 | && (type != 2) /* 2 : dos name (8+3) */ |
5318 | && (size > 0) /* chars convertible to utf8 */ |
5319 | && ((length > 2) |
5320 | || (ntfsname[0] != '.') |
5321 | || (ntfsname[1] != '\0') |
5322 | || ((ntfsname[2] || ntfsname[3]) |
5323 | && ((ntfsname[2] != '.') || (ntfsname[3] != '\0'))))) { |
5324 | linkage = (struct LINK*)malloc(sizeof(struct LINK) |
5325 | + strlen(dircontext->dir) |
5326 | + size + 2); |
5327 | if (linkage) { |
5328 | /* may find ".fuse_hidden*" files */ |
5329 | /* recommendation is not to hide them, so that */ |
5330 | /* the user has a clue to delete them */ |
5331 | strcpy(linkage->name,dircontext->dir); |
5332 | if (linkage->name[strlen(linkage->name) - 1] != '/') |
5333 | strcat(linkage->name,"/"); |
5334 | name = &linkage->name[strlen(linkage->name)]; |
5335 | newlth = makeutf8(name,ntfsname,length); |
5336 | name[newlth] = 0; |
5337 | linkage->next = dircontext->head; |
5338 | dircontext->head = linkage; |
5339 | } |
5340 | } |
5341 | return (0); |
5342 | } |
5343 | |
5344 | #endif |
5345 | |
5346 | #ifdef WIN32 |
5347 | |
5348 | /* |
5349 | * Backup security descriptors in a directory tree (Windows mode) |
5350 | */ |
5351 | |
5352 | BOOL backup(const char *root) |
5353 | { |
5354 | BOOL err; |
5355 | time_t now; |
5356 | const char *txtime; |
5357 | |
5358 | now = time((time_t*)NULL); |
5359 | txtime = ctime(&now); |
5360 | printf("#\n# Recursive ACL collection on %s#\n",txtime); |
5361 | err = recurseshow(root); |
5362 | return (err); |
5363 | } |
5364 | |
5365 | #else |
5366 | |
5367 | /* |
5368 | * Backup security descriptors in a directory tree (Linux mode) |
5369 | */ |
5370 | |
5371 | BOOL backup(const char *volume, const char *root) |
5372 | { |
5373 | BOOL err; |
5374 | int count; |
5375 | int i,j; |
5376 | time_t now; |
5377 | const char *txtime; |
5378 | |
5379 | now = time((time_t*)NULL); |
5380 | txtime = ctime(&now); |
5381 | if (!getuid() && open_security_api()) { |
5382 | if (open_volume(volume,MS_RDONLY)) { |
5383 | printf("#\n# Recursive ACL collection on %s#\n",txtime); |
5384 | err = recurseshow(root); |
5385 | count = 0; |
5386 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
5387 | if (securdata[i]) |
5388 | for (j=0; j<(1 << SECBLKSZ); j++) |
5389 | if (securdata[i][j].filecount) { |
5390 | count++; |
5391 | } |
5392 | printf("# %d security keys\n",count); |
5393 | close_volume(volume); |
5394 | } else { |
5395 | fprintf(stderr,"Could not open volume %s\n",volume); |
5396 | printerror(stdout); |
5397 | err = TRUE; |
5398 | } |
5399 | close_security_api(); |
5400 | } else { |
5401 | if (getuid()) |
5402 | fprintf(stderr,"This is only possible as root\n"); |
5403 | else |
5404 | fprintf(stderr,"Could not open security API\n"); |
5405 | err = TRUE; |
5406 | } |
5407 | return (err); |
5408 | } |
5409 | |
5410 | #endif |
5411 | |
5412 | #ifdef WIN32 |
5413 | |
5414 | /* |
5415 | * List security descriptors in a directory tree (Windows mode) |
5416 | */ |
5417 | |
5418 | BOOL listfiles(const char *root) |
5419 | { |
5420 | BOOL err; |
5421 | |
5422 | if (opt_r) { |
5423 | printf("\nRecursive file check\n"); |
5424 | err = recurseshow(root); |
5425 | } else |
5426 | err = singleshow(root); |
5427 | return (err); |
5428 | } |
5429 | |
5430 | #else |
5431 | |
5432 | /* |
5433 | * List security descriptors in a directory tree (Linux mode) |
5434 | */ |
5435 | |
5436 | BOOL listfiles(const char *volume, const char *root) |
5437 | { |
5438 | BOOL err; |
5439 | int i,j; |
5440 | int count; |
5441 | |
5442 | if (!getuid() && open_security_api()) { |
5443 | if (open_volume(volume,MS_RDONLY)) { |
5444 | if (opt_r) { |
5445 | printf("\nRecursive file check\n"); |
5446 | err = recurseshow(root); |
5447 | printf("Summary\n"); |
5448 | count = 0; |
5449 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
5450 | if (securdata[i]) |
5451 | for (j=0; j<(1 << SECBLKSZ); j++) |
5452 | if (securdata[i][j].filecount) { |
5453 | printf("Key 0x%x : %d files, mode 0%03o\n", |
5454 | i*(1 << SECBLKSZ)+j,securdata[i][j].filecount, |
5455 | securdata[i][j].mode); |
5456 | count++; |
5457 | } |
5458 | printf("%d security keys\n",count); |
5459 | } else |
5460 | err = singleshow(root); |
5461 | close_volume(volume); |
5462 | } else { |
5463 | fprintf(stderr,"Could not open volume %s\n",volume); |
5464 | printerror(stdout); |
5465 | err = TRUE; |
5466 | } |
5467 | close_security_api(); |
5468 | } else { |
5469 | if (getuid()) |
5470 | fprintf(stderr,"This is only possible as root\n"); |
5471 | else |
5472 | fprintf(stderr,"Could not open security API\n"); |
5473 | err = TRUE; |
5474 | } |
5475 | return (err); |
5476 | } |
5477 | |
5478 | #endif |
5479 | |
5480 | #ifndef WIN32 |
5481 | |
5482 | /* |
5483 | * Check whether a SDS entry is valid |
5484 | */ |
5485 | |
5486 | BOOL valid_sds(const char *attr, unsigned int offset, |
5487 | unsigned int entrysz, unsigned int size, u32 prevkey, |
5488 | BOOL second) |
5489 | { |
5490 | BOOL unsane; |
5491 | u32 comphash; |
5492 | u32 key; |
5493 | |
5494 | unsane = FALSE; |
5495 | if (!get4l(attr,0) && !get4l(attr,4)) { |
5496 | printf("Entry at 0x%lx was deleted\n",(long)offset); |
5497 | } else { |
5498 | if ((ntfs_attr_size(&attr[20]) + 20) > entrysz) { |
5499 | printf("** Entry is truncated (expected size %ld)\n", |
5500 | (long)ntfs_attr_size(&attr[20] + 20)); |
5501 | unsane = TRUE; |
5502 | errors++; |
5503 | } |
5504 | if ((ntfs_attr_size(&attr[20]) + 20) < entrysz) { |
5505 | printf("** Extra data appended to entry (expected size %ld)\n", |
5506 | (long)ntfs_attr_size(&attr[20]) + 20); |
5507 | warnings++; |
5508 | } |
5509 | if (!unsane && !ntfs_valid_descr((const char*)&attr[20],size)) { |
5510 | printf("** General sanity check has failed\n"); |
5511 | unsane = TRUE; |
5512 | errors++; |
5513 | } |
5514 | if (!unsane) { |
5515 | comphash = hash((const le32*)&attr[20],entrysz-20); |
5516 | if ((u32)get4l(attr,0) == comphash) { |
5517 | if (opt_v >= 2) |
5518 | printf("Hash 0x%08lx (correct)\n", |
5519 | (unsigned long)comphash); |
5520 | } else { |
5521 | printf("** hash 0x%08lx (computed : 0x%08lx)\n", |
5522 | (unsigned long)get4l(attr,0), |
5523 | (unsigned long)comphash); |
5524 | unsane = TRUE; |
5525 | errors++; |
5526 | } |
5527 | } |
5528 | if (!unsane) { |
5529 | if ((second ? get8l(attr,8) + 0x40000 : get8l(attr,8)) == offset) { |
5530 | if (opt_v >= 2) |
5531 | printf("Offset 0x%lx (correct)\n",(long)offset); |
5532 | } else { |
5533 | printf("** offset 0x%llx (expected : 0x%llx)\n", |
5534 | (long long)get8l(attr,8), |
5535 | (long long)(second ? get8l(attr,8) - 0x40000 : get8l(attr,8))); |
5536 | // unsane = TRUE; |
5537 | errors++; |
5538 | } |
5539 | } |
5540 | if (!unsane) { |
5541 | key = get4l(attr,4); |
5542 | if (opt_v >= 2) |
5543 | printf("Key 0x%x\n",(int)key); |
5544 | if (key) { |
5545 | if (key <= prevkey) { |
5546 | printf("** Unordered key 0x%lx after 0x%lx\n", |
5547 | (long)key,(long)prevkey); |
5548 | unsane = TRUE; |
5549 | errors++; |
5550 | } |
5551 | } |
5552 | } |
5553 | } |
5554 | return (!unsane); |
5555 | } |
5556 | |
5557 | /* |
5558 | * Check whether a SDS entry is consistent with other known data |
5559 | * and store current data for subsequent checks |
5560 | */ |
5561 | |
5562 | int consist_sds(const char *attr, unsigned int offset, |
5563 | unsigned int entrysz, BOOL second) |
5564 | { |
5565 | int errcnt; |
5566 | u32 key; |
5567 | u32 comphash; |
5568 | struct SECURITY_DATA *psecurdata; |
5569 | |
5570 | errcnt = 0; |
5571 | key = get4l(attr,4); |
5572 | if ((key > 0) && (key < MAXSECURID)) { |
5573 | printf("Valid entry at 0x%lx for key 0x%lx\n", |
5574 | (long)offset,(long)key); |
5575 | if (!securdata[key >> SECBLKSZ]) |
5576 | newblock(key); |
5577 | if (securdata[key >> SECBLKSZ]) { |
5578 | psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
5579 | comphash = hash((const le32*)&attr[20],entrysz-20); |
5580 | if (psecurdata->flags & INSDS1) { |
5581 | if (psecurdata->hash != comphash) { |
5582 | printf("** Different hash values : $SDS-1 0x%08lx $SDS-2 0x%08lx\n", |
5583 | (unsigned long)psecurdata->hash, |
5584 | (unsigned long)comphash); |
5585 | errcnt++; |
5586 | errors++; |
5587 | } |
5588 | if (psecurdata->offset != get8l(attr,8)) { |
5589 | printf("** Different offsets : $SDS-1 0x%llx $SDS-2 0x%llx\n", |
5590 | (long long)psecurdata->offset,(long long)get8l(attr,8)); |
5591 | errcnt++; |
5592 | errors++; |
5593 | } |
5594 | if (psecurdata->length != get4l(attr,16)) { |
5595 | printf("** Different lengths : $SDS-1 0x%lx $SDS-2 0x%lx\n", |
5596 | (long)psecurdata->length,(long)get4l(attr,16)); |
5597 | errcnt++; |
5598 | errors++; |
5599 | } |
5600 | } else { |
5601 | if (second) { |
5602 | printf("** Entry was not present in $SDS-1\n"); |
5603 | errcnt++; |
5604 | errors++; |
5605 | } |
5606 | psecurdata->hash = comphash; |
5607 | psecurdata->offset = get8l(attr,8); |
5608 | psecurdata->length = get4l(attr,16); |
5609 | } |
5610 | psecurdata->flags |= (second ? INSDS2 : INSDS1); |
5611 | } |
5612 | } else |
5613 | if (key || get4l(attr,0)) { |
5614 | printf("** Security_id 0x%x out of bounds\n",key); |
5615 | warnings++; |
5616 | } |
5617 | return (errcnt); |
5618 | } |
5619 | |
5620 | |
5621 | /* |
5622 | * Auditing of $SDS (Linux only) |
5623 | */ |
5624 | |
5625 | int audit_sds(BOOL second) |
5626 | { |
5627 | static char attr[MAXATTRSZ + 20]; |
5628 | BOOL isdir; |
5629 | BOOL done; |
5630 | BOOL unsane; |
5631 | u32 prevkey; |
5632 | int errcnt; |
5633 | int size; |
5634 | unsigned int entrysz; |
5635 | unsigned int entryalsz; |
5636 | unsigned int offset; |
5637 | int count; |
5638 | int deleted; |
5639 | int mode; |
5640 | |
5641 | if (second) |
5642 | printf("\nAuditing $SDS-2\n"); |
5643 | else |
5644 | printf("\nAuditing $SDS-1\n"); |
5645 | errcnt = 0; |
5646 | offset = (second ? 0x40000 : 0); |
5647 | count = 0; |
5648 | deleted = 0; |
5649 | done = FALSE; |
5650 | prevkey = 0; |
5651 | |
5652 | /* get size of first record */ |
5653 | |
5654 | size = ntfs_read_sds(ntfs_context,(char*)attr,20,offset); |
5655 | if (size != 20) { |
5656 | if ((size < 0) && (errno == ENOTSUP)) |
5657 | printf("** There is no $SDS-%d in this volume\n", |
5658 | (second ? 2 : 1)); |
5659 | else { |
5660 | printf("** Could not open $SDS-%d, size %d\n", |
5661 | (second ? 2 : 1),size); |
5662 | errors++; |
5663 | errcnt++; |
5664 | } |
5665 | } else |
5666 | do { |
5667 | entrysz = get4l(attr,16); |
5668 | entryalsz = ((entrysz - 1) | 15) + 1; |
5669 | if (entryalsz <= (MAXATTRSZ + 20)) { |
5670 | /* read next header in anticipation, to get its size */ |
5671 | size = ntfs_read_sds(ntfs_context, |
5672 | (char*)&attr[20],entryalsz,offset + 20); |
5673 | if (opt_v) |
5674 | printf("\nAt offset 0x%lx got %lu bytes\n",(long)offset,(long)size); |
5675 | } else { |
5676 | printf("** Security attribute is too long (%ld bytes) - stopping\n", |
5677 | (long)entryalsz); |
5678 | errcnt++; |
5679 | } |
5680 | if ((entryalsz > (MAXATTRSZ + 20)) || (size < (int)(entrysz - 20))) |
5681 | done = TRUE; |
5682 | else { |
5683 | if (opt_v) { |
5684 | printf("Entry size %d bytes\n",entrysz); |
5685 | hexdump(&attr[20],size,8); |
5686 | } |
5687 | |
5688 | unsane = !valid_sds(attr,offset,entrysz, |
5689 | size,prevkey,second); |
5690 | if (!unsane) { |
5691 | if (!get4l(attr,0) && !get4l(attr,4)) |
5692 | deleted++; |
5693 | else |
5694 | count++; |
5695 | errcnt += consist_sds(attr,offset, |
5696 | entrysz, second); |
5697 | if (opt_v >= 2) { |
5698 | isdir = guess_dir(&attr[20]); |
5699 | printf("Assuming %s descriptor\n",(isdir ? "directory" : "file")); |
5700 | showheader(&attr[20],0); |
5701 | showusid(&attr[20],0); |
5702 | showgsid(&attr[20],0); |
5703 | showdacl(&attr[20],isdir,0); |
5704 | showsacl(&attr[20],isdir,0); |
5705 | mode = linux_permissions( |
5706 | &attr[20],isdir); |
5707 | printf("Interpreted Unix mode 0%03o\n",mode); |
5708 | } |
5709 | prevkey = get4l(attr,4); |
5710 | } |
5711 | if (!unsane) { |
5712 | memcpy(attr,&attr[entryalsz],20); |
5713 | offset += entryalsz; |
5714 | if (!get4l(attr,16) |
5715 | || ((((offset - 1) | 0x3ffff) - offset + 1) < 20)) { |
5716 | if (second) |
5717 | offset = ((offset - 1) | 0x7ffff) + 0x40001; |
5718 | else |
5719 | offset = ((offset - 1) | 0x7ffff) + 1; |
5720 | if (opt_v) |
5721 | printf("Trying next SDS-%d block at offset 0x%lx\n", |
5722 | (second ? 2 : 1), (long)offset); |
5723 | size = ntfs_read_sds(ntfs_context, |
5724 | (char*)attr,20,offset); |
5725 | if (size != 20) { |
5726 | if (opt_v) |
5727 | printf("Assuming end of $SDS, got %d bytes\n",size); |
5728 | done = TRUE; |
5729 | } |
5730 | } |
5731 | } else { |
5732 | printf("** Sanity check failed - stopping there\n"); |
5733 | errcnt++; |
5734 | errors++; |
5735 | done = TRUE; |
5736 | } |
5737 | } |
5738 | } while (!done); |
5739 | if (count || deleted || errcnt) { |
5740 | printf("%d valid and %d deleted entries in $SDS-%d\n", |
5741 | count,deleted,(second ? 2 : 1)); |
5742 | printf("%d errors in $SDS-%c\n",errcnt,(second ? '2' : '1')); |
5743 | } |
5744 | return (errcnt); |
5745 | } |
5746 | |
5747 | /* |
5748 | * Check whether a SII entry is sane |
5749 | */ |
5750 | |
5751 | BOOL valid_sii(const char *entry, u32 prevkey) |
5752 | { |
5753 | BOOL valid; |
5754 | u32 key; |
5755 | |
5756 | valid = TRUE; |
5757 | key = get4l(entry,16); |
5758 | if (key <= prevkey) { |
5759 | printf("** Unordered key 0x%lx after 0x%lx\n", |
5760 | (long)key,(long)prevkey); |
5761 | valid = FALSE; |
5762 | errors++; |
5763 | } |
5764 | prevkey = key; |
5765 | if (get2l(entry,0) != 20) { |
5766 | printf("** offset %d (instead of 20)\n",(int)get2l(entry,0)); |
5767 | valid = FALSE; |
5768 | errors++; |
5769 | } |
5770 | if (get2l(entry,2) != 20) { |
5771 | printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); |
5772 | valid = FALSE; |
5773 | errors++; |
5774 | } |
5775 | if (get4l(entry,4) != 0) { |
5776 | printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); |
5777 | valid = FALSE; |
5778 | errors++; |
5779 | } |
5780 | if (get2l(entry,12) & 1) { |
5781 | if (get2l(entry,8) != 48) { |
5782 | printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); |
5783 | valid = FALSE; |
5784 | errors++; |
5785 | } |
5786 | } else |
5787 | if (get2l(entry,8) != 40) { |
5788 | printf("** index size %d (instead of 40)\n",(int)get2l(entry,8)); |
5789 | valid = FALSE; |
5790 | errors++; |
5791 | } |
5792 | if (get2l(entry,10) != 4) { |
5793 | printf("** index key size %d (instead of 4)\n",(int)get2l(entry,10)); |
5794 | valid = FALSE; |
5795 | errors++; |
5796 | } |
5797 | if ((get2l(entry,12) & ~3) != 0) { |
5798 | printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); |
5799 | valid = FALSE; |
5800 | errors++; |
5801 | } |
5802 | if (get2l(entry,14) != 0) { |
5803 | printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); |
5804 | valid = FALSE; |
5805 | errors++; |
5806 | } |
5807 | if (get4l(entry,24) != key) { |
5808 | printf("** key 0x%x (instead of 0x%x)\n", |
5809 | (int)get4l(entry,24),(int)key); |
5810 | valid = FALSE; |
5811 | errors++; |
5812 | } |
5813 | return (valid); |
5814 | } |
5815 | |
5816 | /* |
5817 | * Check whether a SII entry is consistent with other known data |
5818 | */ |
5819 | |
5820 | int consist_sii(const char *entry) |
5821 | { |
5822 | int errcnt; |
5823 | u32 key; |
5824 | struct SECURITY_DATA *psecurdata; |
5825 | |
5826 | errcnt = 0; |
5827 | key = get4l(entry,16); |
5828 | if ((key > 0) && (key < MAXSECURID)) { |
5829 | printf("Valid entry for key 0x%lx\n",(long)key); |
5830 | if (!securdata[key >> SECBLKSZ]) |
5831 | newblock(key); |
5832 | if (securdata[key >> SECBLKSZ]) { |
5833 | psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
5834 | psecurdata->flags |= INSII; |
5835 | if (psecurdata->flags & (INSDS1 | INSDS2)) { |
5836 | if ((u32)get4l(entry,20) != psecurdata->hash) { |
5837 | printf("** hash 0x%x (instead of 0x%x)\n", |
5838 | (unsigned int)get4l(entry,20), |
5839 | (unsigned int)psecurdata->hash); |
5840 | errors++; |
5841 | } |
5842 | if (get8l(entry,28) != psecurdata->offset) { |
5843 | printf("** offset 0x%llx (instead of 0x%llx)\n", |
5844 | (long long)get8l(entry,28), |
5845 | (long long)psecurdata->offset); |
5846 | errors++; |
5847 | } |
5848 | if (get4l(entry,36) != psecurdata->length) { |
5849 | printf("** length 0x%lx (instead of %ld)\n", |
5850 | (long)get4l(entry,36), |
5851 | (long)psecurdata->length); |
5852 | errors++; |
5853 | } |
5854 | } else { |
5855 | printf("** Entry was not present in $SDS\n"); |
5856 | errors++; |
5857 | psecurdata->hash = get4l(entry,20); |
5858 | psecurdata->offset = get8l(entry,28); |
5859 | psecurdata->length = get4l(entry,36); |
5860 | if (opt_v) { |
5861 | printf(" hash 0x%x\n",(unsigned int)psecurdata->hash); |
5862 | printf(" offset 0x%llx\n",(long long)psecurdata->offset); |
5863 | printf(" length %ld\n",(long)psecurdata->length); |
5864 | } |
5865 | errcnt++; |
5866 | } |
5867 | } |
5868 | } else { |
5869 | printf("** Security_id 0x%x out of bounds\n",key); |
5870 | warnings++; |
5871 | } |
5872 | return (errcnt); |
5873 | } |
5874 | |
5875 | |
5876 | /* |
5877 | * Auditing of $SII (Linux only) |
5878 | */ |
5879 | |
5880 | int audit_sii() |
5881 | { |
5882 | char *entry; |
5883 | int errcnt; |
5884 | u32 prevkey; |
5885 | BOOL valid; |
5886 | BOOL done; |
5887 | int count; |
5888 | |
5889 | printf("\nAuditing $SII\n"); |
5890 | errcnt = 0; |
5891 | count = 0; |
5892 | entry = (char*)NULL; |
5893 | prevkey = 0; |
5894 | done = FALSE; |
5895 | do { |
5896 | entry = (char*)ntfs_read_sii(ntfs_context,(void*)entry); |
5897 | if (entry) { |
5898 | valid = valid_sii(entry,prevkey); |
5899 | if (valid) { |
5900 | count++; |
5901 | errcnt += consist_sii(entry); |
5902 | prevkey = get4l(entry,16); |
5903 | } else |
5904 | errcnt++; |
5905 | } else |
5906 | if ((errno == ENOTSUP) && !prevkey) |
5907 | printf("** There is no $SII in this volume\n"); |
5908 | } while (entry && !done); |
5909 | if (count || errcnt) { |
5910 | printf("%d valid entries in $SII\n",count); |
5911 | printf("%d errors in $SII\n",errcnt); |
5912 | } |
5913 | return (errcnt); |
5914 | } |
5915 | |
5916 | /* |
5917 | * Check whether a SII entry is sane |
5918 | */ |
5919 | |
5920 | BOOL valid_sdh(const char *entry, u32 prevkey, u32 prevhash) |
5921 | { |
5922 | BOOL valid; |
5923 | u32 key; |
5924 | u32 currhash; |
5925 | |
5926 | valid = TRUE; |
5927 | currhash = get4l(entry,16); |
5928 | key = get4l(entry,20); |
5929 | if ((currhash < prevhash) |
5930 | || ((currhash == prevhash) && (key <= prevkey))) { |
5931 | printf("** Unordered hash and key 0x%x 0x%x after 0x%x 0x%x\n", |
5932 | (unsigned int)currhash,(unsigned int)key, |
5933 | (unsigned int)prevhash,(unsigned int)prevkey); |
5934 | valid = FALSE; |
5935 | errors++; |
5936 | } |
5937 | if ((opt_v >= 2) && (currhash == prevhash)) |
5938 | printf("Hash collision (not an error)\n"); |
5939 | |
5940 | if (get2l(entry,0) != 24) { |
5941 | printf("** offset %d (instead of 24)\n",(int)get2l(entry,0)); |
5942 | valid = FALSE; |
5943 | errors++; |
5944 | } |
5945 | if (get2l(entry,2) != 20) { |
5946 | printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); |
5947 | valid = FALSE; |
5948 | errors++; |
5949 | } |
5950 | if (get4l(entry,4) != 0) { |
5951 | printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); |
5952 | valid = FALSE; |
5953 | errors++; |
5954 | } |
5955 | if (get2l(entry,12) & 1) { |
5956 | if (get2l(entry,8) != 56) { |
5957 | printf("** index size %d (instead of 56)\n",(int)get2l(entry,8)); |
5958 | valid = FALSE; |
5959 | errors++; |
5960 | } |
5961 | } else |
5962 | if (get2l(entry,8) != 48) { |
5963 | printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); |
5964 | valid = FALSE; |
5965 | errors++; |
5966 | } |
5967 | if (get2l(entry,10) != 8) { |
5968 | printf("** index key size %d (instead of 8)\n",(int)get2l(entry,10)); |
5969 | valid = FALSE; |
5970 | errors++; |
5971 | } |
5972 | if ((get2l(entry,12) & ~3) != 0) { |
5973 | printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); |
5974 | valid = FALSE; |
5975 | errors++; |
5976 | } |
5977 | if (get2l(entry,14) != 0) { |
5978 | printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); |
5979 | valid = FALSE; |
5980 | errors++; |
5981 | } |
5982 | if ((u32)get4l(entry,24) != currhash) { |
5983 | printf("** hash 0x%x (instead of 0x%x)\n", |
5984 | (unsigned int)get4l(entry,24),(unsigned int)currhash); |
5985 | valid = FALSE; |
5986 | errors++; |
5987 | } |
5988 | if (get4l(entry,28) != key) { |
5989 | printf("** key 0x%x (instead of 0x%x)\n", |
5990 | (int)get4l(entry,28),(int)key); |
5991 | valid = FALSE; |
5992 | errors++; |
5993 | } |
5994 | if (get4l(entry,44) |
5995 | && (get4l(entry,44) != 0x490049)) { |
5996 | printf("** fill3 0x%lx (instead of 0 or 0x490049)\n", |
5997 | (long)get4l(entry,44)); |
5998 | valid = FALSE; |
5999 | errors++; |
6000 | } |
6001 | return (valid); |
6002 | } |
6003 | |
6004 | /* |
6005 | * Check whether a SDH entry is consistent with other known data |
6006 | */ |
6007 | |
6008 | int consist_sdh(const char *entry) |
6009 | { |
6010 | int errcnt; |
6011 | u32 key; |
6012 | struct SECURITY_DATA *psecurdata; |
6013 | |
6014 | errcnt = 0; |
6015 | key = get4l(entry,20); |
6016 | if ((key > 0) && (key < MAXSECURID)) { |
6017 | printf("Valid entry for key 0x%lx\n",(long)key); |
6018 | if (!securdata[key >> SECBLKSZ]) |
6019 | newblock(key); |
6020 | if (securdata[key >> SECBLKSZ]) { |
6021 | psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
6022 | psecurdata->flags |= INSDH; |
6023 | if (psecurdata->flags & (INSDS1 | INSDS2 | INSII)) { |
6024 | if ((u32)get4l(entry,24) != psecurdata->hash) { |
6025 | printf("** hash 0x%x (instead of 0x%x)\n", |
6026 | (unsigned int)get4l(entry,24), |
6027 | (unsigned int)psecurdata->hash); |
6028 | errors++; |
6029 | } |
6030 | if (get8l(entry,32) != psecurdata->offset) { |
6031 | printf("** offset 0x%llx (instead of 0x%llx)\n", |
6032 | (long long)get8l(entry,32), |
6033 | (long long)psecurdata->offset); |
6034 | errors++; |
6035 | } |
6036 | if (get4l(entry,40) != psecurdata->length) { |
6037 | printf("** length %ld (instead of %ld)\n", |
6038 | (long)get4l(entry,40), |
6039 | (long)psecurdata->length); |
6040 | errors++; |
6041 | } |
6042 | } else { |
6043 | printf("** Entry was not present in $SDS nor in $SII\n"); |
6044 | errors++; |
6045 | psecurdata->hash = get4l(entry,24); |
6046 | psecurdata->offset = get8l(entry,32); |
6047 | psecurdata->length = get4l(entry,40); |
6048 | if (opt_v) { |
6049 | printf(" offset 0x%llx\n",(long long)psecurdata->offset); |
6050 | printf(" length %ld\n",(long)psecurdata->length); |
6051 | } |
6052 | errcnt++; |
6053 | } |
6054 | } |
6055 | } else { |
6056 | printf("** Security_id 0x%x out of bounds\n",key); |
6057 | warnings++; |
6058 | } |
6059 | return (errcnt); |
6060 | } |
6061 | |
6062 | /* |
6063 | * Auditing of $SDH (Linux only) |
6064 | */ |
6065 | |
6066 | int audit_sdh() |
6067 | { |
6068 | char *entry; |
6069 | int errcnt; |
6070 | int count; |
6071 | u32 prevkey; |
6072 | u32 prevhash; |
6073 | BOOL valid; |
6074 | BOOL done; |
6075 | |
6076 | printf("\nAuditing $SDH\n"); |
6077 | count = 0; |
6078 | errcnt = 0; |
6079 | prevkey = 0; |
6080 | prevhash = 0; |
6081 | entry = (char*)NULL; |
6082 | done = FALSE; |
6083 | do { |
6084 | entry = (char*)ntfs_read_sdh(ntfs_context,(void*)entry); |
6085 | if (entry) { |
6086 | valid = valid_sdh(entry,prevkey,prevhash); |
6087 | if (valid) { |
6088 | count++; |
6089 | errcnt += consist_sdh(entry); |
6090 | prevhash = get4l(entry,16); |
6091 | prevkey = get4l(entry,20); |
6092 | } else |
6093 | errcnt++; |
6094 | } else |
6095 | if ((errno == ENOTSUP) && !prevkey) |
6096 | printf("** There is no $SDH in this volume\n"); |
6097 | } while (entry && !done); |
6098 | if (count || errcnt) { |
6099 | printf("%d valid entries in $SDH\n",count); |
6100 | printf("%d errors in $SDH\n",errcnt); |
6101 | } |
6102 | return (errcnt); |
6103 | } |
6104 | |
6105 | /* |
6106 | * Audit summary |
6107 | */ |
6108 | |
6109 | void audit_summary() |
6110 | { |
6111 | int count; |
6112 | int flags; |
6113 | int cnt; |
6114 | int found; |
6115 | int i,j; |
6116 | |
6117 | count = 0; |
6118 | found = 0; |
6119 | if (opt_r) printf("Summary of security key use :\n"); |
6120 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
6121 | if (securdata[i]) |
6122 | for (j=0; j<(1 << SECBLKSZ); j++) { |
6123 | flags = securdata[i][j].flags & (INSDS1 + INSDS2 + INSII + INSDH); |
6124 | if (flags) found++; |
6125 | if (flags |
6126 | && (flags != (INSDS1 + INSDS2 + INSII + INSDH))) |
6127 | { |
6128 | if (!count && !opt_r) |
6129 | printf("\n** Keys not present in all files :\n"); |
6130 | cnt = securdata[i][j].filecount; |
6131 | if (opt_r) |
6132 | printf("Key 0x%x used by %d %s, not in", |
6133 | i*(1 << SECBLKSZ)+j,cnt, |
6134 | (cnt > 1 ? "files" : "file")); |
6135 | else |
6136 | printf("Key 0x%x not in", i*(1 << SECBLKSZ)+j); |
6137 | if (!(flags & INSDS1)) |
6138 | printf(" SDS-1"); |
6139 | if (!(flags & INSDS2)) |
6140 | printf(" SDS-2"); |
6141 | if (!(flags & INSII)) |
6142 | printf(" SII"); |
6143 | if (!(flags & INSDH)) |
6144 | printf(" SDH"); |
6145 | printf("\n"); |
6146 | count++; |
6147 | } else { |
6148 | cnt = securdata[i][j].filecount; |
6149 | if (opt_r && cnt) |
6150 | printf("Key 0x%x used by %d %s\n", |
6151 | i*(1 << SECBLKSZ)+j,cnt, |
6152 | (cnt > 1 ? "files" : "file")); |
6153 | } |
6154 | } |
6155 | if (found) { |
6156 | if (count) |
6157 | printf("%d keys not present in all lists\n",count); |
6158 | else |
6159 | printf("All keys are present in all lists\n"); |
6160 | } |
6161 | } |
6162 | |
6163 | /* |
6164 | * Auditing (Linux only) |
6165 | */ |
6166 | |
6167 | BOOL audit(const char *volume) |
6168 | { |
6169 | BOOL err; |
6170 | |
6171 | err = FALSE; |
6172 | if (!getuid() && open_security_api()) { |
6173 | if (open_volume(volume,MS_RDONLY)) { |
6174 | if (audit_sds(FALSE)) err = TRUE; |
6175 | if (audit_sds(TRUE)) err = TRUE; |
6176 | if (audit_sii()) err = TRUE; |
6177 | if (audit_sdh()) err = TRUE; |
6178 | if (opt_r) recurseshow("/"); |
6179 | |
6180 | audit_summary(); |
6181 | close_volume(volume); |
6182 | } |
6183 | else { |
6184 | fprintf(stderr,"Could not open volume %s\n",volume); |
6185 | printerror(stdout); |
6186 | err = TRUE; |
6187 | } |
6188 | close_security_api(); |
6189 | } |
6190 | else { |
6191 | if (getuid()) |
6192 | fprintf(stderr,"This is only possible as root\n"); |
6193 | else fprintf(stderr,"Could not open security API\n"); |
6194 | err = TRUE; |
6195 | } |
6196 | return (err); |
6197 | } |
6198 | |
6199 | #endif |
6200 | |
6201 | #if POSIXACLS |
6202 | |
6203 | /* |
6204 | * Encode a Posix ACL string |
6205 | * [d:]{ugmo}:uid[:perms],... |
6206 | */ |
6207 | |
6208 | struct POSIX_SECURITY *encode_posix_acl(const char *str) |
6209 | { |
6210 | int acccnt; |
6211 | int defcnt; |
6212 | int i,k,l; |
6213 | int c; |
6214 | s32 id; |
6215 | u16 perms; |
6216 | u16 apermsset; |
6217 | u16 dpermsset; |
6218 | u16 tag; |
6219 | u16 tagsset; |
6220 | mode_t mode; |
6221 | BOOL defacl; |
6222 | BOOL dmask; |
6223 | BOOL amask; |
6224 | const char *p; |
6225 | struct POSIX_ACL *acl; |
6226 | struct POSIX_SECURITY *pxdesc; |
6227 | enum { PXBEGIN, PXTAG, PXTAG1, PXID, PXID1, PXID2, |
6228 | PXPERM, PXPERM1, PXPERM2, PXOCT, PXNEXT, PXEND, PXERR |
6229 | } state; |
6230 | |
6231 | /* raw evaluation of ACE count */ |
6232 | p = str; |
6233 | amask = FALSE; |
6234 | dmask = FALSE; |
6235 | if (*p == 'd') { |
6236 | acccnt = 0; |
6237 | defcnt = 1; |
6238 | } else { |
6239 | if ((*p >= '0') && (*p <= '7')) |
6240 | acccnt = 0; |
6241 | else |
6242 | acccnt = 1; |
6243 | defcnt = 0; |
6244 | } |
6245 | while (*p) |
6246 | if (*p++ == ',') { |
6247 | if (*p == 'd') { |
6248 | defcnt++; |
6249 | if (p[1] && (p[2] == 'm')) |
6250 | dmask = TRUE; |
6251 | } else { |
6252 | acccnt++; |
6253 | if (*p == 'm') |
6254 | amask = TRUE; |
6255 | } |
6256 | } |
6257 | /* account for an implicit mask if none defined */ |
6258 | if (acccnt && !amask) |
6259 | acccnt++; |
6260 | if (defcnt && !dmask) |
6261 | defcnt++; |
6262 | pxdesc = (struct POSIX_SECURITY*)malloc(sizeof(struct POSIX_SECURITY) |
6263 | + (acccnt + defcnt)*sizeof(struct POSIX_ACE)); |
6264 | if (pxdesc) { |
6265 | pxdesc->acccnt = acccnt; |
6266 | pxdesc->firstdef = acccnt; |
6267 | pxdesc->defcnt = defcnt; |
6268 | acl = &pxdesc->acl; |
6269 | p = str; |
6270 | state = PXBEGIN; |
6271 | id = 0; |
6272 | defacl = FALSE; |
6273 | mode = 0; |
6274 | apermsset = 0; |
6275 | dpermsset = 0; |
6276 | tag = 0; |
6277 | perms = 0; |
6278 | k = l = 0; |
6279 | c = *p++; |
6280 | while ((state != PXEND) && (state != PXERR)) { |
6281 | switch (state) { |
6282 | case PXBEGIN : |
6283 | if (c == 'd') { |
6284 | defacl = TRUE; |
6285 | state = PXTAG1; |
6286 | break; |
6287 | } else |
6288 | if ((c >= '0') && (c <= '7')) { |
6289 | mode = c - '0'; |
6290 | state = PXOCT; |
6291 | break; |
6292 | } |
6293 | defacl = FALSE; |
6294 | /* fall through */ |
6295 | case PXTAG : |
6296 | switch (c) { |
6297 | case 'u' : |
6298 | tag = POSIX_ACL_USER; |
6299 | state = PXID; |
6300 | break; |
6301 | case 'g' : |
6302 | tag = POSIX_ACL_GROUP; |
6303 | state = PXID; |
6304 | break; |
6305 | case 'o' : |
6306 | tag = POSIX_ACL_OTHER; |
6307 | state = PXID; |
6308 | break; |
6309 | case 'm' : |
6310 | tag = POSIX_ACL_MASK; |
6311 | state = PXID; |
6312 | break; |
6313 | default : |
6314 | state = PXERR; |
6315 | break; |
6316 | } |
6317 | break; |
6318 | case PXTAG1 : |
6319 | if (c == ':') |
6320 | state = PXTAG; |
6321 | else |
6322 | state = PXERR; |
6323 | break; |
6324 | case PXID : |
6325 | if (c == ':') { |
6326 | if ((tag == POSIX_ACL_OTHER) |
6327 | || (tag == POSIX_ACL_MASK)) |
6328 | state = PXPERM; |
6329 | else |
6330 | state = PXID1; |
6331 | } else |
6332 | state = PXERR; |
6333 | break; |
6334 | case PXID1 : |
6335 | if ((c >= '0') && (c <= '9')) { |
6336 | id = c - '0'; |
6337 | state = PXID2; |
6338 | } else |
6339 | if (c == ':') { |
6340 | id = -1; |
6341 | if (tag == POSIX_ACL_USER) |
6342 | tag = POSIX_ACL_USER_OBJ; |
6343 | if (tag == POSIX_ACL_GROUP) |
6344 | tag = POSIX_ACL_GROUP_OBJ; |
6345 | state = PXPERM1; |
6346 | } else |
6347 | state = PXERR; |
6348 | break; |
6349 | case PXID2 : |
6350 | if ((c >= '0') && (c <= '9')) |
6351 | id = 10*id + c - '0'; |
6352 | else |
6353 | if (c == ':') |
6354 | state = PXPERM1; |
6355 | else |
6356 | state = PXERR; |
6357 | break; |
6358 | case PXPERM : |
6359 | if (c == ':') { |
6360 | id = -1; |
6361 | state = PXPERM1; |
6362 | } else |
6363 | state = PXERR; |
6364 | break; |
6365 | case PXPERM1 : |
6366 | if ((c >= '0') && (c <= '7')) { |
6367 | perms = c - '0'; |
6368 | state = PXNEXT; |
6369 | break; |
6370 | } |
6371 | state = PXPERM2; |
6372 | perms = 0; |
6373 | /* fall through */ |
6374 | case PXPERM2 : |
6375 | switch (c) { |
6376 | case 'r' : |
6377 | perms |= POSIX_PERM_R; |
6378 | break; |
6379 | case 'w' : |
6380 | perms |= POSIX_PERM_W; |
6381 | break; |
6382 | case 'x' : |
6383 | perms |= POSIX_PERM_X; |
6384 | break; |
6385 | case ',' : |
6386 | case '\0' : |
6387 | if (defacl) { |
6388 | i = acccnt + l++; |
6389 | dpermsset |= perms; |
6390 | } else { |
6391 | i = k++; |
6392 | apermsset |= perms; |
6393 | } |
6394 | acl->ace[i].tag = tag; |
6395 | acl->ace[i].perms = perms; |
6396 | acl->ace[i].id = id; |
6397 | if (c == '\0') |
6398 | state = PXEND; |
6399 | else |
6400 | state = PXBEGIN; |
6401 | break; |
6402 | } |
6403 | break; |
6404 | case PXNEXT : |
6405 | if (!c || (c == ',')) { |
6406 | if (defacl) { |
6407 | i = acccnt + l++; |
6408 | dpermsset |= perms; |
6409 | } else { |
6410 | i = k++; |
6411 | apermsset |= perms; |
6412 | } |
6413 | acl->ace[i].tag = tag; |
6414 | acl->ace[i].perms = perms; |
6415 | acl->ace[i].id = id; |
6416 | if (c == '\0') |
6417 | state = PXEND; |
6418 | else |
6419 | state = PXBEGIN; |
6420 | } else |
6421 | state = PXERR; |
6422 | break; |
6423 | case PXOCT : |
6424 | if ((c >= '0') && (c <= '7')) |
6425 | mode = (mode << 3) + c - '0'; |
6426 | else |
6427 | if (c == '\0') |
6428 | state = PXEND; |
6429 | else |
6430 | state = PXBEGIN; |
6431 | break; |
6432 | default : |
6433 | break; |
6434 | } |
6435 | c = *p++; |
6436 | } |
6437 | /* insert default mask if none defined */ |
6438 | if (acccnt && !amask) { |
6439 | i = k++; |
6440 | acl->ace[i].tag = POSIX_ACL_MASK; |
6441 | acl->ace[i].perms = apermsset; |
6442 | acl->ace[i].id = -1; |
6443 | } |
6444 | if (defcnt && !dmask) { |
6445 | i = acccnt + l++; |
6446 | acl->ace[i].tag = POSIX_ACL_MASK; |
6447 | acl->ace[i].perms = dpermsset; |
6448 | acl->ace[i].id = -1; |
6449 | } |
6450 | /* compute the mode and tagsset */ |
6451 | tagsset = 0; |
6452 | for (i=0; i<acccnt; i++) |
6453 | tagsset |= acl->ace[i].tag; |
6454 | switch (acl->ace[i].tag) { |
6455 | case POSIX_ACL_USER_OBJ : |
6456 | mode |= acl->ace[i].perms << 6; |
6457 | break; |
6458 | case POSIX_ACL_GROUP_OBJ : |
6459 | mode |= acl->ace[i].perms << 3; |
6460 | break; |
6461 | case POSIX_ACL_OTHER : |
6462 | mode |= acl->ace[i].perms; |
6463 | break; |
6464 | default : |
6465 | break; |
6466 | } |
6467 | pxdesc->mode = mode; |
6468 | pxdesc->tagsset = tagsset; |
6469 | pxdesc->acl.version = POSIX_VERSION; |
6470 | pxdesc->acl.flags = 0; |
6471 | pxdesc->acl.filler = 0; |
6472 | if (state != PXERR) |
6473 | ntfs_sort_posix(pxdesc); |
6474 | showposix(pxdesc); |
6475 | if ((state == PXERR) |
6476 | || (k != acccnt) |
6477 | || (l != defcnt) |
6478 | || !ntfs_valid_posix(pxdesc)) { |
6479 | if (~pxdesc->tagsset |
6480 | & (POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) |
6481 | fprintf(stderr,"User, group or other permissions missing\n"); |
6482 | else |
6483 | fprintf(stderr,"Bad ACL description\n"); |
6484 | free(pxdesc); |
6485 | pxdesc = (struct POSIX_SECURITY*)NULL; |
6486 | } else |
6487 | if (opt_v >= 2) { |
6488 | printf("Interpreted input description :\n"); |
6489 | showposix(pxdesc); |
6490 | } |
6491 | } else |
6492 | errno = ENOMEM; |
6493 | return (pxdesc); |
6494 | } |
6495 | |
6496 | #endif /* POSIXACLS */ |
6497 | |
6498 | |
6499 | int getoptions(int argc, char *argv[]) |
6500 | { |
6501 | int xarg; |
6502 | int narg; |
6503 | const char *parg; |
6504 | BOOL err; |
6505 | |
6506 | opt_a = FALSE; |
6507 | opt_b = FALSE; |
6508 | opt_e = FALSE; |
6509 | opt_h = FALSE; |
6510 | #if FORCEMASK |
6511 | opt_m = FALSE; |
6512 | #endif |
6513 | opt_r = FALSE; |
6514 | opt_s = FALSE; |
6515 | #if SELFTESTS & !USESTUBS |
6516 | opt_t = FALSE; |
6517 | #endif |
6518 | opt_v = 0; |
6519 | xarg = 1; |
6520 | err = FALSE; |
6521 | while ((xarg < argc) && (argv[xarg][0] == '-')) { |
6522 | parg = argv[xarg++]; |
6523 | while (*++parg) |
6524 | switch (*parg) |
6525 | { |
6526 | #ifndef WIN32 |
6527 | case 'a' : |
6528 | opt_a = TRUE; |
6529 | break; |
6530 | #endif |
6531 | case 'b' : |
6532 | opt_b = TRUE; |
6533 | break; |
6534 | case 'e' : |
6535 | opt_e = TRUE; |
6536 | break; |
6537 | case 'h' : |
6538 | opt_h = TRUE; |
6539 | break; |
6540 | #if FORCEMASK |
6541 | case 'm' : |
6542 | opt_m = TRUE; |
6543 | break; |
6544 | #endif |
6545 | case 'r' : |
6546 | case 'R' : |
6547 | opt_r = TRUE; |
6548 | break; |
6549 | case 's' : |
6550 | opt_s = TRUE; |
6551 | break; |
6552 | #if SELFTESTS & !USESTUBS |
6553 | case 't' : |
6554 | opt_t = TRUE; |
6555 | break; |
6556 | #endif |
6557 | case 'v' : |
6558 | opt_v++; |
6559 | break; |
6560 | default : |
6561 | fprintf(stderr,"Invalid option -%c\n",*parg); |
6562 | err = TRUE; |
6563 | } |
6564 | } |
6565 | narg = argc - xarg; |
6566 | #ifdef WIN32 |
6567 | if ( ((opt_h || opt_s) && (narg > 1)) |
6568 | || ((opt_r || opt_b) && ((narg < 1) || (narg > 2))) |
6569 | #if SELFTESTS & !USESTUBS |
6570 | || (opt_t && (narg > 0)) |
6571 | #endif |
6572 | || (opt_e && !opt_s) |
6573 | || (!opt_h && !opt_r && !opt_b && !opt_s |
6574 | #if SELFTESTS & !USESTUBS |
6575 | && !opt_t |
6576 | #endif |
6577 | && ((narg < 1) || (narg > 2)))) |
6578 | |
6579 | err = TRUE; |
6580 | if (err) { |
6581 | xarg = 0; |
6582 | fprintf(stderr,"Usage:\n"); |
6583 | #if SELFTESTS & !USESTUBS |
6584 | fprintf(stderr," secaudit -t\n"); |
6585 | fprintf(stderr," run self-tests\n"); |
6586 | #endif |
6587 | fprintf(stderr," secaudit -h [file]\n"); |
6588 | fprintf(stderr," display security descriptors within file\n"); |
6589 | fprintf(stderr," secaudit [-v] file\n"); |
6590 | fprintf(stderr," display the security parameters of file\n"); |
6591 | fprintf(stderr," secaudit -r[v] directory\n"); |
6592 | fprintf(stderr," display the security parameters of files in directory\n"); |
6593 | fprintf(stderr," secaudit -b[v] directory\n"); |
6594 | fprintf(stderr," backup the security parameters of files in directory\n"); |
6595 | fprintf(stderr," secaudit -s[ev] [backupfile]\n"); |
6596 | fprintf(stderr," set the security parameters as indicated in backup file\n"); |
6597 | fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); |
6598 | fprintf(stderr," secaudit perms file\n"); |
6599 | fprintf(stderr," set the security parameters of file to perms\n"); |
6600 | fprintf(stderr," secaudit -r[v] perms directory\n"); |
6601 | fprintf(stderr," set the security parameters of files in directory to perms\n"); |
6602 | #if POSIXACLS |
6603 | fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); |
6604 | #else |
6605 | fprintf(stderr," Note: perms is an octal mode\n"); |
6606 | #endif |
6607 | fprintf(stderr," -v is for verbose, -vv for very verbose\n"); |
6608 | } |
6609 | #else |
6610 | if ( (opt_h && (narg > 1)) |
6611 | || (opt_a && (narg != 1)) |
6612 | || ((opt_r || opt_b || opt_s) && ((narg < 1) || (narg > 3))) |
6613 | #if SELFTESTS & !USESTUBS |
6614 | || (opt_t && (narg > 0)) |
6615 | #endif |
6616 | || (opt_e && !opt_s) |
6617 | || (!opt_h && !opt_a && !opt_r && !opt_b && !opt_s |
6618 | #if SELFTESTS & !USESTUBS |
6619 | && !opt_t |
6620 | #endif |
6621 | #ifdef HAVE_SETXATTR |
6622 | && ((narg < 1) || (narg > 3)))) |
6623 | #else |
6624 | && ((narg < 2) || (narg > 3)))) |
6625 | #endif |
6626 | err = TRUE; |
6627 | if (err) { |
6628 | xarg = 0; |
6629 | fprintf(stderr,"Usage:\n"); |
6630 | #if SELFTESTS & !USESTUBS |
6631 | fprintf(stderr," secaudit -t\n"); |
6632 | fprintf(stderr," run self-tests\n"); |
6633 | #endif |
6634 | fprintf(stderr," secaudit -h [file]\n"); |
6635 | fprintf(stderr," display security descriptors within file\n"); |
6636 | fprintf(stderr," secaudit -a[rv] volume\n"); |
6637 | fprintf(stderr," audit the volume\n"); |
6638 | fprintf(stderr," secaudit [-v] volume file\n"); |
6639 | fprintf(stderr," display the security parameters of file\n"); |
6640 | fprintf(stderr," secaudit -r[v] volume directory\n"); |
6641 | fprintf(stderr," display the security parameters of files in directory\n"); |
6642 | fprintf(stderr," secaudit -b[v] volume directory\n"); |
6643 | fprintf(stderr," backup the security parameters of files in directory\n"); |
6644 | fprintf(stderr," secaudit -s[ev] volume [backupfile]\n"); |
6645 | fprintf(stderr," set the security parameters as indicated in backup file\n"); |
6646 | fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); |
6647 | fprintf(stderr," secaudit volume perms file\n"); |
6648 | fprintf(stderr," set the security parameters of file to perms\n"); |
6649 | fprintf(stderr," secaudit -r[v] volume perms directory\n"); |
6650 | fprintf(stderr," set the security parameters of files in directory to perms\n"); |
6651 | #ifdef HAVE_SETXATTR |
6652 | fprintf(stderr," special case, does not require being root :\n"); |
6653 | fprintf(stderr," secaudit [-v] mounted-file\n"); |
6654 | fprintf(stderr," display the security parameters of a mounted file\n"); |
6655 | #endif |
6656 | #if POSIXACLS |
6657 | fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); |
6658 | #else |
6659 | fprintf(stderr," Note: perms is an octal mode\n"); |
6660 | #endif |
6661 | fprintf(stderr," -v is for verbose, -vv for very verbose\n"); |
6662 | } |
6663 | #endif |
6664 | if ((sizeof(SID) != 12) && !err) { |
6665 | fprintf(stderr,"Possible alignment problem, check your compiler options\n"); |
6666 | err = TRUE; |
6667 | xarg = 0; |
6668 | } |
6669 | return (xarg); |
6670 | } |
6671 | |
6672 | /* |
6673 | * Memory allocation with checks |
6674 | */ |
6675 | |
6676 | #undef malloc |
6677 | #undef calloc |
6678 | #undef free |
6679 | #undef isalloc |
6680 | |
6681 | void dumpalloc(const char *txt) |
6682 | { |
6683 | struct CHKALLOC *q; |
6684 | |
6685 | if (firstalloc) { |
6686 | printf("alloc table at %s\n",txt); |
6687 | for (q=firstalloc; q; q=q->next) |
6688 | printf("%08lx : %u bytes at %08lx allocated at %s line %d\n", |
6689 | (long)q,(unsigned int)q->size, |
6690 | (long)q->alloc,q->file,q->line); |
6691 | } |
6692 | } |
6693 | |
6694 | void *chkmalloc(size_t size, const char *file, int line) |
6695 | { |
6696 | void *p; |
6697 | struct CHKALLOC *q; |
6698 | |
6699 | p = (void*)malloc(size+1); |
6700 | if (p) { |
6701 | ((unsigned char*)p)[size] = 0xaa; |
6702 | q = (struct CHKALLOC*)malloc(sizeof(struct CHKALLOC)); |
6703 | if (q) { |
6704 | q->next = firstalloc; |
6705 | q->alloc = p; |
6706 | q->size = size; |
6707 | q->file = file; |
6708 | q->line = line; |
6709 | firstalloc = q; |
6710 | } |
6711 | } |
6712 | return (p); |
6713 | } |
6714 | |
6715 | void *chkcalloc(size_t cnt, size_t size, const char *file, int line) |
6716 | { |
6717 | return (chkmalloc(cnt*size,file,line)); |
6718 | } |
6719 | |
6720 | void chkfree(void *p, const char *file, int line) |
6721 | { |
6722 | struct CHKALLOC *q; |
6723 | struct CHKALLOC *r; |
6724 | |
6725 | if (p) { |
6726 | if (firstalloc && (firstalloc->alloc == p)) { |
6727 | r = firstalloc; |
6728 | firstalloc = firstalloc->next; |
6729 | } else { |
6730 | q = firstalloc; |
6731 | if (q) |
6732 | while (q->next && (q->next->alloc != p)) |
6733 | q = q->next; |
6734 | if (q && q->next) { |
6735 | r = q->next; |
6736 | q->next = r->next; |
6737 | } else { |
6738 | r = (struct CHKALLOC*)NULL; |
6739 | printf("** freeing unallocated memory in %s line %d\n",file,line); |
6740 | if (!isatty(1)) |
6741 | fprintf(stderr,"** freeing unallocated memory in %s line %d\n",file,line); |
6742 | } |
6743 | } |
6744 | if (r) { |
6745 | if (((unsigned char*)p)[r->size] != 0xaa) { |
6746 | printf("** memory corruption, alloc in %s line %d release in %s %d\n", |
6747 | r->file,r->line,file,line); |
6748 | if (!isatty(1)) |
6749 | fprintf(stderr,"** memory corruption, alloc in %s line %d release in %s %d\n", |
6750 | r->file,r->line,file,line); |
6751 | } |
6752 | memset(p,0xaa,r->size); |
6753 | free(r); |
6754 | free(p); |
6755 | } |
6756 | } |
6757 | } |
6758 | |
6759 | void stdfree(void *p) |
6760 | { |
6761 | free(p); |
6762 | } |
6763 | |
6764 | BOOL chkisalloc(void *p, const char *file, int line) |
6765 | { |
6766 | struct CHKALLOC *q; |
6767 | |
6768 | if (p) { |
6769 | q = firstalloc; |
6770 | while (q && (q->alloc != p)) |
6771 | q = q->next; |
6772 | } else |
6773 | q = (struct CHKALLOC*)NULL; |
6774 | if (!p || !q) { |
6775 | printf("error in %s %d : 0x%lx not allocated\n",file,line,(long)p); |
6776 | } |
6777 | return (p && q); |
6778 | } |
6779 | |
6780 | |
6781 | |
6782 | |
6783 | #ifdef WIN32 |
6784 | |
6785 | /* |
6786 | * Windows version |
6787 | */ |
6788 | |
6789 | main(argc,argv) |
6790 | int argc; |
6791 | char *argv[]; |
6792 | { |
6793 | FILE *fd; |
6794 | int xarg; |
6795 | int mode; |
6796 | unsigned int size; |
6797 | BOOL cmderr; |
6798 | char *filename; |
6799 | const char *p; |
6800 | int i; |
6801 | #if POSIXACLS |
6802 | struct POSIX_SECURITY *pxdesc; |
6803 | #endif |
6804 | |
6805 | printf("%s\n",BANNER); |
6806 | cmderr = FALSE; |
6807 | errors = 0; |
6808 | warnings = 0; |
6809 | xarg = getoptions(argc,argv); |
6810 | if (xarg) { |
6811 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
6812 | securdata[i] = (struct SECURITY_DATA*)NULL; |
6813 | #if POSIXACLS |
6814 | context.mapping[MAPUSERS] = (struct MAPPING*)NULL; |
6815 | context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
6816 | #endif |
6817 | firstalloc = (struct CHKALLOC*)NULL; |
6818 | mappingtype = MAPNONE; |
6819 | switch (argc - xarg) { |
6820 | case 0 : |
6821 | if (opt_h) |
6822 | showhex(stdin); |
6823 | else |
6824 | if (opt_s) |
6825 | restore(stdin); |
6826 | #if SELFTESTS & !USESTUBS |
6827 | if (opt_t) |
6828 | selftests(); |
6829 | #endif |
6830 | break; |
6831 | case 1 : |
6832 | if (opt_h || opt_s) { |
6833 | fd = fopen(argv[xarg],"r"); |
6834 | if (fd) { |
6835 | if (opt_h) |
6836 | showhex(fd); |
6837 | else |
6838 | restore(fd); |
6839 | fclose(fd); |
6840 | } else { |
6841 | fprintf(stderr,"Could not open %s\n",argv[xarg]); |
6842 | cmderr = TRUE; |
6843 | } |
6844 | } else { |
6845 | size = utf16size(argv[xarg]); |
6846 | if (size) { |
6847 | filename = (char*)malloc(2*size + 2); |
6848 | if (filename) { |
6849 | makeutf16(filename,argv[xarg]); |
6850 | #if POSIXACLS |
6851 | if (local_build_mapping(context.mapping,filename)) { |
6852 | printf("*** Could not get user mapping data\n"); |
6853 | warnings++; |
6854 | } |
6855 | #endif |
6856 | if (opt_b) |
6857 | cmderr = backup(filename); |
6858 | else { |
6859 | if (opt_r) |
6860 | cmderr = listfiles(filename); |
6861 | else |
6862 | cmderr = singleshow(filename); |
6863 | } |
6864 | #if POSIXACLS |
6865 | ntfs_free_mapping(context.mapping); |
6866 | #endif |
6867 | free(filename); |
6868 | } else { |
6869 | fprintf(stderr,"No more memory\n"); |
6870 | cmderr = TRUE; |
6871 | } |
6872 | } else { |
6873 | fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg]); |
6874 | cmderr = TRUE; |
6875 | } |
6876 | } |
6877 | break; |
6878 | case 2 : |
6879 | mode = 0; |
6880 | p = argv[xarg]; |
6881 | #if POSIXACLS |
6882 | pxdesc = encode_posix_acl(p); |
6883 | if (pxdesc) { |
6884 | size = utf16size(argv[xarg + 1]); |
6885 | if (size) { |
6886 | filename = (char*)malloc(2*size + 2); |
6887 | if (filename) { |
6888 | makeutf16(filename,argv[xarg + 1]); |
6889 | if (local_build_mapping(context.mapping,filename)) { |
6890 | printf("*** Could not get user mapping data\n"); |
6891 | warnings++; |
6892 | } |
6893 | if (opt_r) { |
6894 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
6895 | securdata[i] = (struct SECURITY_DATA*)NULL; |
6896 | recurseset_posix(filename,pxdesc); |
6897 | } else |
6898 | singleset_posix(filename,pxdesc); |
6899 | ntfs_free_mapping(context.mapping); |
6900 | free(filename); |
6901 | } else { |
6902 | fprintf(stderr,"No more memory\n"); |
6903 | cmderr = TRUE; |
6904 | } |
6905 | chkfree(pxdesc,__FILE__,__LINE__); |
6906 | } else { |
6907 | fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); |
6908 | cmderr = TRUE; |
6909 | } |
6910 | } |
6911 | #else |
6912 | while ((*p >= '0') && (*p <= '7')) |
6913 | mode = (mode << 3) + (*p++) - '0'; |
6914 | if (*p) { |
6915 | fprintf(stderr,"New mode should be given in octal\n"); |
6916 | cmderr = TRUE; |
6917 | } else { |
6918 | size = utf16size(argv[xarg + 1]); |
6919 | if (size) { |
6920 | filename = (char*)malloc(2*size + 2); |
6921 | if (filename) { |
6922 | makeutf16(filename,argv[xarg + 1]); |
6923 | #if POSIXACLS |
6924 | if (local_build_mapping(&context,filename)) { |
6925 | printf("*** Could not get user mapping data\n"); |
6926 | warnings++; |
6927 | } |
6928 | #endif |
6929 | if (opt_r) { |
6930 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
6931 | securdata[i] = (struct SECURITY_DATA*)NULL; |
6932 | recurseset(filename,mode); |
6933 | } else |
6934 | singleset(filename,mode); |
6935 | free(filename); |
6936 | } else { |
6937 | fprintf(stderr,"No more memory\n"); |
6938 | cmderr = TRUE; |
6939 | } |
6940 | } else { |
6941 | fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); |
6942 | cmderr = TRUE; |
6943 | } |
6944 | } |
6945 | #endif |
6946 | break; |
6947 | #if FORCEMASK |
6948 | case 3 : |
6949 | mode = 0; |
6950 | forcemsk = 0; |
6951 | p = argv[xarg]; |
6952 | while (*p) { |
6953 | if ((*p >= '0') && (*p <= '9')) |
6954 | forcemsk = (forcemsk << 4) + *p - '0'; |
6955 | else forcemsk = (forcemsk << 4) + (*p & 7) + 9; |
6956 | p++; |
6957 | } |
6958 | p = argv[xarg + 1]; |
6959 | while ((*p >= '0') && (*p <= '7')) |
6960 | mode = (mode << 3) + (*p++) - '0'; |
6961 | if (*p) { |
6962 | fprintf(stderr,"New mode should be given in octal\n"); |
6963 | cmderr = TRUE; |
6964 | } else { |
6965 | if (opt_r) { |
6966 | recurseset(argv[xarg + 2],mode); |
6967 | } |
6968 | else singleset(argv[xarg + 2],mode); |
6969 | } |
6970 | break; |
6971 | #endif |
6972 | } |
6973 | if (warnings) |
6974 | printf("** %u %s signalled\n",warnings, |
6975 | (warnings > 1 ? "warnings were" : "warning was")); |
6976 | if (errors) |
6977 | printf("** %u %s found\n",errors, |
6978 | (errors > 1 ? "errors were" : "error was")); |
6979 | else |
6980 | printf("No errors were found\n"); |
6981 | if (!isatty(1)) { |
6982 | fflush(stdout); |
6983 | if (warnings) |
6984 | fprintf(stderr,"** %u %s signalled\n",warnings, |
6985 | (warnings > 1 ? "warnings were" : "warning was")); |
6986 | if (errors) |
6987 | fprintf(stderr,"** %u %s found\n",errors, |
6988 | (errors > 1 ? "errors were" : "error was")); |
6989 | else |
6990 | fprintf(stderr,"No errors were found\n"); |
6991 | freeblocks(); |
6992 | } |
6993 | } |
6994 | dumpalloc("termination"); |
6995 | if (cmderr || errors) |
6996 | exit(1); |
6997 | return (0); |
6998 | } |
6999 | |
7000 | #else |
7001 | |
7002 | /* |
7003 | * Linux version |
7004 | */ |
7005 | |
7006 | int main(int argc, char *argv[]) |
7007 | { |
7008 | FILE *fd; |
7009 | unsigned int mode; |
7010 | const char *p; |
7011 | int xarg; |
7012 | BOOL cmderr; |
7013 | int i; |
7014 | #if POSIXACLS |
7015 | struct POSIX_SECURITY *pxdesc; |
7016 | #endif |
7017 | |
7018 | printf("%s\n",BANNER); |
7019 | cmderr = FALSE; |
7020 | errors = 0; |
7021 | warnings = 0; |
7022 | xarg = getoptions(argc,argv); |
7023 | if (xarg) { |
7024 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
7025 | securdata[i] = (struct SECURITY_DATA*)NULL; |
7026 | #if POSIXACLS |
7027 | context.mapping[MAPUSERS] = (struct MAPPING*)NULL; |
7028 | context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
7029 | #endif |
7030 | firstalloc = (struct CHKALLOC*)NULL; |
7031 | mappingtype = MAPNONE; |
7032 | switch (argc - xarg) { |
7033 | case 0 : |
7034 | if (opt_h) |
7035 | showhex(stdin); |
7036 | #if SELFTESTS & !USESTUBS |
7037 | if (opt_t) |
7038 | selftests(); |
7039 | #endif |
7040 | break; |
7041 | case 1 : |
7042 | if (opt_a) |
7043 | cmderr = audit(argv[xarg]); |
7044 | else |
7045 | if (opt_h) { |
7046 | fd = fopen(argv[xarg],"rb"); |
7047 | if (fd) { |
7048 | showhex(fd); |
7049 | fclose(fd); |
7050 | } else { |
7051 | fprintf(stderr,"Could not open %s\n",argv[xarg]); |
7052 | cmderr = TRUE; |
7053 | } |
7054 | } else |
7055 | if (opt_b) |
7056 | cmderr = backup(argv[xarg],"/"); |
7057 | else |
7058 | if (opt_r) |
7059 | cmderr = listfiles(argv[xarg],"/"); |
7060 | else |
7061 | if (opt_s) |
7062 | cmderr = dorestore(argv[xarg],stdin); |
7063 | else |
7064 | showmounted(argv[xarg]); |
7065 | break; |
7066 | case 2 : |
7067 | if (opt_b) |
7068 | cmderr = backup(argv[xarg],argv[xarg+1]); |
7069 | else |
7070 | if (opt_s) { |
7071 | fd = fopen(argv[xarg+1],"rb"); |
7072 | if (fd) { |
7073 | if (dorestore(argv[xarg],fd)) |
7074 | cmderr = TRUE; |
7075 | fclose(fd); |
7076 | } else { |
7077 | fprintf(stderr,"Could not open %s\n",argv[xarg]); |
7078 | cmderr = TRUE; |
7079 | } |
7080 | } else |
7081 | cmderr = listfiles(argv[xarg],argv[xarg+1]); |
7082 | break; |
7083 | case 3 : |
7084 | mode = 0; |
7085 | p = argv[xarg+1]; |
7086 | #if POSIXACLS |
7087 | pxdesc = encode_posix_acl(p); |
7088 | if (pxdesc) { |
7089 | if (!getuid() && open_security_api()) { |
7090 | if (open_volume(argv[xarg],MS_NONE)) { |
7091 | if (opt_r) { |
7092 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
7093 | securdata[i] = (struct SECURITY_DATA*)NULL; |
7094 | recurseset_posix(argv[xarg + 2],pxdesc); |
7095 | } else |
7096 | singleset_posix(argv[xarg + 2],pxdesc); |
7097 | close_volume(argv[xarg]); |
7098 | } else { |
7099 | fprintf(stderr,"Could not open volume %s\n",argv[xarg]); |
7100 | printerror(stderr); |
7101 | cmderr = TRUE; |
7102 | } |
7103 | close_security_api(); |
7104 | } else { |
7105 | if (getuid()) |
7106 | fprintf(stderr,"This is only possible as root\n"); |
7107 | else |
7108 | fprintf(stderr,"Could not open security API\n"); |
7109 | cmderr = TRUE; |
7110 | } |
7111 | chkfree(pxdesc,__FILE__,__LINE__); |
7112 | } else |
7113 | cmderr = TRUE; |
7114 | #else |
7115 | while ((*p >= '0') && (*p <= '7')) |
7116 | mode = (mode << 3) + (*p++) - '0'; |
7117 | if (*p) { |
7118 | fprintf(stderr,"New mode should be given in octal\n"); |
7119 | cmderr = TRUE; |
7120 | } else |
7121 | if (!getuid() && open_security_api()) { |
7122 | if (open_volume(argv[xarg],MS_NONE)) { |
7123 | if (opt_r) { |
7124 | for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
7125 | securdata[i] = (struct SECURITY_DATA*)NULL; |
7126 | recurseset(argv[xarg + 2],mode); |
7127 | } else |
7128 | singleset(argv[xarg + 2],mode); |
7129 | close_volume(argv[xarg]); |
7130 | } else { |
7131 | fprintf(stderr,"Could not open volume %s\n",argv[xarg]); |
7132 | printerror(stderr); |
7133 | cmderr = TRUE; |
7134 | } |
7135 | close_security_api(); |
7136 | } else { |
7137 | if (getuid()) |
7138 | fprintf(stderr,"This is only possible as root\n"); |
7139 | else |
7140 | fprintf(stderr,"Could not open security API\n"); |
7141 | cmderr = TRUE; |
7142 | } |
7143 | #endif |
7144 | break; |
7145 | } |
7146 | if (warnings) |
7147 | printf("** %u %s signalled\n",warnings, |
7148 | (warnings > 1 ? "warnings were" : "warning was")); |
7149 | if (errors) |
7150 | printf("** %u %s found\n",errors, |
7151 | (errors > 1 ? "errors were" : "error was")); |
7152 | else |
7153 | if (!cmderr) |
7154 | printf("No errors were found\n"); |
7155 | if (!isatty(1)) { |
7156 | fflush(stdout); |
7157 | if (warnings) |
7158 | fprintf(stderr,"** %u %s signalled\n",warnings, |
7159 | (warnings > 1 ? "warnings were" : "warning was")); |
7160 | if (errors) |
7161 | fprintf(stderr,"** %u %s found\n",errors, |
7162 | (errors > 1 ? "errors were" : "error was")); |
7163 | else |
7164 | if (!cmderr) |
7165 | fprintf(stderr,"No errors were found\n"); |
7166 | } |
7167 | freeblocks(); |
7168 | } else |
7169 | cmderr = TRUE; |
7170 | dumpalloc("termination"); |
7171 | if (cmderr || errors) |
7172 | exit(1); |
7173 | return (0); |
7174 | } |
7175 | |
7176 | #endif |
7177 |