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 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 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 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 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 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