xref: /onnv-gate/usr/src/cmd/fs.d/ufs/fsck/pass3b.c (revision 4205:b2ef771b1acf)
10Sstevel@tonic-gate /*
2*4205Sjr26306  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
110Sstevel@tonic-gate  * All rights reserved.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
140Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
150Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
160Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
170Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
180Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
190Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
200Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
210Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
220Sstevel@tonic-gate  * from this software without specific prior written permission.
230Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
240Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
250Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/mntent.h>
350Sstevel@tonic-gate #include <sys/acl.h>
360Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
370Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
380Sstevel@tonic-gate #include <sys/vnode.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
410Sstevel@tonic-gate #include "fsck.h"
420Sstevel@tonic-gate 
43392Sswilcox /*
44392Sswilcox  * We can be run on multiple filesystems (processed serially), so
45392Sswilcox  * these need to be re-initialized each time we start the pass.
46392Sswilcox  */
47392Sswilcox static caddr_t aclbuf;		/* hold acl's for parsing */
48392Sswilcox static int64_t aclbufoff;	/* offset into aclbuf */
49392Sswilcox static int64_t maxaclsize;	/* how big aclbuf is */
500Sstevel@tonic-gate 
51392Sswilcox static int aclblksort(const void *, const void *);
52392Sswilcox static int bufchk(char *, int64_t, fsck_ino_t);
53392Sswilcox static void clear_shadow_client(struct shadowclientinfo *,
54392Sswilcox 	    struct shadowclients *, int);
55392Sswilcox 
56392Sswilcox void
pass3b(void)57392Sswilcox pass3b(void)
580Sstevel@tonic-gate {
59392Sswilcox 	fsck_ino_t inumber;
600Sstevel@tonic-gate 	struct dinode *dp;
61392Sswilcox 	struct inoinfo *aclp;
620Sstevel@tonic-gate 	struct inodesc curino;
630Sstevel@tonic-gate 	struct shadowclientinfo *sci;
640Sstevel@tonic-gate 	struct shadowclients *scc;
65392Sswilcox 	int64_t acl_size_limit;
660Sstevel@tonic-gate 	int i;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	/*
690Sstevel@tonic-gate 	 * Sort the acl list into disk block order.
700Sstevel@tonic-gate 	 */
710Sstevel@tonic-gate 	qsort((char *)aclpsort, (int)aclplast, sizeof (*aclpsort), aclblksort);
720Sstevel@tonic-gate 	/*
730Sstevel@tonic-gate 	 * Scan all the acl inodes, finding the largest acl file.
74392Sswilcox 	 *
75392Sswilcox 	 * The largest legal size is (4 * MAX_ACL_ENTRIES + 8) entries.
76392Sswilcox 	 * The four are the categories of specific users, specific
77392Sswilcox 	 * groups, default specific users, and default specific groups.
78392Sswilcox 	 * The eight are the entries for the owning user/group/other/class
79392Sswilcox 	 * plus the equivalent defaults.
80392Sswilcox 	 *
81392Sswilcox 	 * We double this to allow for a truly worst-case but legal
82392Sswilcox 	 * situation of every single acl having its own fsd_t wrapper.
83392Sswilcox 	 * Doubling is a bit pessimistic (sizeof (acl_t) > sizeof (fsd_t)).
840Sstevel@tonic-gate 	 */
85392Sswilcox 	acl_size_limit = sizeof (ufs_acl_t) * (4 * MAX_ACL_ENTRIES + 8);
86392Sswilcox 	acl_size_limit *= 2;
87392Sswilcox 
88392Sswilcox 	maxaclsize = 0;
890Sstevel@tonic-gate 	for (inumber = 0; inumber < aclplast; inumber++) {
900Sstevel@tonic-gate 		aclp = aclpsort[inumber];
91392Sswilcox 		if ((int64_t)aclp->i_isize > acl_size_limit) {
92392Sswilcox 			(void) printf(
93392Sswilcox 			    "ACL I=%d is excessively large (%lld > %lld)",
94392Sswilcox 			    inumber,
95392Sswilcox 			    (longlong_t)aclp->i_isize,
96392Sswilcox 			    (longlong_t)acl_size_limit);
97392Sswilcox 			if (preen) {
98392Sswilcox 				(void) printf(" (IGNORING)\n");
99392Sswilcox 			} else if (reply("CLEAR") == 1) {
100392Sswilcox 				freeino(inumber, TI_PARENT);
101392Sswilcox 			} else {
102392Sswilcox 				iscorrupt = 1;
103392Sswilcox 				(void) printf("IGNORING SHADOW I=%d\n",
104392Sswilcox 				    inumber);
105392Sswilcox 			}
106392Sswilcox 			continue;
107392Sswilcox 		}
1080Sstevel@tonic-gate 		if ((int64_t)aclp->i_isize > maxaclsize)
1090Sstevel@tonic-gate 			maxaclsize = (int64_t)aclp->i_isize;
1100Sstevel@tonic-gate 	}
111392Sswilcox 
112392Sswilcox 	maxaclsize = ((maxaclsize / sblock.fs_bsize) + 1) * sblock.fs_bsize;
113392Sswilcox 	if (maxaclsize == 0)
114392Sswilcox 		goto noacls;
115392Sswilcox 
116392Sswilcox 	if (aclbuf != NULL) {
117392Sswilcox 		free((void *)aclbuf);
118392Sswilcox 	}
1190Sstevel@tonic-gate 	if ((aclbuf = malloc(maxaclsize)) == NULL) {
120392Sswilcox 		errexit("cannot alloc %lld bytes for aclbuf\n",
121392Sswilcox 			(longlong_t)maxaclsize);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * Scan all the acl inodes, checking contents
1250Sstevel@tonic-gate 	 */
1260Sstevel@tonic-gate 	for (inumber = 0; inumber < aclplast; inumber++) {
1270Sstevel@tonic-gate 		aclp = aclpsort[inumber];
128392Sswilcox 		if ((int64_t)aclp->i_isize > acl_size_limit) {
129392Sswilcox 			continue;
130392Sswilcox 		}
131392Sswilcox 		if ((statemap[aclp->i_number] & STMASK) != SSTATE) {
132392Sswilcox 			continue;
133392Sswilcox 		}
1340Sstevel@tonic-gate 		dp = ginode(aclp->i_number);
135392Sswilcox 		init_inodesc(&curino);
1360Sstevel@tonic-gate 		curino.id_fix = FIX;
1370Sstevel@tonic-gate 		curino.id_type = ACL;
1380Sstevel@tonic-gate 		curino.id_func = pass3bcheck;
1390Sstevel@tonic-gate 		curino.id_number = aclp->i_number;
1400Sstevel@tonic-gate 		curino.id_filesize = aclp->i_isize;
1410Sstevel@tonic-gate 		aclbufoff = 0;
142392Sswilcox 		(void) memset(aclbuf, 0, (size_t)maxaclsize);
143392Sswilcox 		if ((ckinode(dp, &curino, CKI_TRAVERSE) & KEEPON) == 0 ||
144392Sswilcox 		    bufchk(aclbuf, (int64_t)aclp->i_isize, aclp->i_number)) {
145392Sswilcox 			dp = ginode(aclp->i_number); /* defensive no-op */
1460Sstevel@tonic-gate 			if (dp->di_nlink <= 0) {
1470Sstevel@tonic-gate 				statemap[aclp->i_number] = FSTATE;
1480Sstevel@tonic-gate 				continue;
1490Sstevel@tonic-gate 			}
150392Sswilcox 			(void) printf("ACL I=%d BAD/CORRUPT", aclp->i_number);
1510Sstevel@tonic-gate 			if (preen || reply("CLEAR") == 1) {
1520Sstevel@tonic-gate 				if (preen)
153392Sswilcox 					(void) printf("\n");
154392Sswilcox 				freeino(aclp->i_number, TI_PARENT);
155392Sswilcox 			} else {
156392Sswilcox 				iscorrupt = 1;
1570Sstevel@tonic-gate 			}
1580Sstevel@tonic-gate 		}
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	/*
1610Sstevel@tonic-gate 	 * Now scan all shadow inodes, checking that any inodes that previously
1620Sstevel@tonic-gate 	 * had an acl still have an acl.
1630Sstevel@tonic-gate 	 */
164392Sswilcox noacls:
1650Sstevel@tonic-gate 	for (sci = shadowclientinfo; sci; sci = sci->next) {
166392Sswilcox 		if ((statemap[sci->shadow] & STMASK) != SSTATE) {
1670Sstevel@tonic-gate 			for (scc = sci->clients; scc; scc = scc->next) {
1680Sstevel@tonic-gate 				for (i = 0; i < scc->nclients; i++) {
169392Sswilcox 					clear_shadow_client(sci, scc, i);
1700Sstevel@tonic-gate 				}
1710Sstevel@tonic-gate 			}
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 	}
174392Sswilcox 	free((void *)aclbuf);
175392Sswilcox 	aclbuf = NULL;
176392Sswilcox }
177392Sswilcox 
178392Sswilcox static void
clear_shadow_client(struct shadowclientinfo * sci,struct shadowclients * scc,int client)179392Sswilcox clear_shadow_client(struct shadowclientinfo *sci, struct shadowclients *scc,
180392Sswilcox 	int client)
181392Sswilcox {
182392Sswilcox 	int suppress_update = 0;
183392Sswilcox 	caddr_t flow;
184392Sswilcox 	struct inodesc ldesc;
185392Sswilcox 	struct dinode *dp;
186392Sswilcox 
187392Sswilcox 	(void) printf("I=%d HAS BAD/CLEARED ACL I=%d",
188392Sswilcox 	    scc->client[client], sci->shadow);
189392Sswilcox 	if (preen || reply("FIX") == 1) {
190392Sswilcox 		if (preen)
191392Sswilcox 			(void) printf("\n");
192392Sswilcox 
193392Sswilcox 		/*
194392Sswilcox 		 * If we clear the ACL, then the permissions should
195392Sswilcox 		 * be as restrictive as possible until the user can
196392Sswilcox 		 * set it to something reasonable.  If we keep the
197392Sswilcox 		 * ACL, then the permissions are pretty much
198392Sswilcox 		 * irrelevant.  So, just always clear the permission
199392Sswilcox 		 * bits.
200392Sswilcox 		 */
201392Sswilcox 		dp = ginode(scc->client[client]);
202392Sswilcox 		dp->di_mode &= IFMT;
203392Sswilcox 		dp->di_shadow = 0;
204392Sswilcox 		inodirty();
205392Sswilcox 
206392Sswilcox 		/*
207392Sswilcox 		 * Decrement in-memory link count - pass1 made sure
208392Sswilcox 		 * the shadow inode # is a valid inode number.  But
209392Sswilcox 		 * first, see if we're going to overflow our sixteen
210392Sswilcox 		 * bits.
211392Sswilcox 		 */
212392Sswilcox 		LINK_RANGE(flow, lncntp[dp->di_shadow], 1);
213392Sswilcox 		if (flow != NULL) {
214392Sswilcox 			LINK_CLEAR(flow, scc->client[client], dp->di_mode,
215392Sswilcox 			    &ldesc);
216392Sswilcox 			if (statemap[scc->client[client]] == USTATE)
217392Sswilcox 				suppress_update = 1;
218392Sswilcox 		}
219392Sswilcox 
220392Sswilcox 		/*
221392Sswilcox 		 * We don't touch the shadow's on-disk link count,
222392Sswilcox 		 * because we've already cleared its state in pass3b().
223392Sswilcox 		 * Here we're just trying to keep lncntp[] in sync, so
224392Sswilcox 		 * we can detect spurious links.
225392Sswilcox 		 */
226392Sswilcox 		if (!suppress_update)
227392Sswilcox 			TRACK_LNCNTP(sci->shadow, lncntp[sci->shadow]++);
228392Sswilcox 	} else {
229392Sswilcox 		iscorrupt = 1;
230392Sswilcox 	}
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * Collect all the (data) blocks of an acl file into a buffer.
2350Sstevel@tonic-gate  * Later we'll scan the buffer and validate the acl data.
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate int
pass3bcheck(struct inodesc * idesc)2380Sstevel@tonic-gate pass3bcheck(struct inodesc *idesc)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	struct bufarea *bp;
241392Sswilcox 	size_t size, bsize;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (aclbufoff == idesc->id_filesize) {
2440Sstevel@tonic-gate 		return (STOP);
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	bsize = size = sblock.fs_fsize * idesc->id_numfrags;
2470Sstevel@tonic-gate 	if ((size + aclbufoff) > idesc->id_filesize)
2480Sstevel@tonic-gate 		size = idesc->id_filesize - aclbufoff;
249392Sswilcox 	if (aclbufoff + size > maxaclsize)
250392Sswilcox 		errexit("acl size %lld exceeds maximum calculated "
251392Sswilcox 			"size of %lld bytes",
252392Sswilcox 			(longlong_t)aclbufoff + size, (longlong_t)maxaclsize);
2530Sstevel@tonic-gate 	bp = getdatablk(idesc->id_blkno, bsize);
254392Sswilcox 	if (bp->b_errs != 0) {
255392Sswilcox 		brelse(bp);
256392Sswilcox 		return (STOP);
257392Sswilcox 	}
258392Sswilcox 	(void) memmove((void *)(aclbuf + aclbufoff), (void *)bp->b_un.b_buf,
259392Sswilcox 		(size_t)size);
2600Sstevel@tonic-gate 	aclbufoff += size;
2610Sstevel@tonic-gate 	brelse(bp);
2620Sstevel@tonic-gate 	return (KEEPON);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate  * Routine to sort disk blocks.
2670Sstevel@tonic-gate  */
268392Sswilcox static int
aclblksort(const void * pp1,const void * pp2)269392Sswilcox aclblksort(const void *pp1, const void *pp2)
2700Sstevel@tonic-gate {
271392Sswilcox 	const struct inoinfo **aclpp1 = (const struct inoinfo **)pp1;
272392Sswilcox 	const struct inoinfo **aclpp2 = (const struct inoinfo **)pp2;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	return ((*aclpp1)->i_blks[0] - (*aclpp2)->i_blks[0]);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
277392Sswilcox /*
278392Sswilcox  * Scan a chunk of a shadow file.  Return zero if no ACLs were found,
279392Sswilcox  * or when all that were found were valid.
280392Sswilcox  */
281392Sswilcox static int
bufchk(char * buf,int64_t len,fsck_ino_t inum)282392Sswilcox bufchk(char *buf, int64_t len, fsck_ino_t inum)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	ufs_fsd_t *fsdp;
2850Sstevel@tonic-gate 	ufs_acl_t *ufsaclp = NULL;
2860Sstevel@tonic-gate 	int numacls;
287392Sswilcox 	int curacl;
288392Sswilcox 	struct type_counts_s {
289392Sswilcox 		int nuser_objs;
290392Sswilcox 		int ngroup_objs;
291392Sswilcox 		int nother_objs;
292392Sswilcox 		int nclass_objs;
293392Sswilcox 		int ndef_user_objs;
294392Sswilcox 		int ndef_group_objs;
295392Sswilcox 		int ndef_other_objs;
296392Sswilcox 		int ndef_class_objs;
297392Sswilcox 		int nusers;
298392Sswilcox 		int ngroups;
299392Sswilcox 		int ndef_users;
300392Sswilcox 		int ndef_groups;
301392Sswilcox 	} type_counts[3];	/* indexed by FSD_ACL and FSD_DFACL */
302392Sswilcox 	struct type_counts_s *tcp, *tcp_all, *tcp_def, *tcp_norm;
303392Sswilcox 	int numdefs;
304392Sswilcox 	caddr_t bad;
305392Sswilcox 	caddr_t end = buf + len;
306392Sswilcox 	int64_t recsz = 0;
307392Sswilcox 	int64_t min_recsz = FSD_RECSZ(fsdp, sizeof (*fsdp));
308*4205Sjr26306 	struct shadowclientinfo *sci;
309*4205Sjr26306 	struct shadowclients *scc;
310*4205Sjr26306 	fsck_ino_t target;
311*4205Sjr26306 	int numtargets = 0;
312*4205Sjr26306 
313*4205Sjr26306 	/*
314*4205Sjr26306 	 * check we have a non-zero length for this shadow inode
315*4205Sjr26306 	 */
316*4205Sjr26306 	if (len == 0) {
317*4205Sjr26306 		pwarn("ACL I=%d HAS ZERO LENGTH\n", inum);
318*4205Sjr26306 		return (1);
319*4205Sjr26306 	}
320392Sswilcox 
321392Sswilcox 	(void) memset(type_counts, 0, sizeof (type_counts));
3220Sstevel@tonic-gate 
323392Sswilcox 	/* LINTED pointer cast alignment (aligned buffer always passed in) */
3240Sstevel@tonic-gate 	for (fsdp = (ufs_fsd_t *)buf;
325*4205Sjr26306 	    (caddr_t)fsdp < end;
326392Sswilcox 	    /* LINTED as per the above */
327392Sswilcox 	    fsdp = (ufs_fsd_t *)((caddr_t)fsdp + recsz)) {
328392Sswilcox 
329392Sswilcox 		recsz = FSD_RECSZ(fsdp, fsdp->fsd_size);
330392Sswilcox 		if ((recsz < min_recsz) ||
331392Sswilcox 		    (((caddr_t)fsdp + recsz) > (buf + len))) {
332392Sswilcox 			pwarn("Bad FSD entry size %lld in shadow inode %d",
333392Sswilcox 			    recsz, inum);
334392Sswilcox 			if (reply("CLEAR SHADOW INODE") == 1) {
335392Sswilcox 				freeino(inum, TI_PARENT);
336392Sswilcox 			} else {
337392Sswilcox 				/*
338392Sswilcox 				 * Bad size can cause the kernel to
339392Sswilcox 				 * go traipsing off into never-never land.
340392Sswilcox 				 */
341392Sswilcox 				iscorrupt = 1;
342392Sswilcox 			}
343392Sswilcox 			return (0);
344392Sswilcox 		}
345392Sswilcox 
3460Sstevel@tonic-gate 		switch (fsdp->fsd_type) {
347392Sswilcox 		case FSD_FREE:	/* ignore empty slots */
348392Sswilcox 			break;
3490Sstevel@tonic-gate 		case FSD_ACL:
3500Sstevel@tonic-gate 		case FSD_DFACL:
351392Sswilcox 			/*
352392Sswilcox 			 * Subtract out the two ints in the fsd_type,
353392Sswilcox 			 * leaving us just the size of fsd_data[].
354392Sswilcox 			 */
3550Sstevel@tonic-gate 			numacls = (fsdp->fsd_size - 2 * sizeof (int)) /
3560Sstevel@tonic-gate 							sizeof (ufs_acl_t);
357392Sswilcox 			tcp = &type_counts[fsdp->fsd_type];
358392Sswilcox 			curacl = 0;
359392Sswilcox 			/* LINTED pointer cast alignment */
3600Sstevel@tonic-gate 			for (ufsaclp = (ufs_acl_t *)fsdp->fsd_data;
361392Sswilcox 						numacls; ufsaclp++, curacl++) {
3620Sstevel@tonic-gate 				switch (ufsaclp->acl_tag) {
3630Sstevel@tonic-gate 				case USER_OBJ:		/* Owner */
364392Sswilcox 					tcp->nuser_objs++;
3650Sstevel@tonic-gate 					break;
3660Sstevel@tonic-gate 				case GROUP_OBJ:		/* Group */
367392Sswilcox 					tcp->ngroup_objs++;
3680Sstevel@tonic-gate 					break;
3690Sstevel@tonic-gate 				case OTHER_OBJ:		/* Other */
370392Sswilcox 					tcp->nother_objs++;
3710Sstevel@tonic-gate 					break;
3720Sstevel@tonic-gate 				case CLASS_OBJ:		/* Mask */
373392Sswilcox 					tcp->nclass_objs++;
3740Sstevel@tonic-gate 					break;
3750Sstevel@tonic-gate 				case DEF_USER_OBJ:	/* Default Owner */
376392Sswilcox 					tcp->ndef_user_objs++;
3770Sstevel@tonic-gate 					break;
3780Sstevel@tonic-gate 				case DEF_GROUP_OBJ:	/* Default Group */
379392Sswilcox 					tcp->ndef_group_objs++;
3800Sstevel@tonic-gate 					break;
3810Sstevel@tonic-gate 				case DEF_OTHER_OBJ:	/* Default Other */
382392Sswilcox 					tcp->ndef_other_objs++;
3830Sstevel@tonic-gate 					break;
3840Sstevel@tonic-gate 				case DEF_CLASS_OBJ:	/* Default Mask */
385392Sswilcox 					tcp->ndef_class_objs++;
3860Sstevel@tonic-gate 					break;
3870Sstevel@tonic-gate 				case USER:		/* Users */
388392Sswilcox 					tcp->nusers++;
3890Sstevel@tonic-gate 					break;
3900Sstevel@tonic-gate 				case GROUP:		/* Groups */
391392Sswilcox 					tcp->ngroups++;
3920Sstevel@tonic-gate 					break;
3930Sstevel@tonic-gate 				case DEF_USER:		/* Default Users */
394392Sswilcox 					tcp->ndef_users++;
3950Sstevel@tonic-gate 					break;
3960Sstevel@tonic-gate 				case DEF_GROUP:		/* Default Groups */
397392Sswilcox 					tcp->ndef_groups++;
3980Sstevel@tonic-gate 					break;
3990Sstevel@tonic-gate 				default:
4000Sstevel@tonic-gate 					return (1);
4010Sstevel@tonic-gate 				}
402392Sswilcox 
403392Sswilcox 				if ((ufsaclp->acl_perm & ~07) != 0) {
404392Sswilcox 					/*
405392Sswilcox 					 * Caller will report inode, etc
406392Sswilcox 					 */
407392Sswilcox 					pwarn("Bad permission 0%o in ACL\n",
408392Sswilcox 					    ufsaclp->acl_perm);
409392Sswilcox 					return (1);
410392Sswilcox 				}
411392Sswilcox 
4120Sstevel@tonic-gate 				numacls--;
4130Sstevel@tonic-gate 			}
4140Sstevel@tonic-gate 			break;
4150Sstevel@tonic-gate 		default:
416392Sswilcox 			if (fsdp->fsd_type >= FSD_RESERVED3 &&
417392Sswilcox 			    fsdp->fsd_type <= FSD_RESERVED7)
418392Sswilcox 				bad = "Unexpected";
419392Sswilcox 			else
420392Sswilcox 				bad = "Unknown";
421392Sswilcox 			pwarn("%s FSD type %d in shadow inode %d",
422392Sswilcox 			    bad, fsdp->fsd_type, inum);
423392Sswilcox 			/*
424392Sswilcox 			 * This is relatively harmless, since the
425392Sswilcox 			 * kernel will ignore any entries it doesn't
426392Sswilcox 			 * recognize.  Don't bother with iscorrupt.
427392Sswilcox 			 */
428392Sswilcox 			if (preen) {
429392Sswilcox 				(void) printf(" (IGNORED)\n");
430392Sswilcox 			} else if (reply("IGNORE") == 0) {
431392Sswilcox 				if (reply("CLEAR SHADOW INODE") == 1) {
432392Sswilcox 					freeino(inum, TI_PARENT);
433392Sswilcox 				}
434392Sswilcox 				return (0);
435392Sswilcox 			}
4360Sstevel@tonic-gate 			break;
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 	if ((caddr_t)fsdp != (buf + len)) {
4400Sstevel@tonic-gate 		return (1);
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/* If we didn't find any acls, ignore the unknown attribute */
4440Sstevel@tonic-gate 	if (ufsaclp == NULL)
4450Sstevel@tonic-gate 		return (0);
4460Sstevel@tonic-gate 
447392Sswilcox 	/*
448392Sswilcox 	 * Should only have default ACLs in FSD_DFACL records.
449392Sswilcox 	 * However, the kernel can handle it, so just report that
450392Sswilcox 	 * something odd might be going on.
451392Sswilcox 	 */
452392Sswilcox 	tcp = &type_counts[FSD_DFACL];
453392Sswilcox 	if (verbose &&
454392Sswilcox 	    (tcp->nuser_objs != 0 ||
455392Sswilcox 	    tcp->ngroup_objs != 0 ||
456392Sswilcox 	    tcp->nother_objs != 0 ||
457392Sswilcox 	    tcp->nclass_objs != 0 ||
458392Sswilcox 	    tcp->nusers != 0 ||
459392Sswilcox 	    tcp->ngroups != 0)) {
460392Sswilcox 		(void) printf("NOTE: ACL I=%d has miscategorized ACLs.  ",
461392Sswilcox 		    inum);
462392Sswilcox 		(void) printf("This is harmless, but not normal.\n");
463392Sswilcox 	}
464392Sswilcox 
465392Sswilcox 	/*
466392Sswilcox 	 * Similarly for default ACLs in FSD_ACL records.
467392Sswilcox 	 */
468392Sswilcox 	tcp = &type_counts[FSD_ACL];
469392Sswilcox 	if (verbose &&
470392Sswilcox 	    (tcp->ndef_user_objs != 0 ||
471392Sswilcox 	    tcp->ndef_group_objs != 0 ||
472392Sswilcox 	    tcp->ndef_other_objs != 0 ||
473392Sswilcox 	    tcp->ndef_class_objs != 0 ||
474392Sswilcox 	    tcp->ndef_users != 0 ||
475392Sswilcox 	    tcp->ndef_groups != 0)) {
476392Sswilcox 		(void) printf("NOTE: ACL I=%d has miscategorized ACLs.",
477392Sswilcox 		    inum);
478392Sswilcox 		(void) printf("  This is harmless, but not normal.\n");
4790Sstevel@tonic-gate 	}
480392Sswilcox 
481392Sswilcox 	/*
482392Sswilcox 	 * Get consolidated totals, now that we're done with checking
483392Sswilcox 	 * the segregation above.  Assumes that neither FSD_ACL nor
484392Sswilcox 	 * FSD_DFACL are zero.
485392Sswilcox 	 */
486392Sswilcox 	tcp_all = &type_counts[0];
487392Sswilcox 	tcp_norm = &type_counts[FSD_ACL];
488392Sswilcox 	tcp_def = &type_counts[FSD_DFACL];
489392Sswilcox 
490392Sswilcox 	tcp_all->nuser_objs = tcp_def->nuser_objs + tcp_norm->nuser_objs;
491392Sswilcox 	tcp_all->ngroup_objs = tcp_def->ngroup_objs + tcp_norm->ngroup_objs;
492392Sswilcox 	tcp_all->nother_objs = tcp_def->nother_objs + tcp_norm->nother_objs;
493392Sswilcox 	tcp_all->nclass_objs = tcp_def->nclass_objs + tcp_norm->nclass_objs;
494392Sswilcox 	tcp_all->ndef_user_objs =
495392Sswilcox 		tcp_def->ndef_user_objs + tcp_norm->ndef_user_objs;
496392Sswilcox 	tcp_all->ndef_group_objs =
497392Sswilcox 		tcp_def->ndef_group_objs + tcp_norm->ndef_group_objs;
498392Sswilcox 	tcp_all->ndef_other_objs =
499392Sswilcox 		tcp_def->ndef_other_objs + tcp_norm->ndef_other_objs;
500392Sswilcox 	tcp_all->ndef_class_objs =
501392Sswilcox 		tcp_def->ndef_class_objs + tcp_norm->ndef_class_objs;
502392Sswilcox 	tcp_all->nusers = tcp_def->nusers + tcp_norm->nusers;
503392Sswilcox 	tcp_all->ngroups = tcp_def->ngroups + tcp_norm->ngroups;
504392Sswilcox 	tcp_all->ndef_users = tcp_def->ndef_users + tcp_norm->ndef_users;
505392Sswilcox 	tcp_all->ndef_groups = tcp_def->ndef_groups + tcp_norm->ndef_groups;
506392Sswilcox 
507392Sswilcox 	/*
508392Sswilcox 	 * Check relationships among acls
509392Sswilcox 	 */
510392Sswilcox 	if (tcp_all->nuser_objs != 1 ||
511392Sswilcox 	    tcp_all->ngroup_objs != 1 ||
512392Sswilcox 	    tcp_all->nother_objs != 1 ||
513392Sswilcox 	    tcp_all->nclass_objs > 1) {
5140Sstevel@tonic-gate 		return (1);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
517392Sswilcox 	if (tcp_all->ngroups && !tcp_all->nclass_objs) {
518392Sswilcox 		return (1);
519392Sswilcox 	}
520392Sswilcox 
521392Sswilcox 	if (tcp_all->ndef_user_objs > 1 ||
522392Sswilcox 	    tcp_all->ndef_group_objs > 1 ||
523392Sswilcox 	    tcp_all->ndef_other_objs > 1 ||
524392Sswilcox 	    tcp_all->ndef_class_objs > 1) {
525392Sswilcox 		return (1);
526392Sswilcox 	}
527392Sswilcox 
528392Sswilcox 	/*
529392Sswilcox 	 * Check relationships among default acls
530392Sswilcox 	 */
531392Sswilcox 	numdefs = tcp_all->ndef_other_objs + tcp_all->ndef_user_objs +
532392Sswilcox 		tcp_all->ndef_group_objs;
533392Sswilcox 
5340Sstevel@tonic-gate 	if (numdefs != 0 && numdefs != 3) {
5350Sstevel@tonic-gate 		return (1);
5360Sstevel@tonic-gate 	}
537392Sswilcox 
538392Sswilcox 	/*
539*4205Sjr26306 	 * If there are default acls, then the shadow inode's clients
540*4205Sjr26306 	 * must be a directory or an xattr directory.
541392Sswilcox 	 */
542*4205Sjr26306 	if (numdefs != 0) {
543*4205Sjr26306 		/* This is an ACL so find it's clients */
544*4205Sjr26306 		for (sci = shadowclientinfo; sci != NULL; sci = sci->next)
545*4205Sjr26306 			if (sci->shadow == inum)
546*4205Sjr26306 			    break;
547*4205Sjr26306 		if ((sci ==  NULL) || (sci->clients == NULL))
548*4205Sjr26306 			return (1);
549*4205Sjr26306 
550*4205Sjr26306 		/* Got shadow info, now look at clients */
551*4205Sjr26306 		for (scc = sci->clients; scc != NULL; scc = scc->next) {
552*4205Sjr26306 			for (numtargets = 0; numtargets < scc->nclients;
553*4205Sjr26306 			    numtargets++) {
554*4205Sjr26306 				target = scc->client[numtargets];
555*4205Sjr26306 				if (!INO_IS_DVALID(target))
556*4205Sjr26306 					return (1);
557*4205Sjr26306 			}
558*4205Sjr26306 		}
5590Sstevel@tonic-gate 	}
560392Sswilcox 
561392Sswilcox 	if (tcp_all->ndef_groups && !tcp_all->ndef_class_objs) {
5620Sstevel@tonic-gate 		return (1);
5630Sstevel@tonic-gate 	}
564392Sswilcox 
565392Sswilcox 	if ((tcp_all->ndef_users || tcp_all->ndef_groups) &&
566392Sswilcox 	    ((numdefs != 3) && !tcp_all->ndef_class_objs)) {
567392Sswilcox 		return (1);
568392Sswilcox 	}
569392Sswilcox 
5700Sstevel@tonic-gate 	return (0);
5710Sstevel@tonic-gate }
572