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