xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass3b.c (revision 7c478bd9)
1 /*
2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/mntent.h>
35 #include <sys/acl.h>
36 #include <sys/fs/ufs_acl.h>
37 
38 #define	bcopy(f, t, n)	memcpy(t, f, n)
39 #define	bzero(s, n)	memset(s, 0, n)
40 #define	bcmp(s, d, n)	memcmp(s, d, n)
41 
42 #define	index(s, r)	strchr(s, r)
43 #define	rindex(s, r)	strrchr(s, r)
44 
45 #include <sys/fs/ufs_fs.h>
46 #include <sys/vnode.h>
47 #include <string.h>
48 #include <sys/fs/ufs_inode.h>
49 #include "fsck.h"
50 
51 int pass3bcheck(struct inodesc *);
52 int aclblksort();
53 void dodump(char *, int);
54 int bufchk(char *, int64_t);
55 void listshadows(void);
56 
57 pass3b()
58 {
59 	ino_t inumber;
60 	struct dinode *dp;
61 	struct aclinfo *aclp;
62 	struct inodesc curino;
63 	char pathbuf[MAXPATHLEN + 1];
64 	int64_t maxaclsize = 0;
65 	struct shadowclientinfo *sci;
66 	struct shadowclients *scc;
67 	int i;
68 
69 	/*
70 	 * Sort the acl list into disk block order.
71 	 */
72 	qsort((char *)aclpsort, (int)aclplast, sizeof (*aclpsort), aclblksort);
73 	/*
74 	 * Scan all the acl inodes, finding the largest acl file.
75 	 */
76 	for (inumber = 0; inumber < aclplast; inumber++) {
77 		aclp = aclpsort[inumber];
78 		/* ACL file will not be >=2GB */
79 		if ((int64_t)aclp->i_isize > maxaclsize)
80 			maxaclsize = (int64_t)aclp->i_isize;
81 	}
82 	maxaclsize = ((maxaclsize / sblock.fs_bsize) + 1) *
83 				sblock.fs_bsize;
84 	if ((aclbuf = malloc(maxaclsize)) == NULL) {
85 		printf("cannot alloc %ld bytes for aclbuf\n", maxaclsize);
86 		return (1);
87 	}
88 	/*
89 	 * Scan all the acl inodes, checking contents
90 	 */
91 	for (inumber = 0; inumber < aclplast; inumber++) {
92 		aclp = aclpsort[inumber];
93 		dp = ginode(aclp->i_number);
94 		curino.id_fix = FIX;
95 		curino.id_type = ACL;
96 		curino.id_func = pass3bcheck;
97 		curino.id_number = aclp->i_number;
98 		curino.id_filesize = aclp->i_isize;
99 		aclbufoff = 0;
100 		bzero(aclbuf, (size_t)maxaclsize);
101 		if ((ckinode(dp, &curino) & KEEPON) == 0 ||
102 				bufchk(aclbuf, (int64_t)aclp->i_isize)) {
103 			if (dp->di_nlink <= 0) {
104 				statemap[aclp->i_number] = FSTATE;
105 				continue;
106 			}
107 			printf("ACL I=%d BAD/CORRUPT", aclp->i_number);
108 			if (preen || reply("CLEAR") == 1) {
109 				if (preen)
110 					printf("\n");
111 				freeino(aclp->i_number);
112 			}
113 		}
114 	}
115 	/*
116 	 * Now scan all shadow inodes, checking that any inodes that previously
117 	 * had an acl still have an acl.
118 	 */
119 	for (sci = shadowclientinfo; sci; sci = sci->next) {
120 		if (statemap[sci->shadow] != SSTATE) {
121 			for (scc = sci->clients; scc; scc = scc->next) {
122 				for (i = 0; i < scc->nclients; i++) {
123 					printf("I=%d HAS BAD/CLEARED ACL I=%d",
124 					    scc->client[i], sci->shadow);
125 					if (preen || reply("FIX") == 1) {
126 						if (preen)
127 							printf("\n");
128 						dp = ginode(scc->client[i]);
129 						dp->di_mode &= IFMT;
130 						dp->di_smode = dp->di_mode;
131 						/*
132 						 * Decrement link count -
133 						 * pass1 made sure the shadow
134 						 * inode # is a valid inode
135 						 * number.
136 						 */
137 						lncntp[dp->di_shadow]++;
138 						dp->di_shadow = 0;
139 						inodirty();
140 					}
141 				}
142 			}
143 		}
144 	}
145 	/* listshadows(); */
146 }
147 
148 /*
149  * Collect all the (data) blocks of an acl file into a buffer.
150  * Later we'll scan the buffer and validate the acl data.
151  */
152 int
153 pass3bcheck(struct inodesc *idesc)
154 {
155 	struct bufarea *bp;
156 	int size, bsize;
157 
158 	if (aclbufoff == idesc->id_filesize) {
159 		return (STOP);
160 	}
161 	bsize = size = sblock.fs_fsize * idesc->id_numfrags;
162 	if ((size + aclbufoff) > idesc->id_filesize)
163 		size = idesc->id_filesize - aclbufoff;
164 	bp = getdatablk(idesc->id_blkno, bsize);
165 	bcopy(bp->b_un.b_buf, aclbuf + aclbufoff, (size_t)size);
166 	aclbufoff += size;
167 	brelse(bp);
168 	return (KEEPON);
169 }
170 
171 /*
172  * Routine to sort disk blocks.
173  */
174 aclblksort(aclpp1, aclpp2)
175 	struct aclinfo **aclpp1, **aclpp2;
176 {
177 
178 	return ((*aclpp1)->i_blks[0] - (*aclpp2)->i_blks[0]);
179 }
180 
181 int
182 bufchk(char *buf, int64_t len)
183 {
184 	ufs_fsd_t *fsdp;
185 	ufs_acl_t *ufsaclp = NULL;
186 	int numacls;
187 	int i;
188 	int nuser_objs = 0;
189 	int ngroup_objs = 0;
190 	int nother_objs = 0;
191 	int nclass_objs = 0;
192 	int ndef_user_objs = 0;
193 	int ndef_group_objs = 0;
194 	int ndef_other_objs = 0;
195 	int ndef_class_objs = 0;
196 	int nusers = 0;
197 	int ngroups = 0;
198 	int ndef_users = 0;
199 	int ndef_groups = 0;
200 	int numdefs = 0;
201 
202 	for (fsdp = (ufs_fsd_t *)buf;
203 	    (caddr_t)fsdp < (buf + len) &&
204 	    ((caddr_t)fsdp + fsdp->fsd_size) <= (buf + len);
205 	    fsdp = (ufs_fsd_t *)((caddr_t)fsdp +
206 	    FSD_RECSZ(fsdp, fsdp->fsd_size))) {
207 		switch (fsdp->fsd_type) {
208 		case FSD_ACL:
209 		case FSD_DFACL:
210 			numacls = (fsdp->fsd_size - 2 * sizeof (int)) /
211 							sizeof (ufs_acl_t);
212 			for (ufsaclp = (ufs_acl_t *)fsdp->fsd_data;
213 							numacls; ufsaclp++) {
214 				switch (ufsaclp->acl_tag) {
215 				case USER_OBJ:		/* Owner */
216 					nuser_objs++;
217 					break;
218 				case GROUP_OBJ:		/* Group */
219 					ngroup_objs++;
220 					break;
221 				case OTHER_OBJ:		/* Other */
222 					nother_objs++;
223 					break;
224 				case CLASS_OBJ:		/* Mask */
225 					nclass_objs++;
226 					break;
227 				case DEF_USER_OBJ:	/* Default Owner */
228 					ndef_user_objs++;
229 					break;
230 				case DEF_GROUP_OBJ:	/* Default Group */
231 					ndef_group_objs++;
232 					break;
233 				case DEF_OTHER_OBJ:	/* Default Other */
234 					ndef_other_objs++;
235 					break;
236 				case DEF_CLASS_OBJ:	/* Default Mask */
237 					ndef_class_objs++;
238 					break;
239 				case USER:		/* Users */
240 					nusers++;
241 					break;
242 				case GROUP:		/* Groups */
243 					ngroups++;
244 					break;
245 				case DEF_USER:		/* Default Users */
246 					ndef_users++;
247 					break;
248 				case DEF_GROUP:		/* Default Groups */
249 					ndef_groups++;
250 					break;
251 				default:
252 					return (1);
253 				}
254 /*
255  *				if ((ufsaclp->acl_perm & ~07) != 0) {
256  *					return (1);
257  *				}
258  */
259 				numacls--;
260 			}
261 			break;
262 		default:
263 			break;
264 		}
265 	}
266 	if ((caddr_t)fsdp != (buf + len)) {
267 		return (1);
268 	}
269 
270 	/* If we didn't find any acls, ignore the unknown attribute */
271 	if (ufsaclp == NULL)
272 		return (0);
273 
274 	/* Check relationships amoung acls */
275 	if (nuser_objs != 1 || ngroup_objs != 1 ||
276 	    nother_objs != 1 || nclass_objs > 1) {
277 		return (1);
278 	}
279 	if (ngroups && !nclass_objs) {
280 		return (1);
281 	}
282 	if (ndef_other_objs > 1 || ndef_user_objs > 1 ||
283 	    ndef_group_objs > 1 || ndef_class_objs > 1) {
284 		return (1);
285 	}
286 
287 	/* Check relationships amoung default acls */
288 	numdefs = ndef_other_objs + ndef_user_objs + ndef_group_objs;
289 	if (numdefs != 0 && numdefs != 3) {
290 		return (1);
291 	}
292 	if (ndef_groups && !ndef_class_objs) {
293 		return (1);
294 	}
295 	if ((ndef_users || ndef_groups) &&
296 	    ((numdefs != 3) && !ndef_class_objs)) {
297 		return (1);
298 	}
299 	return (0);
300 }
301