pass3b.c revision 0eca9a2491ccacd1e43ae395f374369b5d7e3dbe
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by the University of California, Berkeley and its contributors''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fsck.h"
/*
* We can be run on multiple filesystems (processed serially), so
* these need to be re-initialized each time we start the pass.
*/
static int aclblksort(const void *, const void *);
static void clear_shadow_client(struct shadowclientinfo *,
struct shadowclients *, int);
void
pass3b(void)
{
struct shadowclientinfo *sci;
struct shadowclients *scc;
int i;
/*
* Sort the acl list into disk block order.
*/
/*
* Scan all the acl inodes, finding the largest acl file.
*
* The largest legal size is (4 * MAX_ACL_ENTRIES + 8) entries.
* The four are the categories of specific users, specific
* groups, default specific users, and default specific groups.
* plus the equivalent defaults.
*
* We double this to allow for a truly worst-case but legal
* situation of every single acl having its own fsd_t wrapper.
* Doubling is a bit pessimistic (sizeof (acl_t) > sizeof (fsd_t)).
*/
acl_size_limit *= 2;
maxaclsize = 0;
(void) printf(
"ACL I=%d is excessively large (%lld > %lld)",
if (preen) {
(void) printf(" (IGNORING)\n");
} else {
iscorrupt = 1;
(void) printf("IGNORING SHADOW I=%d\n",
inumber);
}
continue;
}
}
if (maxaclsize == 0)
goto noacls;
}
errexit("cannot alloc %lld bytes for aclbuf\n",
}
/*
* Scan all the acl inodes, checking contents
*/
continue;
}
continue;
}
aclbufoff = 0;
continue;
}
if (preen)
(void) printf("\n");
} else {
iscorrupt = 1;
}
}
}
/*
* Now scan all shadow inodes, checking that any inodes that previously
* had an acl still have an acl.
*/
}
}
}
}
}
static void
int client)
{
int suppress_update = 0;
if (preen)
(void) printf("\n");
/*
* If we clear the ACL, then the permissions should
* be as restrictive as possible until the user can
* set it to something reasonable. If we keep the
* ACL, then the permissions are pretty much
* irrelevant. So, just always clear the permission
* bits.
*/
inodirty();
/*
* Decrement in-memory link count - pass1 made sure
* the shadow inode # is a valid inode number. But
* first, see if we're going to overflow our sixteen
* bits.
*/
&ldesc);
suppress_update = 1;
}
/*
* We don't touch the shadow's on-disk link count,
* because we've already cleared its state in pass3b().
* Here we're just trying to keep lncntp[] in sync, so
* we can detect spurious links.
*/
if (!suppress_update)
} else {
iscorrupt = 1;
}
}
/*
* Collect all the (data) blocks of an acl file into a buffer.
* Later we'll scan the buffer and validate the acl data.
*/
int
{
return (STOP);
}
errexit("acl size %lld exceeds maximum calculated "
"size of %lld bytes",
return (STOP);
}
return (KEEPON);
}
/*
* Routine to sort disk blocks.
*/
static int
{
}
/*
* Scan a chunk of a shadow file. Return zero if no ACLs were found,
* or when all that were found were valid.
*/
static int
{
int numacls;
int curacl;
struct type_counts_s {
int nuser_objs;
int ngroup_objs;
int nother_objs;
int nclass_objs;
int ndef_user_objs;
int ndef_group_objs;
int ndef_other_objs;
int ndef_class_objs;
int nusers;
int ngroups;
int ndef_users;
int ndef_groups;
int numdefs;
struct shadowclientinfo *sci;
struct shadowclients *scc;
int numtargets = 0;
/*
* check we have a non-zero length for this shadow inode
*/
if (len == 0) {
return (1);
}
/* LINTED pointer cast alignment (aligned buffer always passed in) */
/* LINTED as per the above */
pwarn("Bad FSD entry size %lld in shadow inode %d",
} else {
/*
* Bad size can cause the kernel to
* go traipsing off into never-never land.
*/
iscorrupt = 1;
}
return (0);
}
case FSD_FREE: /* ignore empty slots */
break;
case FSD_ACL:
case FSD_DFACL:
/*
* Subtract out the two ints in the fsd_type,
* leaving us just the size of fsd_data[].
*/
sizeof (ufs_acl_t);
curacl = 0;
/* LINTED pointer cast alignment */
case USER_OBJ: /* Owner */
tcp->nuser_objs++;
break;
case GROUP_OBJ: /* Group */
tcp->ngroup_objs++;
break;
case OTHER_OBJ: /* Other */
tcp->nother_objs++;
break;
case CLASS_OBJ: /* Mask */
tcp->nclass_objs++;
break;
case DEF_USER_OBJ: /* Default Owner */
tcp->ndef_user_objs++;
break;
case DEF_GROUP_OBJ: /* Default Group */
tcp->ndef_group_objs++;
break;
case DEF_OTHER_OBJ: /* Default Other */
tcp->ndef_other_objs++;
break;
case DEF_CLASS_OBJ: /* Default Mask */
tcp->ndef_class_objs++;
break;
case USER: /* Users */
break;
case GROUP: /* Groups */
break;
case DEF_USER: /* Default Users */
tcp->ndef_users++;
break;
case DEF_GROUP: /* Default Groups */
tcp->ndef_groups++;
break;
default:
return (1);
}
/*
* Caller will report inode, etc
*/
pwarn("Bad permission 0%o in ACL\n",
return (1);
}
numacls--;
}
break;
default:
bad = "Unexpected";
else
bad = "Unknown";
pwarn("%s FSD type %d in shadow inode %d",
/*
* This is relatively harmless, since the
* kernel will ignore any entries it doesn't
* recognize. Don't bother with iscorrupt.
*/
if (preen) {
(void) printf(" (IGNORED)\n");
} else if (reply("IGNORE") == 0) {
}
return (0);
}
break;
}
}
return (1);
}
/* If we didn't find any acls, ignore the unknown attribute */
return (0);
/*
* Should only have default ACLs in FSD_DFACL records.
* However, the kernel can handle it, so just report that
* something odd might be going on.
*/
if (verbose &&
(tcp->nuser_objs != 0 ||
tcp->ngroup_objs != 0 ||
tcp->nother_objs != 0 ||
tcp->nclass_objs != 0 ||
(void) printf("NOTE: ACL I=%d has miscategorized ACLs. ",
inum);
(void) printf("This is harmless, but not normal.\n");
}
/*
* Similarly for default ACLs in FSD_ACL records.
*/
if (verbose &&
(tcp->ndef_user_objs != 0 ||
tcp->ndef_group_objs != 0 ||
tcp->ndef_other_objs != 0 ||
tcp->ndef_class_objs != 0 ||
tcp->ndef_users != 0 ||
tcp->ndef_groups != 0)) {
(void) printf("NOTE: ACL I=%d has miscategorized ACLs.",
inum);
(void) printf(" This is harmless, but not normal.\n");
}
/*
* Get consolidated totals, now that we're done with checking
* the segregation above. Assumes that neither FSD_ACL nor
* FSD_DFACL are zero.
*/
tcp_all = &type_counts[0];
/*
* Check relationships among acls
*/
return (1);
}
return (1);
}
return (1);
}
/*
* Check relationships among default acls
*/
return (1);
}
/*
* If there are default acls, then the shadow inode's clients
* must be a directory or an xattr directory.
*/
if (numdefs != 0) {
/* This is an ACL so find it's clients */
break;
return (1);
/* Got shadow info, now look at clients */
numtargets++) {
if (!INO_IS_DVALID(target))
return (1);
}
}
}
return (1);
}
return (1);
}
return (0);
}