8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / fsck / pass3b.c
blob8eead2027f5ec9e673b72e4a650d865f82599d63
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms are permitted
14 * provided that: (1) source distributions retain this entire copyright
15 * notice and comment, and (2) distributions including binaries display
16 * the following acknowledgement: ``This product includes software
17 * developed by the University of California, Berkeley and its contributors''
18 * in the documentation or other materials provided with the distribution
19 * and in all advertising materials mentioning features or use of this
20 * software. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/mntent.h>
35 #include <sys/acl.h>
36 #include <sys/fs/ufs_acl.h>
37 #include <sys/fs/ufs_fs.h>
38 #include <sys/vnode.h>
39 #include <string.h>
40 #include <sys/fs/ufs_inode.h>
41 #include "fsck.h"
44 * We can be run on multiple filesystems (processed serially), so
45 * these need to be re-initialized each time we start the pass.
47 static caddr_t aclbuf; /* hold acl's for parsing */
48 static int64_t aclbufoff; /* offset into aclbuf */
49 static int64_t maxaclsize; /* how big aclbuf is */
51 static int aclblksort(const void *, const void *);
52 static int bufchk(char *, int64_t, fsck_ino_t);
53 static void clear_shadow_client(struct shadowclientinfo *,
54 struct shadowclients *, int);
56 void
57 pass3b(void)
59 fsck_ino_t inumber;
60 struct dinode *dp;
61 struct inoinfo *aclp;
62 struct inodesc curino;
63 struct shadowclientinfo *sci;
64 struct shadowclients *scc;
65 int64_t acl_size_limit;
66 int i;
69 * Sort the acl list into disk block order.
71 qsort((char *)aclpsort, (int)aclplast, sizeof (*aclpsort), aclblksort);
73 * Scan all the acl inodes, finding the largest acl file.
75 * The largest legal size is (4 * MAX_ACL_ENTRIES + 8) entries.
76 * The four are the categories of specific users, specific
77 * groups, default specific users, and default specific groups.
78 * The eight are the entries for the owning user/group/other/class
79 * plus the equivalent defaults.
81 * We double this to allow for a truly worst-case but legal
82 * situation of every single acl having its own fsd_t wrapper.
83 * Doubling is a bit pessimistic (sizeof (acl_t) > sizeof (fsd_t)).
85 acl_size_limit = sizeof (ufs_acl_t) * (4 * MAX_ACL_ENTRIES + 8);
86 acl_size_limit *= 2;
88 maxaclsize = 0;
89 for (inumber = 0; inumber < aclplast; inumber++) {
90 aclp = aclpsort[inumber];
91 if ((int64_t)aclp->i_isize > acl_size_limit) {
92 (void) printf(
93 "ACL I=%d is excessively large (%lld > %lld)",
94 inumber,
95 (longlong_t)aclp->i_isize,
96 (longlong_t)acl_size_limit);
97 if (preen) {
98 (void) printf(" (IGNORING)\n");
99 } else if (reply("CLEAR") == 1) {
100 freeino(inumber, TI_PARENT);
101 } else {
102 iscorrupt = 1;
103 (void) printf("IGNORING SHADOW I=%d\n",
104 inumber);
106 continue;
108 if ((int64_t)aclp->i_isize > maxaclsize)
109 maxaclsize = (int64_t)aclp->i_isize;
112 maxaclsize = ((maxaclsize / sblock.fs_bsize) + 1) * sblock.fs_bsize;
113 if (maxaclsize == 0)
114 goto noacls;
116 if (aclbuf != NULL) {
117 free((void *)aclbuf);
119 if ((aclbuf = malloc(maxaclsize)) == NULL) {
120 errexit("cannot alloc %lld bytes for aclbuf\n",
121 (longlong_t)maxaclsize);
124 * Scan all the acl inodes, checking contents
126 for (inumber = 0; inumber < aclplast; inumber++) {
127 aclp = aclpsort[inumber];
128 if ((int64_t)aclp->i_isize > acl_size_limit) {
129 continue;
131 if ((statemap[aclp->i_number] & STMASK) != SSTATE) {
132 continue;
134 dp = ginode(aclp->i_number);
135 init_inodesc(&curino);
136 curino.id_fix = FIX;
137 curino.id_type = ACL;
138 curino.id_func = pass3bcheck;
139 curino.id_number = aclp->i_number;
140 curino.id_filesize = aclp->i_isize;
141 aclbufoff = 0;
142 (void) memset(aclbuf, 0, (size_t)maxaclsize);
143 if ((ckinode(dp, &curino, CKI_TRAVERSE) & KEEPON) == 0 ||
144 bufchk(aclbuf, (int64_t)aclp->i_isize, aclp->i_number)) {
145 dp = ginode(aclp->i_number); /* defensive no-op */
146 if (dp->di_nlink <= 0) {
147 statemap[aclp->i_number] = FSTATE;
148 continue;
150 (void) printf("ACL I=%d BAD/CORRUPT", aclp->i_number);
151 if (preen || reply("CLEAR") == 1) {
152 if (preen)
153 (void) printf("\n");
154 freeino(aclp->i_number, TI_PARENT);
155 } else {
156 iscorrupt = 1;
161 * Now scan all shadow inodes, checking that any inodes that previously
162 * had an acl still have an acl.
164 noacls:
165 for (sci = shadowclientinfo; sci; sci = sci->next) {
166 if ((statemap[sci->shadow] & STMASK) != SSTATE) {
167 for (scc = sci->clients; scc; scc = scc->next) {
168 for (i = 0; i < scc->nclients; i++) {
169 clear_shadow_client(sci, scc, i);
174 free((void *)aclbuf);
175 aclbuf = NULL;
178 static void
179 clear_shadow_client(struct shadowclientinfo *sci, struct shadowclients *scc,
180 int client)
182 int suppress_update = 0;
183 caddr_t flow;
184 struct inodesc ldesc;
185 struct dinode *dp;
187 (void) printf("I=%d HAS BAD/CLEARED ACL I=%d",
188 scc->client[client], sci->shadow);
189 if (preen || reply("FIX") == 1) {
190 if (preen)
191 (void) printf("\n");
194 * If we clear the ACL, then the permissions should
195 * be as restrictive as possible until the user can
196 * set it to something reasonable. If we keep the
197 * ACL, then the permissions are pretty much
198 * irrelevant. So, just always clear the permission
199 * bits.
201 dp = ginode(scc->client[client]);
202 dp->di_mode &= IFMT;
203 dp->di_shadow = 0;
204 inodirty();
207 * Decrement in-memory link count - pass1 made sure
208 * the shadow inode # is a valid inode number. But
209 * first, see if we're going to overflow our sixteen
210 * bits.
212 LINK_RANGE(flow, lncntp[dp->di_shadow], 1);
213 if (flow != NULL) {
214 LINK_CLEAR(flow, scc->client[client], dp->di_mode,
215 &ldesc);
216 if (statemap[scc->client[client]] == USTATE)
217 suppress_update = 1;
221 * We don't touch the shadow's on-disk link count,
222 * because we've already cleared its state in pass3b().
223 * Here we're just trying to keep lncntp[] in sync, so
224 * we can detect spurious links.
226 if (!suppress_update)
227 TRACK_LNCNTP(sci->shadow, lncntp[sci->shadow]++);
228 } else {
229 iscorrupt = 1;
234 * Collect all the (data) blocks of an acl file into a buffer.
235 * Later we'll scan the buffer and validate the acl data.
238 pass3bcheck(struct inodesc *idesc)
240 struct bufarea *bp;
241 size_t size, bsize;
243 if (aclbufoff == idesc->id_filesize) {
244 return (STOP);
246 bsize = size = sblock.fs_fsize * idesc->id_numfrags;
247 if ((size + aclbufoff) > idesc->id_filesize)
248 size = idesc->id_filesize - aclbufoff;
249 if (aclbufoff + size > maxaclsize)
250 errexit("acl size %lld exceeds maximum calculated "
251 "size of %lld bytes",
252 (longlong_t)aclbufoff + size, (longlong_t)maxaclsize);
253 bp = getdatablk(idesc->id_blkno, bsize);
254 if (bp->b_errs != 0) {
255 brelse(bp);
256 return (STOP);
258 (void) memmove((void *)(aclbuf + aclbufoff), (void *)bp->b_un.b_buf,
259 (size_t)size);
260 aclbufoff += size;
261 brelse(bp);
262 return (KEEPON);
266 * Routine to sort disk blocks.
268 static int
269 aclblksort(const void *pp1, const void *pp2)
271 const struct inoinfo **aclpp1 = (const struct inoinfo **)pp1;
272 const struct inoinfo **aclpp2 = (const struct inoinfo **)pp2;
274 return ((*aclpp1)->i_blks[0] - (*aclpp2)->i_blks[0]);
278 * Scan a chunk of a shadow file. Return zero if no ACLs were found,
279 * or when all that were found were valid.
281 static int
282 bufchk(char *buf, int64_t len, fsck_ino_t inum)
284 ufs_fsd_t *fsdp;
285 ufs_acl_t *ufsaclp = NULL;
286 int numacls;
287 int curacl;
288 struct type_counts_s {
289 int nuser_objs;
290 int ngroup_objs;
291 int nother_objs;
292 int nclass_objs;
293 int ndef_user_objs;
294 int ndef_group_objs;
295 int ndef_other_objs;
296 int ndef_class_objs;
297 int nusers;
298 int ngroups;
299 int ndef_users;
300 int ndef_groups;
301 } type_counts[3]; /* indexed by FSD_ACL and FSD_DFACL */
302 struct type_counts_s *tcp, *tcp_all, *tcp_def, *tcp_norm;
303 int numdefs;
304 caddr_t bad;
305 caddr_t end = buf + len;
306 int64_t recsz = 0;
307 int64_t min_recsz = FSD_RECSZ(fsdp, sizeof (*fsdp));
308 struct shadowclientinfo *sci;
309 struct shadowclients *scc;
310 fsck_ino_t target;
311 int numtargets = 0;
314 * check we have a non-zero length for this shadow inode
316 if (len == 0) {
317 pwarn("ACL I=%d HAS ZERO LENGTH\n", inum);
318 return (1);
321 (void) memset(type_counts, 0, sizeof (type_counts));
323 /* LINTED pointer cast alignment (aligned buffer always passed in) */
324 for (fsdp = (ufs_fsd_t *)buf;
325 (caddr_t)fsdp < end;
326 /* LINTED as per the above */
327 fsdp = (ufs_fsd_t *)((caddr_t)fsdp + recsz)) {
329 recsz = FSD_RECSZ(fsdp, fsdp->fsd_size);
330 if ((recsz < min_recsz) ||
331 (((caddr_t)fsdp + recsz) > (buf + len))) {
332 pwarn("Bad FSD entry size %lld in shadow inode %d",
333 recsz, inum);
334 if (reply("CLEAR SHADOW INODE") == 1) {
335 freeino(inum, TI_PARENT);
336 } else {
338 * Bad size can cause the kernel to
339 * go traipsing off into never-never land.
341 iscorrupt = 1;
343 return (0);
346 switch (fsdp->fsd_type) {
347 case FSD_FREE: /* ignore empty slots */
348 break;
349 case FSD_ACL:
350 case FSD_DFACL:
352 * Subtract out the two ints in the fsd_type,
353 * leaving us just the size of fsd_data[].
355 numacls = (fsdp->fsd_size - 2 * sizeof (int)) /
356 sizeof (ufs_acl_t);
357 tcp = &type_counts[fsdp->fsd_type];
358 curacl = 0;
359 /* LINTED pointer cast alignment */
360 for (ufsaclp = (ufs_acl_t *)fsdp->fsd_data;
361 numacls; ufsaclp++, curacl++) {
362 switch (ufsaclp->acl_tag) {
363 case USER_OBJ: /* Owner */
364 tcp->nuser_objs++;
365 break;
366 case GROUP_OBJ: /* Group */
367 tcp->ngroup_objs++;
368 break;
369 case OTHER_OBJ: /* Other */
370 tcp->nother_objs++;
371 break;
372 case CLASS_OBJ: /* Mask */
373 tcp->nclass_objs++;
374 break;
375 case DEF_USER_OBJ: /* Default Owner */
376 tcp->ndef_user_objs++;
377 break;
378 case DEF_GROUP_OBJ: /* Default Group */
379 tcp->ndef_group_objs++;
380 break;
381 case DEF_OTHER_OBJ: /* Default Other */
382 tcp->ndef_other_objs++;
383 break;
384 case DEF_CLASS_OBJ: /* Default Mask */
385 tcp->ndef_class_objs++;
386 break;
387 case USER: /* Users */
388 tcp->nusers++;
389 break;
390 case GROUP: /* Groups */
391 tcp->ngroups++;
392 break;
393 case DEF_USER: /* Default Users */
394 tcp->ndef_users++;
395 break;
396 case DEF_GROUP: /* Default Groups */
397 tcp->ndef_groups++;
398 break;
399 default:
400 return (1);
403 if ((ufsaclp->acl_perm & ~07) != 0) {
405 * Caller will report inode, etc
407 pwarn("Bad permission 0%o in ACL\n",
408 ufsaclp->acl_perm);
409 return (1);
412 numacls--;
414 break;
415 default:
416 if (fsdp->fsd_type >= FSD_RESERVED3 &&
417 fsdp->fsd_type <= FSD_RESERVED7)
418 bad = "Unexpected";
419 else
420 bad = "Unknown";
421 pwarn("%s FSD type %d in shadow inode %d",
422 bad, fsdp->fsd_type, inum);
424 * This is relatively harmless, since the
425 * kernel will ignore any entries it doesn't
426 * recognize. Don't bother with iscorrupt.
428 if (preen) {
429 (void) printf(" (IGNORED)\n");
430 } else if (reply("IGNORE") == 0) {
431 if (reply("CLEAR SHADOW INODE") == 1) {
432 freeino(inum, TI_PARENT);
434 return (0);
436 break;
439 if ((caddr_t)fsdp != (buf + len)) {
440 return (1);
443 /* If we didn't find any acls, ignore the unknown attribute */
444 if (ufsaclp == NULL)
445 return (0);
448 * Should only have default ACLs in FSD_DFACL records.
449 * However, the kernel can handle it, so just report that
450 * something odd might be going on.
452 tcp = &type_counts[FSD_DFACL];
453 if (verbose &&
454 (tcp->nuser_objs != 0 ||
455 tcp->ngroup_objs != 0 ||
456 tcp->nother_objs != 0 ||
457 tcp->nclass_objs != 0 ||
458 tcp->nusers != 0 ||
459 tcp->ngroups != 0)) {
460 (void) printf("NOTE: ACL I=%d has miscategorized ACLs. ",
461 inum);
462 (void) printf("This is harmless, but not normal.\n");
466 * Similarly for default ACLs in FSD_ACL records.
468 tcp = &type_counts[FSD_ACL];
469 if (verbose &&
470 (tcp->ndef_user_objs != 0 ||
471 tcp->ndef_group_objs != 0 ||
472 tcp->ndef_other_objs != 0 ||
473 tcp->ndef_class_objs != 0 ||
474 tcp->ndef_users != 0 ||
475 tcp->ndef_groups != 0)) {
476 (void) printf("NOTE: ACL I=%d has miscategorized ACLs.",
477 inum);
478 (void) printf(" This is harmless, but not normal.\n");
482 * Get consolidated totals, now that we're done with checking
483 * the segregation above. Assumes that neither FSD_ACL nor
484 * FSD_DFACL are zero.
486 tcp_all = &type_counts[0];
487 tcp_norm = &type_counts[FSD_ACL];
488 tcp_def = &type_counts[FSD_DFACL];
490 tcp_all->nuser_objs = tcp_def->nuser_objs + tcp_norm->nuser_objs;
491 tcp_all->ngroup_objs = tcp_def->ngroup_objs + tcp_norm->ngroup_objs;
492 tcp_all->nother_objs = tcp_def->nother_objs + tcp_norm->nother_objs;
493 tcp_all->nclass_objs = tcp_def->nclass_objs + tcp_norm->nclass_objs;
494 tcp_all->ndef_user_objs =
495 tcp_def->ndef_user_objs + tcp_norm->ndef_user_objs;
496 tcp_all->ndef_group_objs =
497 tcp_def->ndef_group_objs + tcp_norm->ndef_group_objs;
498 tcp_all->ndef_other_objs =
499 tcp_def->ndef_other_objs + tcp_norm->ndef_other_objs;
500 tcp_all->ndef_class_objs =
501 tcp_def->ndef_class_objs + tcp_norm->ndef_class_objs;
502 tcp_all->nusers = tcp_def->nusers + tcp_norm->nusers;
503 tcp_all->ngroups = tcp_def->ngroups + tcp_norm->ngroups;
504 tcp_all->ndef_users = tcp_def->ndef_users + tcp_norm->ndef_users;
505 tcp_all->ndef_groups = tcp_def->ndef_groups + tcp_norm->ndef_groups;
508 * Check relationships among acls
510 if (tcp_all->nuser_objs != 1 ||
511 tcp_all->ngroup_objs != 1 ||
512 tcp_all->nother_objs != 1 ||
513 tcp_all->nclass_objs > 1) {
514 return (1);
517 if (tcp_all->ngroups && !tcp_all->nclass_objs) {
518 return (1);
521 if (tcp_all->ndef_user_objs > 1 ||
522 tcp_all->ndef_group_objs > 1 ||
523 tcp_all->ndef_other_objs > 1 ||
524 tcp_all->ndef_class_objs > 1) {
525 return (1);
529 * Check relationships among default acls
531 numdefs = tcp_all->ndef_other_objs + tcp_all->ndef_user_objs +
532 tcp_all->ndef_group_objs;
534 if (numdefs != 0 && numdefs != 3) {
535 return (1);
539 * If there are default acls, then the shadow inode's clients
540 * must be a directory or an xattr directory.
542 if (numdefs != 0) {
543 /* This is an ACL so find it's clients */
544 for (sci = shadowclientinfo; sci != NULL; sci = sci->next)
545 if (sci->shadow == inum)
546 break;
547 if ((sci == NULL) || (sci->clients == NULL))
548 return (1);
550 /* Got shadow info, now look at clients */
551 for (scc = sci->clients; scc != NULL; scc = scc->next) {
552 for (numtargets = 0; numtargets < scc->nclients;
553 numtargets++) {
554 target = scc->client[numtargets];
555 if (!INO_IS_DVALID(target))
556 return (1);
561 if (tcp_all->ndef_groups && !tcp_all->ndef_class_objs) {
562 return (1);
565 if ((tcp_all->ndef_users || tcp_all->ndef_groups) &&
566 ((numdefs != 3) && !tcp_all->ndef_class_objs)) {
567 return (1);
570 return (0);