~ubuntu-branches/ubuntu/utopic/xfsprogs/utopic-proposed

« back to all changes in this revision

Viewing changes to repair/attr_repair.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathan Scott
  • Date: 2002-04-13 09:45:06 UTC
  • Revision ID: james.westby@ubuntu.com-20020413094506-t8dhemv41gkeg4kx
Tags: 2.0.3-1
New upstream bugfix release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
 
3
 * 
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of version 2 of the GNU General Public License as
 
6
 * published by the Free Software Foundation.
 
7
 * 
 
8
 * This program is distributed in the hope that it would be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
11
 * 
 
12
 * Further, this software is distributed without any warranty that it is
 
13
 * free of the rightful claim of any third person regarding infringement
 
14
 * or the like.  Any license provided herein, whether implied or
 
15
 * otherwise, applies only to this software file.  Patent licenses, if
 
16
 * any, provided herein do not apply to combinations of this program with
 
17
 * other software, or any other product whatsoever.
 
18
 * 
 
19
 * You should have received a copy of the GNU General Public License along
 
20
 * with this program; if not, write the Free Software Foundation, Inc., 59
 
21
 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
22
 * 
 
23
 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 
24
 * Mountain View, CA  94043, or:
 
25
 * 
 
26
 * http://www.sgi.com 
 
27
 * 
 
28
 * For further information regarding this notice, see: 
 
29
 * 
 
30
 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 
31
 */
 
32
 
 
33
#include <libxfs.h>
 
34
#include "globals.h"
 
35
#include "err_protos.h"
 
36
#include "attr_repair.h"
 
37
#include "dir.h"
 
38
#include "dinode.h"
 
39
#include "bmap.h"
 
40
 
 
41
static int xfs_acl_valid(xfs_acl_t *aclp);
 
42
static int xfs_mac_valid(xfs_mac_label_t *lp);
 
43
 
 
44
 
 
45
/*
 
46
 * For attribute repair, there are 3 formats to worry about. First, is 
 
47
 * shortform attributes which reside in the inode. Second is the leaf
 
48
 * form, and lastly the btree. Much of this models after the directory
 
49
 * structure so code resembles the directory repair cases. 
 
50
 * For shortform case, if an attribute looks corrupt, it is removed.
 
51
 * If that leaves the shortform down to 0 attributes, it's okay and 
 
52
 * will appear to just have a null attribute fork. Some checks are done
 
53
 * for validity of the value field based on what the security needs are.
 
54
 * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
 
55
 * security attributes exist. They will be cleared if invalid.
 
56
 * No other values will be checked. The DMF folks do not have current
 
57
 * requirements, but may in the future.
 
58
 *
 
59
 * For leaf block attributes, it requires more processing. One sticky
 
60
 * point is that the attributes can be local (within the leaf) or 
 
61
 * remote (outside the leaf in other blocks). Thinking of local only
 
62
 * if you get a bad attribute, and want to delete just one, its a-okay
 
63
 * if it remains large enough to still be a leaf block attribute. Otherwise,
 
64
 * it may have to be converted to shortform. How to convert this and when
 
65
 * is an issue. This call is happening in Phase3. Phase5 will capture empty
 
66
 * blocks, but Phase6 allows you to use the simulation library which knows
 
67
 * how to handle attributes in the kernel for converting formats. What we
 
68
 * could do is mark an attribute to be cleared now, but in phase6 somehow
 
69
 * have it cleared for real and then the format changed to shortform if
 
70
 * applicable. Since this requires more work than I anticipate can be
 
71
 * accomplished for the next release, we will instead just say any bad
 
72
 * attribute in the leaf block will make the entire attribute fork be
 
73
 * cleared. The simplest way to do that is to ignore the leaf format, and
 
74
 * call clear_dinode_attr to just make a shortform attribute fork with
 
75
 * zero entries. 
 
76
 *
 
77
 * Another issue with handling repair on leaf attributes is the remote
 
78
 * blocks. To make sure that they look good and are not used multiple times
 
79
 * by the attribute fork, some mechanism to keep track of all them is necessary.
 
80
 * Do this in the future, time permitting. For now, note that there is no
 
81
 * check for remote blocks and their allocations.
 
82
 *
 
83
 * For btree formatted attributes, the model can follow directories. That
 
84
 * would mean go down the tree to the leftmost leaf. From there moving down
 
85
 * the links and processing each. They would call back up the tree, to verify
 
86
 * that the tree structure is okay. Any problems will result in the attribute
 
87
 * fork being emptied and put in shortform format.
 
88
 */
 
89
 
 
90
/*
 
91
 * This routine just checks what security needs are for attribute values
 
92
 * only called when root flag is set, otherwise these names could exist in
 
93
 * in user attribute land without a conflict.
 
94
 * If value is non-zero, then a remote attribute is being passed in
 
95
 */
 
96
 
 
97
int
 
98
valuecheck(char *namevalue, char *value, int namelen, int valuelen)
 
99
{
 
100
        /* for proper alignment issues, get the structs and bcopy the values */
 
101
        xfs_mac_label_t macl;
 
102
        xfs_acl_t thisacl;
 
103
        void *valuep;
 
104
        int clearit = 0;
 
105
 
 
106
        if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) || 
 
107
                        (strncmp(namevalue, SGI_ACL_DEFAULT, 
 
108
                                SGI_ACL_DEFAULT_SIZE) == 0)) {
 
109
                if (value == NULL) {    
 
110
                        bzero(&thisacl, sizeof(xfs_acl_t));
 
111
                        bcopy(namevalue+namelen, &thisacl, valuelen);
 
112
                        valuep = &thisacl;
 
113
                } else
 
114
                        valuep = value;
 
115
 
 
116
                if (xfs_acl_valid((xfs_acl_t *) valuep) != 0) { /* 0 is valid */
 
117
                        clearit = 1;
 
118
                        do_warn("entry contains illegal value in attribute named SGI_ACL_FILE or SGI_ACL_DEFAULT\n");
 
119
                }
 
120
        } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
 
121
                if (value == NULL) {
 
122
                        bzero(&macl, sizeof(xfs_mac_label_t));
 
123
                        bcopy(namevalue+namelen, &macl, valuelen);
 
124
                        valuep = &macl;
 
125
                } else 
 
126
                        valuep = value;
 
127
 
 
128
                if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
 
129
                         /*
 
130
                         *if sysconf says MAC enabled, 
 
131
                         *      temp = mac_from_text("msenhigh/mintlow", NULL)
 
132
                         *      copy it to value, update valuelen, totsize
 
133
                         *      This causes pushing up or down of all following
 
134
                         *      attributes, forcing a attribute format change!!
 
135
                         * else clearit = 1;
 
136
                         */
 
137
                        clearit = 1;
 
138
                        do_warn("entry contains illegal value in attribute named SGI_MAC_LABEL\n");
 
139
                }
 
140
        } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
 
141
                if ( valuelen != sizeof(xfs_cap_set_t)) {
 
142
                        clearit = 1;
 
143
                        do_warn("entry contains illegal value in attribute named SGI_CAP_FILE\n");
 
144
                }
 
145
        }
 
146
 
 
147
        return(clearit);
 
148
}
 
149
 
 
150
 
 
151
/*
 
152
 * this routine validates the attributes in shortform format.
 
153
 * a non-zero return repair value means certain attributes are bogus
 
154
 * and were cleared if possible. Warnings do not generate error conditions
 
155
 * if you cannot modify the structures. repair is set to 1, if anything
 
156
 * was fixed.
 
157
 */
 
158
int
 
159
process_shortform_attr(
 
160
        xfs_ino_t       ino,
 
161
        xfs_dinode_t    *dip,
 
162
        int             *repair)        
 
163
{
 
164
        xfs_attr_shortform_t    *asf;
 
165
        xfs_attr_sf_entry_t     *currententry, *nextentry, *tempentry;
 
166
        int                     i, junkit;
 
167
        int                     currentsize, remainingspace;
 
168
        
 
169
        *repair = 0;
 
170
 
 
171
        asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
 
172
 
 
173
        /* Assumption: hdr.totsize is less than a leaf block and was checked
 
174
         * by lclinode for valid sizes. Check the count though. 
 
175
        */
 
176
        if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0) 
 
177
                /* then the total size should just be the header length */
 
178
                if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) {
 
179
                        /* whoops there's a discrepancy. Clear the hdr */
 
180
                        if (!no_modify) {
 
181
                                do_warn("there are no attributes in the fork for inode %llu \n", ino);
 
182
                                INT_SET(asf->hdr.totsize, ARCH_CONVERT,
 
183
                                                sizeof(xfs_attr_sf_hdr_t));
 
184
                                *repair = 1;
 
185
                                return(1);      
 
186
                        } else {
 
187
                                do_warn("would junk the attribute fork since the count is 0 for inode %llu\n",ino);
 
188
                                return(1);
 
189
                        }
 
190
                }
 
191
                
 
192
        currentsize = sizeof(xfs_attr_sf_hdr_t); 
 
193
        remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize;
 
194
        nextentry = &asf->list[0];
 
195
        for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++)  {
 
196
                currententry = nextentry;
 
197
                junkit = 0;
 
198
 
 
199
                /* don't go off the end if the hdr.count was off */
 
200
                if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) > 
 
201
                                INT_GET(asf->hdr.totsize, ARCH_CONVERT))
 
202
                        break; /* get out and reset count and totSize */
 
203
 
 
204
                /* if the namelen is 0, can't get to the rest of the entries */
 
205
                if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) {
 
206
                        do_warn("zero length name entry in attribute fork, ");
 
207
                        if (!no_modify) {
 
208
                                do_warn("truncating attributes for inode %llu to %d \n", ino, i);
 
209
                                *repair = 1;
 
210
                                break;  /* and then update hdr fields */
 
211
                        } else {
 
212
                                do_warn("would truncate attributes for inode %llu to %d \n", ino, i);
 
213
                                break;
 
214
                        }
 
215
                } else {
 
216
                        /* It's okay to have a 0 length valuelen, but do a
 
217
                         * rough check to make sure we haven't gone outside of
 
218
                         * totsize.
 
219
                         */
 
220
                        if ((remainingspace < INT_GET(currententry->namelen, ARCH_CONVERT)) ||
 
221
                                ((remainingspace - INT_GET(currententry->namelen, ARCH_CONVERT))
 
222
                                          < INT_GET(currententry->valuelen, ARCH_CONVERT))) {
 
223
                                do_warn("name or value attribute lengths are too large, \n");
 
224
                                if (!no_modify) {
 
225
                                        do_warn(" truncating attributes for inode %llu to %d \n", ino, i);
 
226
                                        *repair = 1; 
 
227
                                        break; /* and then update hdr fields */
 
228
                                } else {
 
229
                                        do_warn(" would truncate attributes for inode %llu to %d \n", ino, i);  
 
230
                                        break;
 
231
                                }       
 
232
                        }
 
233
                }
 
234
        
 
235
                /* namecheck checks for / and null terminated for file names. 
 
236
                 * attributes names currently follow the same rules.
 
237
                */
 
238
                if (namecheck((char *)&currententry->nameval[0], 
 
239
                                INT_GET(currententry->namelen, ARCH_CONVERT)))  {
 
240
                        do_warn("entry contains illegal character in shortform attribute name\n");
 
241
                        junkit = 1;
 
242
                }
 
243
 
 
244
                if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
 
245
                        do_warn("entry has INCOMPLETE flag on in shortform attribute\n");
 
246
                        junkit = 1;
 
247
                }
 
248
 
 
249
                /* Only check values for root security attributes */
 
250
                if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) 
 
251
                       junkit = valuecheck((char *)&currententry->nameval[0], NULL, 
 
252
                                INT_GET(currententry->namelen, ARCH_CONVERT), INT_GET(currententry->valuelen, ARCH_CONVERT));
 
253
 
 
254
                remainingspace = remainingspace - 
 
255
                                XFS_ATTR_SF_ENTSIZE(currententry);
 
256
 
 
257
                if (junkit) {
 
258
                        if (!no_modify) {
 
259
                                /* get rid of only this entry */
 
260
                                do_warn("removing attribute entry %d for inode %llu \n", i, ino);
 
261
                                tempentry = (xfs_attr_sf_entry_t *)
 
262
                                        ((__psint_t) currententry +
 
263
                                         XFS_ATTR_SF_ENTSIZE(currententry));
 
264
                                memmove(currententry,tempentry,remainingspace);
 
265
                                INT_MOD(asf->hdr.count, ARCH_CONVERT, -1);
 
266
                                i--; /* no worries, it will wrap back to 0 */
 
267
                                *repair = 1;
 
268
                                continue; /* go back up now */
 
269
                        } else { 
 
270
                                do_warn("would remove attribute entry %d for inode %llu \n", i, ino);
 
271
                        }
 
272
                }
 
273
 
 
274
                /* Let's get ready for the next entry... */
 
275
                nextentry = (xfs_attr_sf_entry_t *)
 
276
                         ((__psint_t) nextentry +
 
277
                         XFS_ATTR_SF_ENTSIZE(currententry));
 
278
                currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
 
279
        
 
280
                } /* end the loop */
 
281
 
 
282
        
 
283
        if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i)  {
 
284
                if (no_modify)  {
 
285
                        do_warn("would have corrected attribute entry count in inode %llu from %d to %d\n",
 
286
                                ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
 
287
                } else  {
 
288
                        do_warn("corrected attribute entry count in inode %llu, was %d, now %d\n",
 
289
                                ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
 
290
                        INT_SET(asf->hdr.count, ARCH_CONVERT, i);
 
291
                        *repair = 1;
 
292
                }
 
293
        }
 
294
        
 
295
        /* ASSUMPTION: currentsize <= totsize */
 
296
        if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize)  {
 
297
                if (no_modify)  {
 
298
                        do_warn("would have corrected attribute totsize in inode %llu from %d to %d\n",
 
299
                                ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
 
300
                } else  {
 
301
                        do_warn("corrected attribute entry totsize in inode %llu, was %d, now %d\n",
 
302
                                ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
 
303
                        INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize);
 
304
                        *repair = 1;
 
305
                }
 
306
        }
 
307
 
 
308
        return(*repair);
 
309
}
 
310
 
 
311
/* This routine brings in blocks from disk one by one and assembles them
 
312
 * in the value buffer. If get_bmapi gets smarter later to return an extent
 
313
 * or list of extents, that would be great. For now, we don't expect too
 
314
 * many blocks per remote value, so one by one is sufficient.
 
315
 */
 
316
static int
 
317
rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
 
318
                xfs_dablk_t blocknum, int valuelen, char* value)
 
319
{
 
320
        xfs_dfsbno_t    bno;
 
321
        xfs_buf_t       *bp;
 
322
        int             clearit = 0, i = 0, length = 0, amountdone = 0;
 
323
        
 
324
        /* ASSUMPTION: valuelen is a valid number, so use it for looping */
 
325
        /* Note that valuelen is not a multiple of blocksize */  
 
326
        while (amountdone < valuelen) {
 
327
                bno = blkmap_get(blkmap, blocknum + i);
 
328
                if (bno == NULLDFSBNO) {
 
329
                        do_warn("remote block for attributes of inode %llu"
 
330
                                " is missing\n", ino);
 
331
                        clearit = 1;
 
332
                        break;
 
333
                }
 
334
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
 
335
                                XFS_FSB_TO_BB(mp, 1), 0);
 
336
                if (!bp) {
 
337
                        do_warn("can't read remote block for attributes"
 
338
                                " of inode %llu\n", ino);
 
339
                        clearit = 1;
 
340
                        break;
 
341
                }
 
342
                ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp));
 
343
                length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone);
 
344
                bcopy(XFS_BUF_PTR(bp), value, length); 
 
345
                amountdone += length;
 
346
                value += length;
 
347
                i++;
 
348
                libxfs_putbuf(bp);
 
349
        }
 
350
        return (clearit);
 
351
}
 
352
 
 
353
/*
 
354
 * freespace map for directory and attribute leaf blocks (1 bit per byte)
 
355
 * 1 == used, 0 == free
 
356
 */
 
357
static da_freemap_t attr_freemap[DA_BMAP_SIZE];
 
358
 
 
359
/* The block is read in. The magic number and forward / backward
 
360
 * links are checked by the caller process_leaf_attr.
 
361
 * If any problems occur the routine returns with non-zero. In
 
362
 * this case the next step is to clear the attribute fork, by
 
363
 * changing it to shortform and zeroing it out. Forkoff need not
 
364
 * be changed. 
 
365
 */
 
366
 
 
367
int
 
368
process_leaf_attr_block(
 
369
        xfs_mount_t     *mp,
 
370
        xfs_attr_leafblock_t *leaf,
 
371
        xfs_dablk_t     da_bno,
 
372
        xfs_ino_t       ino,
 
373
        blkmap_t        *blkmap,
 
374
        xfs_dahash_t    last_hashval,
 
375
        xfs_dahash_t    *current_hashval,
 
376
        int             *repair)        
 
377
{
 
378
        xfs_attr_leaf_entry_t *entry;
 
379
        xfs_attr_leaf_name_local_t *local;
 
380
        xfs_attr_leaf_name_remote_t *remotep;
 
381
        int  i, start, stop, clearit, usedbs, firstb, thissize;
 
382
 
 
383
        clearit = usedbs = 0;
 
384
        *repair = 0;
 
385
        firstb = mp->m_sb.sb_blocksize; 
 
386
        stop = sizeof(xfs_attr_leaf_hdr_t);
 
387
 
 
388
        /* does the count look sorta valid? */
 
389
        if (INT_GET(leaf->hdr.count, ARCH_CONVERT)
 
390
                                * sizeof(xfs_attr_leaf_entry_t)
 
391
                                + sizeof(xfs_attr_leaf_hdr_t)
 
392
                                                        > XFS_LBSIZE(mp)) {
 
393
                do_warn("bad attribute count %d in attr block %u, inode %llu\n",
 
394
                        (int) INT_GET(leaf->hdr.count, ARCH_CONVERT),
 
395
                                                da_bno, ino);
 
396
                return (1);
 
397
        }
 
398
 
 
399
        init_da_freemap(attr_freemap);
 
400
        (void) set_da_freemap(mp, attr_freemap, 0, stop);
 
401
        
 
402
        /* go thru each entry checking for problems */
 
403
        for (i = 0, entry = &leaf->entries[0]; 
 
404
                        i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
 
405
                                                i++, entry++) {
 
406
        
 
407
                /* check if index is within some boundary. */
 
408
                if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) {
 
409
                        do_warn("bad attribute nameidx %d in attr block %u, inode %llu\n",
 
410
                                (int)INT_GET(entry->nameidx, ARCH_CONVERT),
 
411
                                da_bno,ino);
 
412
                        clearit = 1;
 
413
                        break;
 
414
                        }
 
415
 
 
416
                if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
 
417
                        /* we are inconsistent state. get rid of us */
 
418
                        do_warn("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n",
 
419
                                i, da_bno, ino);
 
420
                        clearit = 1;
 
421
                        break;
 
422
                        }
 
423
 
 
424
                /* mark the entry used */
 
425
                start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;
 
426
                stop = start + sizeof(xfs_attr_leaf_entry_t);
 
427
                if (set_da_freemap(mp, attr_freemap, start, stop))  {
 
428
                        do_warn("attribute entry %d in attr block %u, inode %llu claims already used space\n",
 
429
                                i,da_bno,ino);
 
430
                        clearit = 1;
 
431
                        break;  /* got an overlap */
 
432
                        }
 
433
 
 
434
                if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) {
 
435
 
 
436
                        local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);      
 
437
                        if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) || 
 
438
                                        (namecheck((char *)&local->nameval[0], 
 
439
                                                INT_GET(local->namelen, ARCH_CONVERT)))) {
 
440
                                do_warn("attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n",
 
441
                                        i, da_bno, ino, (int) INT_GET(local->namelen, ARCH_CONVERT));
 
442
 
 
443
                                clearit = 1;
 
444
                                break;
 
445
                                };
 
446
 
 
447
                        /* Check on the hash value. Checking ordering of hash values
 
448
                         * is not necessary, since one wrong one clears the whole
 
449
                         * fork. If the ordering's wrong, it's caught here or 
 
450
                         * the kernel code has a bug with transaction logging
 
451
                         * or attributes itself. For paranoia reasons, let's check
 
452
                         * ordering anyway in case both the name value and the 
 
453
                         * hashvalue were wrong but matched. Unlikely, however.
 
454
                        */
 
455
                        if (INT_GET(entry->hashval, ARCH_CONVERT) != 
 
456
                                libxfs_da_hashname((char *)&local->nameval[0],
 
457
                                        INT_GET(local->namelen, ARCH_CONVERT)) ||
 
458
                                (INT_GET(entry->hashval, ARCH_CONVERT)
 
459
                                                        < last_hashval)) {
 
460
                                do_warn("bad hashvalue for attribute entry %d in attr block %u, inode %llu\n",
 
461
                                        i, da_bno, ino);
 
462
                                clearit = 1;
 
463
                                break;
 
464
                        }
 
465
 
 
466
                        /* Only check values for root security attributes */
 
467
                        if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) 
 
468
                                if (valuecheck((char *)&local->nameval[0], NULL,
 
469
                                            INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT))) {
 
470
                                        do_warn("bad security value for attribute entry %d in attr block %u, inode %llu\n",
 
471
                                                i,da_bno,ino);
 
472
                                        clearit = 1;
 
473
                                        break;
 
474
                                };
 
475
                        thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL(
 
476
                                        INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT));
 
477
 
 
478
                } else {
 
479
                        /* do the remote case */
 
480
                        remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
 
481
                        thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE(
 
482
                                        INT_GET(remotep->namelen, ARCH_CONVERT)); 
 
483
 
 
484
                        if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) || 
 
485
                                   (namecheck((char *)&remotep->name[0],
 
486
                                        INT_GET(remotep->namelen, ARCH_CONVERT))) ||
 
487
                                   (INT_GET(entry->hashval, ARCH_CONVERT)
 
488
                                                != libxfs_da_hashname(
 
489
                                        (char *)&remotep->name[0],
 
490
                                         INT_GET(remotep->namelen, ARCH_CONVERT))) ||
 
491
                                   (INT_GET(entry->hashval, ARCH_CONVERT)
 
492
                                                < last_hashval) ||
 
493
                                   (INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) {
 
494
                                do_warn("inconsistent remote attribute entry %d in attr block %u, ino %llu\n",
 
495
                                        i, da_bno, ino);
 
496
                                clearit = 1;
 
497
                                break;
 
498
                        };
 
499
 
 
500
                        if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) {
 
501
                                char*   value;
 
502
                                if ((value = malloc(INT_GET(remotep->valuelen, ARCH_CONVERT)))==NULL){
 
503
                                        do_warn("cannot malloc enough for remotevalue attribute for inode %llu\n",ino);
 
504
                                        do_warn("SKIPPING this remote attribute\n");
 
505
                                        continue;
 
506
                                }
 
507
                                if (rmtval_get(mp, ino, blkmap,
 
508
                                                INT_GET(remotep->valueblk, ARCH_CONVERT),
 
509
                                                INT_GET(remotep->valuelen, ARCH_CONVERT), value)) {
 
510
                                        do_warn("remote attribute get failed for entry %d, inode %llu\n", i,ino);
 
511
                                        clearit = 1;
 
512
                                        free(value);
 
513
                                        break;
 
514
                                }
 
515
                                if (valuecheck((char *)&remotep->name[0], value,
 
516
                                            INT_GET(remotep->namelen, ARCH_CONVERT), INT_GET(remotep->valuelen, ARCH_CONVERT))){
 
517
                                        do_warn("remote attribute value check  failed for entry %d, inode %llu\n", i, ino);
 
518
                                        clearit = 1;
 
519
                                        free(value);
 
520
                                        break;
 
521
                                }
 
522
                                free(value);
 
523
                        }
 
524
                }
 
525
 
 
526
                *current_hashval = last_hashval 
 
527
                                 = INT_GET(entry->hashval, ARCH_CONVERT);
 
528
 
 
529
                if (set_da_freemap(mp, attr_freemap, INT_GET(entry->nameidx, ARCH_CONVERT),
 
530
                                INT_GET(entry->nameidx, ARCH_CONVERT) + thissize))  {
 
531
                        do_warn("attribute entry %d in attr block %u, inode %llu claims used space\n",
 
532
                                i, da_bno, ino);
 
533
                        clearit = 1;
 
534
                        break;  /* got an overlap */
 
535
                }                       
 
536
                usedbs += thissize;
 
537
                if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb) 
 
538
                        firstb = INT_GET(entry->nameidx, ARCH_CONVERT);
 
539
 
 
540
        } /* end the loop */
 
541
 
 
542
        if (!clearit) {
 
543
                /* verify the header information is correct */
 
544
 
 
545
                /* if the holes flag is set, don't reset first_used unless it's
 
546
                 * pointing to used bytes.  we're being conservative here
 
547
                 * since the block will get compacted anyhow by the kernel. 
 
548
                 */
 
549
 
 
550
                if (  (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0
 
551
                    && firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT))
 
552
                    || INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb)  {
 
553
                        if (!no_modify)  {
 
554
                                do_warn("- resetting first used heap value from %d to %d in block %u of attribute fork of inode %llu\n",
 
555
                                        (int)INT_GET(leaf->hdr.firstused,
 
556
                                                ARCH_CONVERT), firstb,
 
557
                                                da_bno, ino);
 
558
                                INT_SET(leaf->hdr.firstused,
 
559
                                                ARCH_CONVERT, firstb);
 
560
                                *repair = 1;
 
561
                        } else  {
 
562
                                do_warn("- would reset first used value from %d to %d in block %u of attribute fork of inode %llu\n",
 
563
                                        (int)INT_GET(leaf->hdr.firstused,
 
564
                                                ARCH_CONVERT), firstb,
 
565
                                                da_bno, ino);
 
566
                        }
 
567
                }
 
568
 
 
569
                if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT))  {
 
570
                        if (!no_modify)  {
 
571
                                do_warn("- resetting usedbytes cnt from %d to %d in block %u of attribute fork of inode %llu\n",
 
572
                                        (int)INT_GET(leaf->hdr.usedbytes,
 
573
                                          ARCH_CONVERT), usedbs, da_bno, ino);
 
574
                                INT_SET(leaf->hdr.usedbytes,
 
575
                                                ARCH_CONVERT, usedbs);
 
576
                                *repair = 1;
 
577
                        } else  {
 
578
                                do_warn("- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %llu\n",
 
579
                                        (int)INT_GET(leaf->hdr.usedbytes,
 
580
                                            ARCH_CONVERT), usedbs,da_bno,ino);
 
581
                        }
 
582
                }
 
583
 
 
584
                /* there's a lot of work in process_leaf_dir_block to go thru
 
585
                * checking for holes and compacting if appropiate. I don't think
 
586
                * attributes need all that, so let's just leave the holes. If
 
587
                * we discover later that this is a good place to do compaction
 
588
                * we can add it then. 
 
589
                */
 
590
        }
 
591
        return (clearit);  /* and repair */
 
592
}
 
593
 
 
594
 
 
595
/*
 
596
 * returns 0 if the attribute fork is ok, 1 if it has to be junked.
 
597
 */
 
598
int
 
599
process_leaf_attr_level(xfs_mount_t     *mp,
 
600
                        da_bt_cursor_t  *da_cursor)
 
601
{
 
602
        int                     repair;
 
603
        xfs_attr_leafblock_t    *leaf;
 
604
        xfs_buf_t               *bp;
 
605
        xfs_ino_t               ino;
 
606
        xfs_dfsbno_t            dev_bno;
 
607
        xfs_dablk_t             da_bno;
 
608
        xfs_dablk_t             prev_bno;
 
609
        xfs_dahash_t            current_hashval = 0;
 
610
        xfs_dahash_t            greatest_hashval;
 
611
 
 
612
        da_bno = da_cursor->level[0].bno;
 
613
        ino = da_cursor->ino;
 
614
        prev_bno = 0;
 
615
 
 
616
        do {
 
617
                repair = 0;
 
618
                dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
 
619
                /*
 
620
                 * 0 is the root block and no block
 
621
                 * pointer can point to the root block of the btree
 
622
                 */
 
623
                ASSERT(da_bno != 0);
 
624
 
 
625
                if (dev_bno == NULLDFSBNO) {
 
626
                        do_warn("can't map block %u for attribute fork "
 
627
                                "for inode %llu\n", da_bno, ino);
 
628
                        goto error_out; 
 
629
                }
 
630
 
 
631
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
 
632
                                        XFS_FSB_TO_BB(mp, 1), 0);
 
633
                if (!bp) {
 
634
                        do_warn("can't read file block %u (fsbno %llu) for"
 
635
                                " attribute fork of inode %llu\n",
 
636
                                da_bno, dev_bno, ino);
 
637
                        goto error_out;
 
638
                }
 
639
 
 
640
                leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
 
641
 
 
642
                /* check magic number for leaf directory btree block */
 
643
                if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
 
644
                                                != XFS_ATTR_LEAF_MAGIC) {
 
645
                        do_warn("bad attribute leaf magic %#x for inode %llu\n",
 
646
                                 leaf->hdr.info.magic, ino);
 
647
                        libxfs_putbuf(bp);
 
648
                        goto error_out;
 
649
                }
 
650
 
 
651
                /*
 
652
                 * for each block, process the block, verify it's path,
 
653
                 * then get next block.  update cursor values along the way
 
654
                 */
 
655
                if (process_leaf_attr_block(mp, leaf, da_bno, ino,
 
656
                                da_cursor->blkmap, current_hashval,
 
657
                                &greatest_hashval, &repair))  {
 
658
                        libxfs_putbuf(bp);
 
659
                        goto error_out;
 
660
                }
 
661
 
 
662
                /*
 
663
                 * index can be set to hdr.count so match the
 
664
                 * indexes of the interior blocks -- which at the
 
665
                 * end of the block will point to 1 after the final
 
666
                 * real entry in the block
 
667
                 */
 
668
                da_cursor->level[0].hashval = greatest_hashval;
 
669
                da_cursor->level[0].bp = bp;
 
670
                da_cursor->level[0].bno = da_bno;
 
671
                da_cursor->level[0].index
 
672
                                = INT_GET(leaf->hdr.count, ARCH_CONVERT);
 
673
                da_cursor->level[0].dirty = repair; 
 
674
 
 
675
                if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno)  {
 
676
                        do_warn("bad sibling back pointer for block %u in "
 
677
                                "attribute fork for inode %llu\n", da_bno, ino);
 
678
                        libxfs_putbuf(bp);
 
679
                        goto error_out;
 
680
                }
 
681
 
 
682
                prev_bno = da_bno;
 
683
                da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
 
684
 
 
685
                if (da_bno != 0 && verify_da_path(mp, da_cursor, 0))  {
 
686
                        libxfs_putbuf(bp);
 
687
                        goto error_out;
 
688
                }
 
689
 
 
690
                current_hashval = greatest_hashval;
 
691
 
 
692
                if (repair && !no_modify) {
 
693
                        libxfs_writebuf(bp, 0);
 
694
                }
 
695
                else {
 
696
                        libxfs_putbuf(bp);
 
697
                }
 
698
        } while (da_bno != 0);
 
699
 
 
700
        if (verify_final_da_path(mp, da_cursor, 0))  {
 
701
                /*
 
702
                 * verify the final path up (right-hand-side) if still ok
 
703
                 */
 
704
                do_warn("bad hash path in attribute fork for inode %llu\n",
 
705
                        da_cursor->ino);
 
706
                goto error_out;
 
707
        }
 
708
 
 
709
        /* releases all buffers holding interior btree blocks */
 
710
        release_da_cursor(mp, da_cursor, 0);
 
711
        return(0);
 
712
 
 
713
error_out:
 
714
        /* release all buffers holding interior btree blocks */
 
715
        err_release_da_cursor(mp, da_cursor, 0);
 
716
        return(1);
 
717
}
 
718
 
 
719
 
 
720
/*
 
721
 * a node directory is a true btree  -- where the attribute fork
 
722
 * has gotten big enough that it is represented as a non-trivial (e.g.
 
723
 * has more than just a block) btree.
 
724
 *
 
725
 * Note that if we run into any problems, we will trash the attribute fork.
 
726
 * 
 
727
 * returns 0 if things are ok, 1 if bad
 
728
 * Note this code has been based off process_node_dir. 
 
729
 */
 
730
int
 
731
process_node_attr(
 
732
        xfs_mount_t     *mp,
 
733
        xfs_ino_t       ino,
 
734
        xfs_dinode_t    *dip,
 
735
        blkmap_t        *blkmap)
 
736
{
 
737
        xfs_dablk_t                     bno;
 
738
        int                             error = 0;
 
739
        da_bt_cursor_t                  da_cursor;
 
740
 
 
741
        /*
 
742
         * try again -- traverse down left-side of tree until we hit
 
743
         * the left-most leaf block setting up the btree cursor along
 
744
         * the way.  Then walk the leaf blocks left-to-right, calling
 
745
         * a parent-verification routine each time we traverse a block.
 
746
         */
 
747
        bzero(&da_cursor, sizeof(da_bt_cursor_t));
 
748
        da_cursor.active = 0;
 
749
        da_cursor.type = 0;
 
750
        da_cursor.ino = ino;
 
751
        da_cursor.dip = dip;
 
752
        da_cursor.greatest_bno = 0;
 
753
        da_cursor.blkmap = blkmap;
 
754
 
 
755
        /*
 
756
         * now process interior node. don't have any buffers held in this path.
 
757
         */
 
758
        error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
 
759
        if (error == 0) 
 
760
                return(1);  /* 0 means unsuccessful */
 
761
 
 
762
        /*
 
763
         * now pass cursor and bno into leaf-block processing routine
 
764
         * the leaf dir level routine checks the interior paths
 
765
         * up to the root including the final right-most path.
 
766
         */
 
767
        
 
768
        return (process_leaf_attr_level(mp, &da_cursor));
 
769
}
 
770
 
 
771
/*
 
772
 * Start processing for a leaf or fuller btree.
 
773
 * A leaf directory is one where the attribute fork is too big for
 
774
 * the inode  but is small enough to fit into one btree block
 
775
 * outside the inode. This code is modelled after process_leaf_dir_block.
 
776
 *
 
777
 * returns 0 if things are ok, 1 if bad (attributes needs to be junked)
 
778
 * repair is set, if anything was changed, but attributes can live thru it
 
779
 */
 
780
 
 
781
int
 
782
process_longform_attr(
 
783
        xfs_mount_t     *mp,
 
784
        xfs_ino_t       ino,
 
785
        xfs_dinode_t    *dip,
 
786
        blkmap_t        *blkmap,
 
787
        int             *repair)        /* out - 1 if something was fixed */
 
788
{
 
789
        xfs_attr_leafblock_t    *leaf;
 
790
        xfs_dfsbno_t    bno;
 
791
        xfs_buf_t       *bp;
 
792
        xfs_dahash_t    next_hashval;
 
793
        int             repairlinks = 0;
 
794
 
 
795
        *repair = 0;
 
796
 
 
797
        bno = blkmap_get(blkmap, 0);
 
798
 
 
799
        if ( bno == NULLDFSBNO ) {
 
800
                if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0  &&
 
801
                    dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS )
 
802
                        /* it's okay the kernel can handle this state */
 
803
                        return(0);
 
804
                else    {
 
805
                        do_warn("block 0 of inode %llu attribute fork"
 
806
                                " is missing\n", ino);
 
807
                        return(1);
 
808
                }
 
809
        }
 
810
        /* FIX FOR bug 653709 -- EKN */
 
811
        if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
 
812
                do_warn("agno of attribute fork of inode %llu out of "
 
813
                        "regular partition\n", ino);
 
814
                return(1);
 
815
        }
 
816
 
 
817
        bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
 
818
                                XFS_FSB_TO_BB(mp, 1), 0);
 
819
        if (!bp) {
 
820
                do_warn("can't read block 0 of inode %llu attribute fork\n",
 
821
                        ino);
 
822
                return(1);
 
823
        }
 
824
 
 
825
        /* verify leaf block */
 
826
        leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
 
827
 
 
828
        /* check sibling pointers in leaf block or root block 0 before
 
829
        * we have to release the btree block
 
830
        */
 
831
        if (   INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0
 
832
            || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0)  {
 
833
                if (!no_modify)  {
 
834
                        do_warn("clearing forw/back pointers in block 0 "
 
835
                                "for attributes in inode %llu\n", ino);
 
836
                        repairlinks = 1;
 
837
                        INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0);
 
838
                        INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0);
 
839
                } else  {
 
840
                        do_warn("would clear forw/back pointers in block 0 "
 
841
                                "for attributes in inode %llu\n", ino);
 
842
                }
 
843
        }
 
844
 
 
845
        /*
 
846
         * use magic number to tell us what type of attribute this is.
 
847
         * it's possible to have a node or leaf attribute in either an
 
848
         * extent format or btree format attribute fork.
 
849
         */
 
850
        switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
 
851
        case XFS_ATTR_LEAF_MAGIC:       /* leaf-form attribute */
 
852
                if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
 
853
                                0, &next_hashval, repair)) {
 
854
                        /* the block is bad.  lose the attribute fork. */
 
855
                        libxfs_putbuf(bp);
 
856
                        return(1); 
 
857
                }
 
858
                *repair = *repair || repairlinks; 
 
859
                break;
 
860
 
 
861
        case XFS_DA_NODE_MAGIC:         /* btree-form attribute */
 
862
                /* must do this now, to release block 0 before the traversal */
 
863
                if (repairlinks) {
 
864
                        *repair = 1;
 
865
                        libxfs_writebuf(bp, 0);
 
866
                } else 
 
867
                        libxfs_putbuf(bp);      
 
868
                return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */
 
869
        default:
 
870
                do_warn("bad attribute leaf magic # %#x for dir ino %llu\n", 
 
871
                        INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
 
872
                libxfs_putbuf(bp);
 
873
                return(1);
 
874
        }
 
875
 
 
876
        if (*repair && !no_modify) 
 
877
                libxfs_writebuf(bp, 0);
 
878
        else
 
879
                libxfs_putbuf(bp);
 
880
 
 
881
        return(0);  /* repair may be set */
 
882
}
 
883
 
 
884
 
 
885
static void
 
886
xfs_acl_get_endian(xfs_acl_t *aclp)
 
887
{
 
888
        xfs_acl_entry_t *ace, *end;
 
889
 
 
890
        INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
 
891
        end = &aclp->acl_entry[0]+aclp->acl_cnt;
 
892
        for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
 
893
                INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
 
894
                INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
 
895
                INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
 
896
        }
 
897
}
 
898
 
 
899
/*
 
900
 * returns 1 if attributes got cleared
 
901
 * and 0 if things are ok. 
 
902
 */
 
903
int
 
904
process_attributes(
 
905
        xfs_mount_t     *mp,
 
906
        xfs_ino_t       ino,
 
907
        xfs_dinode_t    *dip,
 
908
        blkmap_t        *blkmap,
 
909
        int             *repair)  /* returned if we did repair */
 
910
{
 
911
        int err;
 
912
        xfs_dinode_core_t *dinoc;
 
913
        /* REFERENCED */
 
914
        xfs_attr_shortform_t *asf;
 
915
 
 
916
        dinoc = &dip->di_core;
 
917
        asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
 
918
 
 
919
        if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) {
 
920
                ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <= XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT));
 
921
                err = process_shortform_attr(ino, dip, repair);
 
922
        } else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS ||
 
923
                   dinoc->di_aformat == XFS_DINODE_FMT_BTREE)  {
 
924
                        err = process_longform_attr(mp, ino, dip, blkmap,
 
925
                                repair);
 
926
                        /* if err, convert this to shortform and clear it */
 
927
                        /* if repair and no error, it's taken care of */
 
928
        } else  {
 
929
                do_warn("illegal attribute format %d, ino %llu\n",
 
930
                        dinoc->di_aformat, ino);
 
931
                err = 1; 
 
932
        }
 
933
        return (err);  /* and repair */
 
934
}
 
935
 
 
936
/* 
 
937
 * Validate an ACL
 
938
 */
 
939
static int
 
940
xfs_acl_valid(xfs_acl_t *aclp)
 
941
{
 
942
        xfs_acl_entry_t *entry, *e;
 
943
        int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
 
944
        int i, j;
 
945
 
 
946
        if (aclp == NULL)
 
947
                goto acl_invalid;
 
948
 
 
949
        xfs_acl_get_endian(aclp);
 
950
 
 
951
        if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
 
952
                goto acl_invalid;
 
953
 
 
954
        for (i = 0; i < aclp->acl_cnt; i++) {
 
955
                entry = &aclp->acl_entry[i];
 
956
                switch (entry->ae_tag) {
 
957
                        case ACL_USER_OBJ:
 
958
                                if (user++)
 
959
                                        goto acl_invalid;
 
960
                                break;
 
961
                        case ACL_GROUP_OBJ:
 
962
                                if (group++)
 
963
                                        goto acl_invalid;
 
964
                                break;
 
965
                        case ACL_OTHER:
 
966
                                if (other++)
 
967
                                        goto acl_invalid;
 
968
                                break;
 
969
                        case ACL_USER:
 
970
                        case ACL_GROUP:
 
971
                                for (j = i + 1; j < aclp->acl_cnt; j++) {
 
972
                                        e = &aclp->acl_entry[j];
 
973
                                        if (e->ae_id == entry->ae_id &&
 
974
                                            e->ae_tag == entry->ae_tag)
 
975
                                                goto acl_invalid;
 
976
                                }
 
977
                                mask_required++;
 
978
                                break;
 
979
                        case ACL_MASK:
 
980
                                if (mask++)
 
981
                                        goto acl_invalid;
 
982
                                break;
 
983
                        default:
 
984
                                goto acl_invalid;
 
985
                }
 
986
        }
 
987
        if (!user || !group || !other || (mask_required && !mask))
 
988
                goto acl_invalid;
 
989
        else
 
990
                return 0;
 
991
acl_invalid:
 
992
        errno = EINVAL;
 
993
        return (-1);
 
994
}
 
995
 
 
996
/*
 
997
 * Check a category or division set to ensure that all values are in
 
998
 * ascending order and each division or category appears only once.
 
999
 */
 
1000
static int
 
1001
__check_setvalue(const unsigned short *list, unsigned short count)
 
1002
{
 
1003
        unsigned short i;
 
1004
 
 
1005
        for (i = 1; i < count ; i++)
 
1006
                if (list[i] <= list[i-1])
 
1007
                        return -1;
 
1008
        return 0;
 
1009
}
 
1010
 
 
1011
/*
 
1012
 * xfs_mac_valid(lp)
 
1013
 * Check the validity of a MAC label.
 
1014
 */
 
1015
static int
 
1016
xfs_mac_valid(xfs_mac_label_t *lp)
 
1017
{
 
1018
        if (lp == NULL)
 
1019
                return (0);
 
1020
 
 
1021
        /*
 
1022
         * if the total category set and division set is greater than 250
 
1023
         * report error
 
1024
         */
 
1025
        if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
 
1026
                return(0);
 
1027
 
 
1028
        /*
 
1029
         * check whether the msentype value is valid, and do they have
 
1030
         * appropriate level, category association.
 
1031
         */
 
1032
        switch (lp->ml_msen_type) {
 
1033
                case MSEN_ADMIN_LABEL:
 
1034
                case MSEN_EQUAL_LABEL:
 
1035
                case MSEN_HIGH_LABEL:
 
1036
                case MSEN_MLD_HIGH_LABEL:
 
1037
                case MSEN_LOW_LABEL:
 
1038
                case MSEN_MLD_LOW_LABEL:
 
1039
                        if (lp->ml_level != 0 || lp->ml_catcount > 0 )
 
1040
                                return (0);
 
1041
                        break;
 
1042
                case MSEN_TCSEC_LABEL:
 
1043
                case MSEN_MLD_LABEL:
 
1044
                        if (lp->ml_catcount > 0 &&
 
1045
                            __check_setvalue(lp->ml_list,
 
1046
                                             lp->ml_catcount) == -1)
 
1047
                                return (0);
 
1048
                        break;
 
1049
                case MSEN_UNKNOWN_LABEL:
 
1050
                default:
 
1051
                        return (0);
 
1052
        }
 
1053
 
 
1054
        /*
 
1055
         * check whether the minttype value is valid, and do they have
 
1056
         * appropriate grade, division association.
 
1057
         */
 
1058
        switch (lp->ml_mint_type) {
 
1059
                case MINT_BIBA_LABEL:
 
1060
                        if (lp->ml_divcount > 0 &&
 
1061
                            __check_setvalue(lp->ml_list + lp->ml_catcount,
 
1062
                                             lp->ml_divcount) == -1)
 
1063
                                return(0);
 
1064
                        break;
 
1065
                case MINT_EQUAL_LABEL:
 
1066
                case MINT_HIGH_LABEL:
 
1067
                case MINT_LOW_LABEL:
 
1068
                        if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
 
1069
                                return(0);
 
1070
                        break;
 
1071
                default:
 
1072
                        return(0);
 
1073
        }
 
1074
 
 
1075
        return (1);
 
1076
}