17c478bd9Sstevel@tonic-gate /*
2*0eca9a24Sjr26306 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
77c478bd9Sstevel@tonic-gate /* All Rights Reserved */
87c478bd9Sstevel@tonic-gate
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
117c478bd9Sstevel@tonic-gate * All rights reserved.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission.
237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
357c478bd9Sstevel@tonic-gate #include <sys/acl.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
377c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
417c478bd9Sstevel@tonic-gate #include "fsck.h"
427c478bd9Sstevel@tonic-gate
43355d6bb5Sswilcox /*
44355d6bb5Sswilcox * We can be run on multiple filesystems (processed serially), so
45355d6bb5Sswilcox * these need to be re-initialized each time we start the pass.
46355d6bb5Sswilcox */
47355d6bb5Sswilcox static caddr_t aclbuf; /* hold acl's for parsing */
48355d6bb5Sswilcox static int64_t aclbufoff; /* offset into aclbuf */
49355d6bb5Sswilcox static int64_t maxaclsize; /* how big aclbuf is */
507c478bd9Sstevel@tonic-gate
51355d6bb5Sswilcox static int aclblksort(const void *, const void *);
52355d6bb5Sswilcox static int bufchk(char *, int64_t, fsck_ino_t);
53355d6bb5Sswilcox static void clear_shadow_client(struct shadowclientinfo *,
54355d6bb5Sswilcox struct shadowclients *, int);
55355d6bb5Sswilcox
56355d6bb5Sswilcox void
pass3b(void)57355d6bb5Sswilcox pass3b(void)
587c478bd9Sstevel@tonic-gate {
59355d6bb5Sswilcox fsck_ino_t inumber;
607c478bd9Sstevel@tonic-gate struct dinode *dp;
61355d6bb5Sswilcox struct inoinfo *aclp;
627c478bd9Sstevel@tonic-gate struct inodesc curino;
637c478bd9Sstevel@tonic-gate struct shadowclientinfo *sci;
647c478bd9Sstevel@tonic-gate struct shadowclients *scc;
65355d6bb5Sswilcox int64_t acl_size_limit;
667c478bd9Sstevel@tonic-gate int i;
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate * Sort the acl list into disk block order.
707c478bd9Sstevel@tonic-gate */
717c478bd9Sstevel@tonic-gate qsort((char *)aclpsort, (int)aclplast, sizeof (*aclpsort), aclblksort);
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate * Scan all the acl inodes, finding the largest acl file.
74355d6bb5Sswilcox *
75355d6bb5Sswilcox * The largest legal size is (4 * MAX_ACL_ENTRIES + 8) entries.
76355d6bb5Sswilcox * The four are the categories of specific users, specific
77355d6bb5Sswilcox * groups, default specific users, and default specific groups.
78355d6bb5Sswilcox * The eight are the entries for the owning user/group/other/class
79355d6bb5Sswilcox * plus the equivalent defaults.
80355d6bb5Sswilcox *
81355d6bb5Sswilcox * We double this to allow for a truly worst-case but legal
82355d6bb5Sswilcox * situation of every single acl having its own fsd_t wrapper.
83355d6bb5Sswilcox * Doubling is a bit pessimistic (sizeof (acl_t) > sizeof (fsd_t)).
847c478bd9Sstevel@tonic-gate */
85355d6bb5Sswilcox acl_size_limit = sizeof (ufs_acl_t) * (4 * MAX_ACL_ENTRIES + 8);
86355d6bb5Sswilcox acl_size_limit *= 2;
87355d6bb5Sswilcox
88355d6bb5Sswilcox maxaclsize = 0;
897c478bd9Sstevel@tonic-gate for (inumber = 0; inumber < aclplast; inumber++) {
907c478bd9Sstevel@tonic-gate aclp = aclpsort[inumber];
91355d6bb5Sswilcox if ((int64_t)aclp->i_isize > acl_size_limit) {
92355d6bb5Sswilcox (void) printf(
93355d6bb5Sswilcox "ACL I=%d is excessively large (%lld > %lld)",
94355d6bb5Sswilcox inumber,
95355d6bb5Sswilcox (longlong_t)aclp->i_isize,
96355d6bb5Sswilcox (longlong_t)acl_size_limit);
97355d6bb5Sswilcox if (preen) {
98355d6bb5Sswilcox (void) printf(" (IGNORING)\n");
99355d6bb5Sswilcox } else if (reply("CLEAR") == 1) {
100355d6bb5Sswilcox freeino(inumber, TI_PARENT);
101355d6bb5Sswilcox } else {
102355d6bb5Sswilcox iscorrupt = 1;
103355d6bb5Sswilcox (void) printf("IGNORING SHADOW I=%d\n",
104355d6bb5Sswilcox inumber);
105355d6bb5Sswilcox }
106355d6bb5Sswilcox continue;
107355d6bb5Sswilcox }
1087c478bd9Sstevel@tonic-gate if ((int64_t)aclp->i_isize > maxaclsize)
1097c478bd9Sstevel@tonic-gate maxaclsize = (int64_t)aclp->i_isize;
1107c478bd9Sstevel@tonic-gate }
111355d6bb5Sswilcox
112355d6bb5Sswilcox maxaclsize = ((maxaclsize / sblock.fs_bsize) + 1) * sblock.fs_bsize;
113355d6bb5Sswilcox if (maxaclsize == 0)
114355d6bb5Sswilcox goto noacls;
115355d6bb5Sswilcox
116355d6bb5Sswilcox if (aclbuf != NULL) {
117355d6bb5Sswilcox free((void *)aclbuf);
118355d6bb5Sswilcox }
1197c478bd9Sstevel@tonic-gate if ((aclbuf = malloc(maxaclsize)) == NULL) {
120355d6bb5Sswilcox errexit("cannot alloc %lld bytes for aclbuf\n",
121355d6bb5Sswilcox (longlong_t)maxaclsize);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * Scan all the acl inodes, checking contents
1257c478bd9Sstevel@tonic-gate */
1267c478bd9Sstevel@tonic-gate for (inumber = 0; inumber < aclplast; inumber++) {
1277c478bd9Sstevel@tonic-gate aclp = aclpsort[inumber];
128355d6bb5Sswilcox if ((int64_t)aclp->i_isize > acl_size_limit) {
129355d6bb5Sswilcox continue;
130355d6bb5Sswilcox }
131355d6bb5Sswilcox if ((statemap[aclp->i_number] & STMASK) != SSTATE) {
132355d6bb5Sswilcox continue;
133355d6bb5Sswilcox }
1347c478bd9Sstevel@tonic-gate dp = ginode(aclp->i_number);
135355d6bb5Sswilcox init_inodesc(&curino);
1367c478bd9Sstevel@tonic-gate curino.id_fix = FIX;
1377c478bd9Sstevel@tonic-gate curino.id_type = ACL;
1387c478bd9Sstevel@tonic-gate curino.id_func = pass3bcheck;
1397c478bd9Sstevel@tonic-gate curino.id_number = aclp->i_number;
1407c478bd9Sstevel@tonic-gate curino.id_filesize = aclp->i_isize;
1417c478bd9Sstevel@tonic-gate aclbufoff = 0;
142355d6bb5Sswilcox (void) memset(aclbuf, 0, (size_t)maxaclsize);
143355d6bb5Sswilcox if ((ckinode(dp, &curino, CKI_TRAVERSE) & KEEPON) == 0 ||
144355d6bb5Sswilcox bufchk(aclbuf, (int64_t)aclp->i_isize, aclp->i_number)) {
145355d6bb5Sswilcox dp = ginode(aclp->i_number); /* defensive no-op */
1467c478bd9Sstevel@tonic-gate if (dp->di_nlink <= 0) {
1477c478bd9Sstevel@tonic-gate statemap[aclp->i_number] = FSTATE;
1487c478bd9Sstevel@tonic-gate continue;
1497c478bd9Sstevel@tonic-gate }
150355d6bb5Sswilcox (void) printf("ACL I=%d BAD/CORRUPT", aclp->i_number);
1517c478bd9Sstevel@tonic-gate if (preen || reply("CLEAR") == 1) {
1527c478bd9Sstevel@tonic-gate if (preen)
153355d6bb5Sswilcox (void) printf("\n");
154355d6bb5Sswilcox freeino(aclp->i_number, TI_PARENT);
155355d6bb5Sswilcox } else {
156355d6bb5Sswilcox iscorrupt = 1;
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate * Now scan all shadow inodes, checking that any inodes that previously
1627c478bd9Sstevel@tonic-gate * had an acl still have an acl.
1637c478bd9Sstevel@tonic-gate */
164355d6bb5Sswilcox noacls:
1657c478bd9Sstevel@tonic-gate for (sci = shadowclientinfo; sci; sci = sci->next) {
166355d6bb5Sswilcox if ((statemap[sci->shadow] & STMASK) != SSTATE) {
1677c478bd9Sstevel@tonic-gate for (scc = sci->clients; scc; scc = scc->next) {
1687c478bd9Sstevel@tonic-gate for (i = 0; i < scc->nclients; i++) {
169355d6bb5Sswilcox clear_shadow_client(sci, scc, i);
170355d6bb5Sswilcox }
171355d6bb5Sswilcox }
172355d6bb5Sswilcox }
173355d6bb5Sswilcox }
174355d6bb5Sswilcox free((void *)aclbuf);
175355d6bb5Sswilcox aclbuf = NULL;
176355d6bb5Sswilcox }
177355d6bb5Sswilcox
178355d6bb5Sswilcox static void
clear_shadow_client(struct shadowclientinfo * sci,struct shadowclients * scc,int client)179355d6bb5Sswilcox clear_shadow_client(struct shadowclientinfo *sci, struct shadowclients *scc,
180355d6bb5Sswilcox int client)
181355d6bb5Sswilcox {
182355d6bb5Sswilcox int suppress_update = 0;
183355d6bb5Sswilcox caddr_t flow;
184355d6bb5Sswilcox struct inodesc ldesc;
185355d6bb5Sswilcox struct dinode *dp;
186355d6bb5Sswilcox
187355d6bb5Sswilcox (void) printf("I=%d HAS BAD/CLEARED ACL I=%d",
188355d6bb5Sswilcox scc->client[client], sci->shadow);
1897c478bd9Sstevel@tonic-gate if (preen || reply("FIX") == 1) {
1907c478bd9Sstevel@tonic-gate if (preen)
191355d6bb5Sswilcox (void) printf("\n");
192355d6bb5Sswilcox
1937c478bd9Sstevel@tonic-gate /*
194355d6bb5Sswilcox * If we clear the ACL, then the permissions should
195355d6bb5Sswilcox * be as restrictive as possible until the user can
196355d6bb5Sswilcox * set it to something reasonable. If we keep the
197355d6bb5Sswilcox * ACL, then the permissions are pretty much
198355d6bb5Sswilcox * irrelevant. So, just always clear the permission
199355d6bb5Sswilcox * bits.
2007c478bd9Sstevel@tonic-gate */
201355d6bb5Sswilcox dp = ginode(scc->client[client]);
202355d6bb5Sswilcox dp->di_mode &= IFMT;
2037c478bd9Sstevel@tonic-gate dp->di_shadow = 0;
2047c478bd9Sstevel@tonic-gate inodirty();
205355d6bb5Sswilcox
206355d6bb5Sswilcox /*
207355d6bb5Sswilcox * Decrement in-memory link count - pass1 made sure
208355d6bb5Sswilcox * the shadow inode # is a valid inode number. But
209355d6bb5Sswilcox * first, see if we're going to overflow our sixteen
210355d6bb5Sswilcox * bits.
211355d6bb5Sswilcox */
212355d6bb5Sswilcox LINK_RANGE(flow, lncntp[dp->di_shadow], 1);
213355d6bb5Sswilcox if (flow != NULL) {
214355d6bb5Sswilcox LINK_CLEAR(flow, scc->client[client], dp->di_mode,
215355d6bb5Sswilcox &ldesc);
216355d6bb5Sswilcox if (statemap[scc->client[client]] == USTATE)
217355d6bb5Sswilcox suppress_update = 1;
2187c478bd9Sstevel@tonic-gate }
219355d6bb5Sswilcox
220355d6bb5Sswilcox /*
221355d6bb5Sswilcox * We don't touch the shadow's on-disk link count,
222355d6bb5Sswilcox * because we've already cleared its state in pass3b().
223355d6bb5Sswilcox * Here we're just trying to keep lncntp[] in sync, so
224355d6bb5Sswilcox * we can detect spurious links.
225355d6bb5Sswilcox */
226355d6bb5Sswilcox if (!suppress_update)
227355d6bb5Sswilcox TRACK_LNCNTP(sci->shadow, lncntp[sci->shadow]++);
228355d6bb5Sswilcox } else {
229355d6bb5Sswilcox iscorrupt = 1;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate * Collect all the (data) blocks of an acl file into a buffer.
2357c478bd9Sstevel@tonic-gate * Later we'll scan the buffer and validate the acl data.
2367c478bd9Sstevel@tonic-gate */
2377c478bd9Sstevel@tonic-gate int
pass3bcheck(struct inodesc * idesc)2387c478bd9Sstevel@tonic-gate pass3bcheck(struct inodesc *idesc)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate struct bufarea *bp;
241355d6bb5Sswilcox size_t size, bsize;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate if (aclbufoff == idesc->id_filesize) {
2447c478bd9Sstevel@tonic-gate return (STOP);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate bsize = size = sblock.fs_fsize * idesc->id_numfrags;
2477c478bd9Sstevel@tonic-gate if ((size + aclbufoff) > idesc->id_filesize)
2487c478bd9Sstevel@tonic-gate size = idesc->id_filesize - aclbufoff;
249355d6bb5Sswilcox if (aclbufoff + size > maxaclsize)
250355d6bb5Sswilcox errexit("acl size %lld exceeds maximum calculated "
251355d6bb5Sswilcox "size of %lld bytes",
252355d6bb5Sswilcox (longlong_t)aclbufoff + size, (longlong_t)maxaclsize);
2537c478bd9Sstevel@tonic-gate bp = getdatablk(idesc->id_blkno, bsize);
254355d6bb5Sswilcox if (bp->b_errs != 0) {
255355d6bb5Sswilcox brelse(bp);
256355d6bb5Sswilcox return (STOP);
257355d6bb5Sswilcox }
258355d6bb5Sswilcox (void) memmove((void *)(aclbuf + aclbufoff), (void *)bp->b_un.b_buf,
259355d6bb5Sswilcox (size_t)size);
2607c478bd9Sstevel@tonic-gate aclbufoff += size;
2617c478bd9Sstevel@tonic-gate brelse(bp);
2627c478bd9Sstevel@tonic-gate return (KEEPON);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate * Routine to sort disk blocks.
2677c478bd9Sstevel@tonic-gate */
268355d6bb5Sswilcox static int
aclblksort(const void * pp1,const void * pp2)269355d6bb5Sswilcox aclblksort(const void *pp1, const void *pp2)
2707c478bd9Sstevel@tonic-gate {
271355d6bb5Sswilcox const struct inoinfo **aclpp1 = (const struct inoinfo **)pp1;
272355d6bb5Sswilcox const struct inoinfo **aclpp2 = (const struct inoinfo **)pp2;
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate return ((*aclpp1)->i_blks[0] - (*aclpp2)->i_blks[0]);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate
277355d6bb5Sswilcox /*
278355d6bb5Sswilcox * Scan a chunk of a shadow file. Return zero if no ACLs were found,
279355d6bb5Sswilcox * or when all that were found were valid.
280355d6bb5Sswilcox */
281355d6bb5Sswilcox static int
bufchk(char * buf,int64_t len,fsck_ino_t inum)282355d6bb5Sswilcox bufchk(char *buf, int64_t len, fsck_ino_t inum)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate ufs_fsd_t *fsdp;
2857c478bd9Sstevel@tonic-gate ufs_acl_t *ufsaclp = NULL;
2867c478bd9Sstevel@tonic-gate int numacls;
287355d6bb5Sswilcox int curacl;
288355d6bb5Sswilcox struct type_counts_s {
289355d6bb5Sswilcox int nuser_objs;
290355d6bb5Sswilcox int ngroup_objs;
291355d6bb5Sswilcox int nother_objs;
292355d6bb5Sswilcox int nclass_objs;
293355d6bb5Sswilcox int ndef_user_objs;
294355d6bb5Sswilcox int ndef_group_objs;
295355d6bb5Sswilcox int ndef_other_objs;
296355d6bb5Sswilcox int ndef_class_objs;
297355d6bb5Sswilcox int nusers;
298355d6bb5Sswilcox int ngroups;
299355d6bb5Sswilcox int ndef_users;
300355d6bb5Sswilcox int ndef_groups;
301355d6bb5Sswilcox } type_counts[3]; /* indexed by FSD_ACL and FSD_DFACL */
302355d6bb5Sswilcox struct type_counts_s *tcp, *tcp_all, *tcp_def, *tcp_norm;
303355d6bb5Sswilcox int numdefs;
304355d6bb5Sswilcox caddr_t bad;
305355d6bb5Sswilcox caddr_t end = buf + len;
306355d6bb5Sswilcox int64_t recsz = 0;
307355d6bb5Sswilcox int64_t min_recsz = FSD_RECSZ(fsdp, sizeof (*fsdp));
308*0eca9a24Sjr26306 struct shadowclientinfo *sci;
309*0eca9a24Sjr26306 struct shadowclients *scc;
310*0eca9a24Sjr26306 fsck_ino_t target;
311*0eca9a24Sjr26306 int numtargets = 0;
312*0eca9a24Sjr26306
313*0eca9a24Sjr26306 /*
314*0eca9a24Sjr26306 * check we have a non-zero length for this shadow inode
315*0eca9a24Sjr26306 */
316*0eca9a24Sjr26306 if (len == 0) {
317*0eca9a24Sjr26306 pwarn("ACL I=%d HAS ZERO LENGTH\n", inum);
318*0eca9a24Sjr26306 return (1);
319*0eca9a24Sjr26306 }
3207c478bd9Sstevel@tonic-gate
321355d6bb5Sswilcox (void) memset(type_counts, 0, sizeof (type_counts));
322355d6bb5Sswilcox
323355d6bb5Sswilcox /* LINTED pointer cast alignment (aligned buffer always passed in) */
3247c478bd9Sstevel@tonic-gate for (fsdp = (ufs_fsd_t *)buf;
325*0eca9a24Sjr26306 (caddr_t)fsdp < end;
326355d6bb5Sswilcox /* LINTED as per the above */
327355d6bb5Sswilcox fsdp = (ufs_fsd_t *)((caddr_t)fsdp + recsz)) {
328355d6bb5Sswilcox
329355d6bb5Sswilcox recsz = FSD_RECSZ(fsdp, fsdp->fsd_size);
330355d6bb5Sswilcox if ((recsz < min_recsz) ||
331355d6bb5Sswilcox (((caddr_t)fsdp + recsz) > (buf + len))) {
332355d6bb5Sswilcox pwarn("Bad FSD entry size %lld in shadow inode %d",
333355d6bb5Sswilcox recsz, inum);
334355d6bb5Sswilcox if (reply("CLEAR SHADOW INODE") == 1) {
335355d6bb5Sswilcox freeino(inum, TI_PARENT);
336355d6bb5Sswilcox } else {
337355d6bb5Sswilcox /*
338355d6bb5Sswilcox * Bad size can cause the kernel to
339355d6bb5Sswilcox * go traipsing off into never-never land.
340355d6bb5Sswilcox */
341355d6bb5Sswilcox iscorrupt = 1;
342355d6bb5Sswilcox }
343355d6bb5Sswilcox return (0);
344355d6bb5Sswilcox }
345355d6bb5Sswilcox
3467c478bd9Sstevel@tonic-gate switch (fsdp->fsd_type) {
347355d6bb5Sswilcox case FSD_FREE: /* ignore empty slots */
348355d6bb5Sswilcox break;
3497c478bd9Sstevel@tonic-gate case FSD_ACL:
3507c478bd9Sstevel@tonic-gate case FSD_DFACL:
351355d6bb5Sswilcox /*
352355d6bb5Sswilcox * Subtract out the two ints in the fsd_type,
353355d6bb5Sswilcox * leaving us just the size of fsd_data[].
354355d6bb5Sswilcox */
3557c478bd9Sstevel@tonic-gate numacls = (fsdp->fsd_size - 2 * sizeof (int)) /
3567c478bd9Sstevel@tonic-gate sizeof (ufs_acl_t);
357355d6bb5Sswilcox tcp = &type_counts[fsdp->fsd_type];
358355d6bb5Sswilcox curacl = 0;
359355d6bb5Sswilcox /* LINTED pointer cast alignment */
3607c478bd9Sstevel@tonic-gate for (ufsaclp = (ufs_acl_t *)fsdp->fsd_data;
361355d6bb5Sswilcox numacls; ufsaclp++, curacl++) {
3627c478bd9Sstevel@tonic-gate switch (ufsaclp->acl_tag) {
3637c478bd9Sstevel@tonic-gate case USER_OBJ: /* Owner */
364355d6bb5Sswilcox tcp->nuser_objs++;
3657c478bd9Sstevel@tonic-gate break;
3667c478bd9Sstevel@tonic-gate case GROUP_OBJ: /* Group */
367355d6bb5Sswilcox tcp->ngroup_objs++;
3687c478bd9Sstevel@tonic-gate break;
3697c478bd9Sstevel@tonic-gate case OTHER_OBJ: /* Other */
370355d6bb5Sswilcox tcp->nother_objs++;
3717c478bd9Sstevel@tonic-gate break;
3727c478bd9Sstevel@tonic-gate case CLASS_OBJ: /* Mask */
373355d6bb5Sswilcox tcp->nclass_objs++;
3747c478bd9Sstevel@tonic-gate break;
3757c478bd9Sstevel@tonic-gate case DEF_USER_OBJ: /* Default Owner */
376355d6bb5Sswilcox tcp->ndef_user_objs++;
3777c478bd9Sstevel@tonic-gate break;
3787c478bd9Sstevel@tonic-gate case DEF_GROUP_OBJ: /* Default Group */
379355d6bb5Sswilcox tcp->ndef_group_objs++;
3807c478bd9Sstevel@tonic-gate break;
3817c478bd9Sstevel@tonic-gate case DEF_OTHER_OBJ: /* Default Other */
382355d6bb5Sswilcox tcp->ndef_other_objs++;
3837c478bd9Sstevel@tonic-gate break;
3847c478bd9Sstevel@tonic-gate case DEF_CLASS_OBJ: /* Default Mask */
385355d6bb5Sswilcox tcp->ndef_class_objs++;
3867c478bd9Sstevel@tonic-gate break;
3877c478bd9Sstevel@tonic-gate case USER: /* Users */
388355d6bb5Sswilcox tcp->nusers++;
3897c478bd9Sstevel@tonic-gate break;
3907c478bd9Sstevel@tonic-gate case GROUP: /* Groups */
391355d6bb5Sswilcox tcp->ngroups++;
3927c478bd9Sstevel@tonic-gate break;
3937c478bd9Sstevel@tonic-gate case DEF_USER: /* Default Users */
394355d6bb5Sswilcox tcp->ndef_users++;
3957c478bd9Sstevel@tonic-gate break;
3967c478bd9Sstevel@tonic-gate case DEF_GROUP: /* Default Groups */
397355d6bb5Sswilcox tcp->ndef_groups++;
3987c478bd9Sstevel@tonic-gate break;
3997c478bd9Sstevel@tonic-gate default:
4007c478bd9Sstevel@tonic-gate return (1);
4017c478bd9Sstevel@tonic-gate }
402355d6bb5Sswilcox
403355d6bb5Sswilcox if ((ufsaclp->acl_perm & ~07) != 0) {
4047c478bd9Sstevel@tonic-gate /*
405355d6bb5Sswilcox * Caller will report inode, etc
4067c478bd9Sstevel@tonic-gate */
407355d6bb5Sswilcox pwarn("Bad permission 0%o in ACL\n",
408355d6bb5Sswilcox ufsaclp->acl_perm);
409355d6bb5Sswilcox return (1);
410355d6bb5Sswilcox }
411355d6bb5Sswilcox
4127c478bd9Sstevel@tonic-gate numacls--;
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate break;
4157c478bd9Sstevel@tonic-gate default:
416355d6bb5Sswilcox if (fsdp->fsd_type >= FSD_RESERVED3 &&
417355d6bb5Sswilcox fsdp->fsd_type <= FSD_RESERVED7)
418355d6bb5Sswilcox bad = "Unexpected";
419355d6bb5Sswilcox else
420355d6bb5Sswilcox bad = "Unknown";
421355d6bb5Sswilcox pwarn("%s FSD type %d in shadow inode %d",
422355d6bb5Sswilcox bad, fsdp->fsd_type, inum);
423355d6bb5Sswilcox /*
424355d6bb5Sswilcox * This is relatively harmless, since the
425355d6bb5Sswilcox * kernel will ignore any entries it doesn't
426355d6bb5Sswilcox * recognize. Don't bother with iscorrupt.
427355d6bb5Sswilcox */
428355d6bb5Sswilcox if (preen) {
429355d6bb5Sswilcox (void) printf(" (IGNORED)\n");
430355d6bb5Sswilcox } else if (reply("IGNORE") == 0) {
431355d6bb5Sswilcox if (reply("CLEAR SHADOW INODE") == 1) {
432355d6bb5Sswilcox freeino(inum, TI_PARENT);
433355d6bb5Sswilcox }
434355d6bb5Sswilcox return (0);
435355d6bb5Sswilcox }
4367c478bd9Sstevel@tonic-gate break;
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate if ((caddr_t)fsdp != (buf + len)) {
4407c478bd9Sstevel@tonic-gate return (1);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /* If we didn't find any acls, ignore the unknown attribute */
4447c478bd9Sstevel@tonic-gate if (ufsaclp == NULL)
4457c478bd9Sstevel@tonic-gate return (0);
4467c478bd9Sstevel@tonic-gate
447355d6bb5Sswilcox /*
448355d6bb5Sswilcox * Should only have default ACLs in FSD_DFACL records.
449355d6bb5Sswilcox * However, the kernel can handle it, so just report that
450355d6bb5Sswilcox * something odd might be going on.
451355d6bb5Sswilcox */
452355d6bb5Sswilcox tcp = &type_counts[FSD_DFACL];
453355d6bb5Sswilcox if (verbose &&
454355d6bb5Sswilcox (tcp->nuser_objs != 0 ||
455355d6bb5Sswilcox tcp->ngroup_objs != 0 ||
456355d6bb5Sswilcox tcp->nother_objs != 0 ||
457355d6bb5Sswilcox tcp->nclass_objs != 0 ||
458355d6bb5Sswilcox tcp->nusers != 0 ||
459355d6bb5Sswilcox tcp->ngroups != 0)) {
460355d6bb5Sswilcox (void) printf("NOTE: ACL I=%d has miscategorized ACLs. ",
461355d6bb5Sswilcox inum);
462355d6bb5Sswilcox (void) printf("This is harmless, but not normal.\n");
4637c478bd9Sstevel@tonic-gate }
464355d6bb5Sswilcox
465355d6bb5Sswilcox /*
466355d6bb5Sswilcox * Similarly for default ACLs in FSD_ACL records.
467355d6bb5Sswilcox */
468355d6bb5Sswilcox tcp = &type_counts[FSD_ACL];
469355d6bb5Sswilcox if (verbose &&
470355d6bb5Sswilcox (tcp->ndef_user_objs != 0 ||
471355d6bb5Sswilcox tcp->ndef_group_objs != 0 ||
472355d6bb5Sswilcox tcp->ndef_other_objs != 0 ||
473355d6bb5Sswilcox tcp->ndef_class_objs != 0 ||
474355d6bb5Sswilcox tcp->ndef_users != 0 ||
475355d6bb5Sswilcox tcp->ndef_groups != 0)) {
476355d6bb5Sswilcox (void) printf("NOTE: ACL I=%d has miscategorized ACLs.",
477355d6bb5Sswilcox inum);
478355d6bb5Sswilcox (void) printf(" This is harmless, but not normal.\n");
4797c478bd9Sstevel@tonic-gate }
480355d6bb5Sswilcox
481355d6bb5Sswilcox /*
482355d6bb5Sswilcox * Get consolidated totals, now that we're done with checking
483355d6bb5Sswilcox * the segregation above. Assumes that neither FSD_ACL nor
484355d6bb5Sswilcox * FSD_DFACL are zero.
485355d6bb5Sswilcox */
486355d6bb5Sswilcox tcp_all = &type_counts[0];
487355d6bb5Sswilcox tcp_norm = &type_counts[FSD_ACL];
488355d6bb5Sswilcox tcp_def = &type_counts[FSD_DFACL];
489355d6bb5Sswilcox
490355d6bb5Sswilcox tcp_all->nuser_objs = tcp_def->nuser_objs + tcp_norm->nuser_objs;
491355d6bb5Sswilcox tcp_all->ngroup_objs = tcp_def->ngroup_objs + tcp_norm->ngroup_objs;
492355d6bb5Sswilcox tcp_all->nother_objs = tcp_def->nother_objs + tcp_norm->nother_objs;
493355d6bb5Sswilcox tcp_all->nclass_objs = tcp_def->nclass_objs + tcp_norm->nclass_objs;
494355d6bb5Sswilcox tcp_all->ndef_user_objs =
495355d6bb5Sswilcox tcp_def->ndef_user_objs + tcp_norm->ndef_user_objs;
496355d6bb5Sswilcox tcp_all->ndef_group_objs =
497355d6bb5Sswilcox tcp_def->ndef_group_objs + tcp_norm->ndef_group_objs;
498355d6bb5Sswilcox tcp_all->ndef_other_objs =
499355d6bb5Sswilcox tcp_def->ndef_other_objs + tcp_norm->ndef_other_objs;
500355d6bb5Sswilcox tcp_all->ndef_class_objs =
501355d6bb5Sswilcox tcp_def->ndef_class_objs + tcp_norm->ndef_class_objs;
502355d6bb5Sswilcox tcp_all->nusers = tcp_def->nusers + tcp_norm->nusers;
503355d6bb5Sswilcox tcp_all->ngroups = tcp_def->ngroups + tcp_norm->ngroups;
504355d6bb5Sswilcox tcp_all->ndef_users = tcp_def->ndef_users + tcp_norm->ndef_users;
505355d6bb5Sswilcox tcp_all->ndef_groups = tcp_def->ndef_groups + tcp_norm->ndef_groups;
506355d6bb5Sswilcox
507355d6bb5Sswilcox /*
508355d6bb5Sswilcox * Check relationships among acls
509355d6bb5Sswilcox */
510355d6bb5Sswilcox if (tcp_all->nuser_objs != 1 ||
511355d6bb5Sswilcox tcp_all->ngroup_objs != 1 ||
512355d6bb5Sswilcox tcp_all->nother_objs != 1 ||
513355d6bb5Sswilcox tcp_all->nclass_objs > 1) {
5147c478bd9Sstevel@tonic-gate return (1);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
517355d6bb5Sswilcox if (tcp_all->ngroups && !tcp_all->nclass_objs) {
518355d6bb5Sswilcox return (1);
519355d6bb5Sswilcox }
520355d6bb5Sswilcox
521355d6bb5Sswilcox if (tcp_all->ndef_user_objs > 1 ||
522355d6bb5Sswilcox tcp_all->ndef_group_objs > 1 ||
523355d6bb5Sswilcox tcp_all->ndef_other_objs > 1 ||
524355d6bb5Sswilcox tcp_all->ndef_class_objs > 1) {
525355d6bb5Sswilcox return (1);
526355d6bb5Sswilcox }
527355d6bb5Sswilcox
528355d6bb5Sswilcox /*
529355d6bb5Sswilcox * Check relationships among default acls
530355d6bb5Sswilcox */
531355d6bb5Sswilcox numdefs = tcp_all->ndef_other_objs + tcp_all->ndef_user_objs +
532355d6bb5Sswilcox tcp_all->ndef_group_objs;
533355d6bb5Sswilcox
5347c478bd9Sstevel@tonic-gate if (numdefs != 0 && numdefs != 3) {
5357c478bd9Sstevel@tonic-gate return (1);
5367c478bd9Sstevel@tonic-gate }
537355d6bb5Sswilcox
538355d6bb5Sswilcox /*
539*0eca9a24Sjr26306 * If there are default acls, then the shadow inode's clients
540*0eca9a24Sjr26306 * must be a directory or an xattr directory.
541355d6bb5Sswilcox */
542*0eca9a24Sjr26306 if (numdefs != 0) {
543*0eca9a24Sjr26306 /* This is an ACL so find it's clients */
544*0eca9a24Sjr26306 for (sci = shadowclientinfo; sci != NULL; sci = sci->next)
545*0eca9a24Sjr26306 if (sci->shadow == inum)
546*0eca9a24Sjr26306 break;
547*0eca9a24Sjr26306 if ((sci == NULL) || (sci->clients == NULL))
5487c478bd9Sstevel@tonic-gate return (1);
549*0eca9a24Sjr26306
550*0eca9a24Sjr26306 /* Got shadow info, now look at clients */
551*0eca9a24Sjr26306 for (scc = sci->clients; scc != NULL; scc = scc->next) {
552*0eca9a24Sjr26306 for (numtargets = 0; numtargets < scc->nclients;
553*0eca9a24Sjr26306 numtargets++) {
554*0eca9a24Sjr26306 target = scc->client[numtargets];
555*0eca9a24Sjr26306 if (!INO_IS_DVALID(target))
556*0eca9a24Sjr26306 return (1);
557*0eca9a24Sjr26306 }
558*0eca9a24Sjr26306 }
5597c478bd9Sstevel@tonic-gate }
560355d6bb5Sswilcox
561355d6bb5Sswilcox if (tcp_all->ndef_groups && !tcp_all->ndef_class_objs) {
5627c478bd9Sstevel@tonic-gate return (1);
5637c478bd9Sstevel@tonic-gate }
564355d6bb5Sswilcox
565355d6bb5Sswilcox if ((tcp_all->ndef_users || tcp_all->ndef_groups) &&
566355d6bb5Sswilcox ((numdefs != 3) && !tcp_all->ndef_class_objs)) {
567355d6bb5Sswilcox return (1);
568355d6bb5Sswilcox }
569355d6bb5Sswilcox
5707c478bd9Sstevel@tonic-gate return (0);
5717c478bd9Sstevel@tonic-gate }
572