Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | #include <afsconfig.h> | |
11 | #include <afs/param.h> | |
12 | #include <afs/stds.h> | |
13 | ||
14 | #include <roken.h> | |
15 | ||
16 | /* | |
17 | * (3) Define a structure, idused, instead of an | |
18 | * array of long integers, idmap, to count group | |
19 | * memberships. These structures are on a linked | |
20 | * list, with each structure containing IDCOUNT | |
21 | * slots for id's. | |
22 | * (4) Add new functions to processs the structure | |
23 | * described above: | |
24 | * zeromap(), idcount(), inccount(). | |
25 | * (5) Add code, primarily in WalkNextChain(): | |
26 | * 1. Test id's, allowing groups within groups. | |
27 | * 2. Count the membership list for supergroups, | |
28 | * and follow the continuation chain for | |
29 | * supergroups. | |
30 | * (6) Add fprintf statements for various error | |
31 | * conditions. | |
32 | */ | |
33 | ||
34 | ||
35 | #ifdef AFS_NT40_ENV | |
36 | #include <WINNT/afsevent.h> | |
37 | #else | |
38 | #include <sys/file.h> | |
39 | #endif | |
40 | ||
41 | #include <afs/cellconfig.h> | |
42 | #include <afs/afsutil.h> | |
43 | #include <ubik.h> | |
44 | #include <afs/cmd.h> | |
45 | #include <afs/com_err.h> | |
46 | ||
47 | #include "ptint.h" | |
48 | #include "pterror.h" | |
49 | #include "ptserver.h" | |
50 | #include "ptuser.h" | |
51 | #include "display.h" | |
52 | ||
53 | struct prheader cheader; | |
54 | int fd; | |
55 | const char *pr_dbaseName; | |
56 | char *whoami = "db_verify"; | |
57 | #define UBIK_HEADERSIZE 64 | |
58 | ||
59 | afs_int32 | |
60 | printheader(struct prheader *h) | |
61 | { | |
62 | printf("Version = %d\n", ntohl(h->version)); | |
63 | printf("Header Size = %d\n", ntohl(h->headerSize)); | |
64 | printf("Free Ptr = 0x%x\n", ntohl(h->freePtr)); | |
65 | printf("EOF Ptr = 0x%x\n", ntohl(h->eofPtr)); | |
66 | printf("Max Group ID = %d\n", ntohl(h->maxGroup)); | |
67 | printf("Max User ID = %d\n", ntohl(h->maxID)); | |
68 | printf("Max Foreign ID = %d\n", ntohl(h->maxForeign)); | |
69 | /* printf("Max Sub/Super ID = %d\n", ntohl(h->maxInst)); */ | |
70 | printf("Orphaned groups = %d\n", ntohl(h->orphan)); | |
71 | printf("User Count = %d\n", ntohl(h->usercount)); | |
72 | printf("Group Count = %d\n", ntohl(h->groupcount)); | |
73 | /* printf("Foreign Count = %d\n", ntohl(h->foreigncount)); NYI */ | |
74 | /* printf("Sub/super Count = %d\n", ntohl(h->instcount)); NYI */ | |
75 | printf("Name Hash = %d buckets\n", HASHSIZE); | |
76 | printf("ID Hash = %d buckets\n", HASHSIZE); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | static afs_int32 | |
81 | pr_Read(afs_int32 pos, void *buff, afs_int32 len) | |
82 | { | |
83 | afs_int32 code; | |
84 | ||
85 | code = lseek(fd, UBIK_HEADERSIZE + pos, 0); | |
86 | if (code == -1) | |
87 | return errno; | |
88 | ||
89 | code = read(fd, buff, len); | |
90 | if (code != len) | |
91 | return -1; | |
92 | if (code == -1) | |
93 | return errno; | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | /* InitDB () | |
99 | * Initializes the a transaction on the database and reads the header into | |
100 | * the static variable cheader. If successful it returns a read-locked | |
101 | * transaction. If ubik reports that cached database info should be up to date | |
102 | * the cheader structure is not re-read from the ubik. | |
103 | */ | |
104 | ||
105 | afs_int32 | |
106 | ReadHeader(void) | |
107 | { | |
108 | afs_int32 code; | |
109 | ||
110 | code = pr_Read(0, (char *)&cheader, sizeof(cheader)); | |
111 | if (code) { | |
112 | afs_com_err(whoami, code, "couldn't read header"); | |
113 | return code; | |
114 | } | |
115 | /* Check and see if database exists and is approximately OK. */ | |
116 | if (ntohl(cheader.headerSize) != sizeof(cheader) | |
117 | || ntohl(cheader.eofPtr) == 0) { | |
118 | if (code) | |
119 | return code; | |
120 | afs_com_err(whoami, PRDBBAD, "header is bad"); | |
121 | return PRDBBAD; | |
122 | } | |
123 | return 0; | |
124 | } | |
125 | ||
126 | static afs_int32 | |
127 | IDHash(afs_int32 x) | |
128 | { | |
129 | /* returns hash bucket for x */ | |
130 | return ((abs(x)) % HASHSIZE); | |
131 | } | |
132 | ||
133 | static afs_int32 | |
134 | NameHash(char *aname) | |
135 | { | |
136 | /* returns hash bucket for aname */ | |
137 | unsigned int hash = 0; | |
138 | int i; | |
139 | /* stolen directly from the HashString function in the vol package */ | |
140 | for (i = strlen(aname), aname += i - 1; i--; aname--) | |
141 | hash = (hash * 31) + (*(unsigned char *)aname - 31); | |
142 | return (hash % HASHSIZE); | |
143 | } | |
144 | ||
145 | #define MAP_NAMEHASH 1 | |
146 | #define MAP_IDHASH 2 | |
147 | #define MAP_HASHES (MAP_NAMEHASH | MAP_IDHASH) | |
148 | #define MAP_CONT 4 | |
149 | #define MAP_FREE 8 | |
150 | #define MAP_OWNED 0x10 | |
151 | #define MAP_RECREATE 0x20 | |
152 | ||
153 | struct misc_data { | |
154 | int nEntries; /* number of database entries */ | |
155 | int anon; /* found anonymous Id */ | |
156 | afs_int32 maxId; /* user */ | |
157 | afs_int32 minId; /* group */ | |
158 | afs_int32 maxForId; /* foreign user id */ | |
159 | #if defined(SUPERGROUPS) | |
160 | #define IDCOUNT 512 | |
161 | struct idused { | |
162 | int idstart; | |
163 | afs_int32 idcount[IDCOUNT]; | |
164 | struct idused *idnext; | |
165 | } *idmap; | |
166 | #else | |
167 | int idRange; /* number of ids in map */ | |
168 | afs_int32 *idmap; /* map of all id's: midId is origin */ | |
169 | #endif /* SUPERGROUPS */ | |
170 | int nusers; /* counts of each type */ | |
171 | int ngroups; | |
172 | int nforeigns; | |
173 | int ninsts; | |
174 | int ncells; | |
175 | int maxOwnerLength; /* longest owner chain */ | |
176 | int maxContLength; /* longest chain of cont. blks */ | |
177 | int orphanLength; /* length of orphan list */ | |
178 | int freeLength; /* length of free list */ | |
179 | int verbose; | |
180 | int listuheader; | |
181 | int listpheader; | |
182 | int listentries; | |
183 | FILE *recreate; /* stream for recreate instructions */ | |
184 | }; | |
185 | ||
186 | #if defined(SUPERGROUPS) | |
187 | void zeromap(struct idused *idmap); | |
188 | void inccount(struct idused **idmapp, int id); | |
189 | int idcount(struct idused **idmapp, int id); | |
190 | #endif | |
191 | ||
192 | int | |
193 | readUbikHeader(struct misc_data *misc) | |
194 | { | |
195 | int offset, r; | |
196 | struct ubik_hdr uheader; | |
197 | ||
198 | offset = lseek(fd, 0, 0); | |
199 | if (offset != 0) { | |
200 | printf("error: lseek to 0 failed: %d %d\n", offset, errno); | |
201 | return (-1); | |
202 | } | |
203 | ||
204 | /* now read the info */ | |
205 | r = read(fd, &uheader, sizeof(uheader)); | |
206 | if (r != sizeof(uheader)) { | |
207 | printf("error: read of %" AFS_SIZET_FMT " bytes failed: %d %d\n", | |
208 | sizeof(uheader), r, errno); | |
209 | return (-1); | |
210 | } | |
211 | ||
212 | uheader.magic = ntohl(uheader.magic); | |
213 | uheader.size = ntohs(uheader.size); | |
214 | uheader.version.epoch = ntohl(uheader.version.epoch); | |
215 | uheader.version.counter = ntohl(uheader.version.counter); | |
216 | ||
217 | if (misc->listuheader) { | |
218 | printf("Ubik Header\n"); | |
219 | printf(" Magic = 0x%x\n", uheader.magic); | |
220 | printf(" Size = %u\n", uheader.size); | |
221 | printf(" Version.epoch = %u\n", uheader.version.epoch); | |
222 | printf(" Version.counter = %u\n", uheader.version.counter); | |
223 | } | |
224 | ||
225 | if (uheader.size != UBIK_HEADERSIZE) | |
226 | printf("Ubik header size is %u (should be %u)\n", uheader.size, | |
227 | UBIK_HEADERSIZE); | |
228 | if (uheader.magic != UBIK_MAGIC) | |
229 | printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, | |
230 | UBIK_MAGIC); | |
231 | ||
232 | return (0); | |
233 | } | |
234 | ||
235 | afs_int32 | |
236 | ConvertDiskAddress(afs_uint32 ea, int *eiP) | |
237 | { | |
238 | int i; | |
239 | ||
240 | *eiP = -1; | |
241 | ||
242 | if (ea < sizeof(cheader)) | |
243 | return PRDBADDR; | |
244 | if (ea >= ntohl(cheader.eofPtr)) | |
245 | return PRDBADDR; | |
246 | ea -= sizeof(cheader); | |
247 | i = ea / sizeof(struct prentry); | |
248 | if (i * sizeof(struct prentry) != ea) | |
249 | return PRDBADDR; | |
250 | /* if ((i < 0) || (i >= misc->nEntries)) return PRDBADDR; */ | |
251 | *eiP = i; | |
252 | return 0; | |
253 | } | |
254 | ||
255 | int | |
256 | PrintEntryError(struct misc_data *misc, afs_int32 ea, struct prentry *e, int indent) | |
257 | { | |
258 | ||
259 | pr_PrintEntry(stderr, /*net order */ 0, ea, e, indent); | |
260 | return 0; | |
261 | } | |
262 | ||
263 | int | |
264 | PrintContError(struct misc_data *misc, afs_int32 ea, struct contentry *c, int indent) | |
265 | { | |
266 | pr_PrintContEntry(stderr, /*net order */ 0, ea, c, indent); | |
267 | return 0; | |
268 | } | |
269 | ||
270 | afs_int32 | |
271 | WalkHashTable(afs_int32 hashtable[], /* hash table to walk */ | |
272 | int hashType, /* hash function to use */ | |
273 | char map[], /* one byte per db entry */ | |
274 | struct misc_data *misc) /* stuff to keep track of */ | |
275 | { | |
276 | afs_int32 code; | |
277 | int hi; /* index in hash table */ | |
278 | afs_int32 ea; /* entry's db addr */ | |
279 | int ei; /* entry's index */ | |
280 | char bit; /* bits to check for in map */ | |
281 | struct prentry e; | |
282 | afs_int32 next_ea; | |
283 | afs_int32 id; | |
284 | afs_int32 flags; | |
285 | afs_int32 hash; | |
286 | ||
287 | bit = hashType; | |
288 | ||
289 | for (hi = 0; hi < HASHSIZE; hi++) { | |
290 | ea = 0; | |
291 | next_ea = ntohl(hashtable[hi]); | |
292 | while (next_ea) { | |
293 | code = ConvertDiskAddress(next_ea, &ei); | |
294 | if (code) { | |
295 | fprintf(stderr, "Bad chain address %d\n", next_ea); | |
296 | if (ea) { | |
297 | fprintf(stderr, "Last entry in chain:\n"); | |
298 | if (PrintEntryError(misc, ea, &e, 2)) | |
299 | return PRDBBAD; | |
300 | } | |
301 | fprintf(stderr, "Skipping remainder of hash bucket %d\n", hi); | |
302 | break; | |
303 | } | |
304 | ea = next_ea; | |
305 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
306 | if (code) | |
307 | return code; | |
308 | ||
309 | id = ntohl(e.id); | |
310 | ||
311 | if (((e.flags & htonl((PRGRP | PRINST))) == 0) | |
312 | && (strchr(e.name, '@'))) { | |
313 | /* Foreign user */ | |
314 | if (id > misc->maxForId) | |
315 | misc->maxForId = id; | |
316 | } else { | |
317 | if (id == ANONYMOUSID) | |
318 | misc->anon++; | |
319 | else if (id > misc->maxId) | |
320 | misc->maxId = id; | |
321 | if (id < misc->minId) | |
322 | misc->minId = id; | |
323 | } | |
324 | ||
325 | switch (hashType) { | |
326 | case MAP_NAMEHASH: | |
327 | next_ea = ntohl(e.nextName); | |
328 | hash = NameHash(e.name); | |
329 | break; | |
330 | case MAP_IDHASH: | |
331 | next_ea = ntohl(e.nextID); | |
332 | hash = IDHash(id); | |
333 | break; | |
334 | default: | |
335 | fprintf(stderr, "unknown hash table type %d\n", hashType); | |
336 | return PRBADARG; | |
337 | } | |
338 | ||
339 | if (map[ei] & bit) { | |
340 | fprintf(stderr, | |
341 | "Entry found twice in hash table: bucket %d\n", hi); | |
342 | if (hi != hash) | |
343 | fprintf(stderr, "also in wrong bucket: should be in %d\n", | |
344 | hash); | |
345 | if (PrintEntryError(misc, ea, &e, 2)) | |
346 | return PRDBBAD; | |
347 | break; | |
348 | } | |
349 | map[ei] |= bit; | |
350 | ||
351 | flags = ntohl(e.flags); | |
352 | switch (flags & PRTYPE) { | |
353 | case PRFREE: | |
354 | fprintf(stderr, "ENTRY IS FREE"); | |
355 | goto abort; | |
356 | case PRCONT: | |
357 | fprintf(stderr, "ENTRY IS CONTINUATION"); | |
358 | goto abort; | |
359 | case PRGRP: | |
360 | case PRUSER: | |
361 | break; | |
362 | case PRCELL: | |
363 | case PRFOREIGN: | |
364 | case PRINST: | |
365 | fprintf(stderr, "ENTRY IS unexpected type (flags=0x%x)\n", | |
366 | flags); | |
367 | break; | |
368 | default: | |
369 | fprintf(stderr, "ENTRY IS OF unknown type (flags=0x%x)\n", | |
370 | flags); | |
371 | goto abort; | |
372 | } | |
373 | ||
374 | if (hash != hi) { | |
375 | fprintf(stderr, "entry hashed in bucket %d should be %d\n", | |
376 | hi, hash); | |
377 | abort: | |
378 | if (PrintEntryError(misc, ea, &e, 2)) | |
379 | return PRDBBAD; | |
380 | continue; | |
381 | } | |
382 | } | |
383 | } | |
384 | return 0; | |
385 | } | |
386 | ||
387 | afs_int32 | |
388 | WalkNextChain(char map[], /* one byte per db entry */ | |
389 | struct misc_data *misc, /* stuff to keep track of */ | |
390 | afs_int32 ea, struct prentry *e) | |
391 | { | |
392 | afs_int32 head; | |
393 | int bit; | |
394 | afs_int32 code; | |
395 | struct contentry c; /* continuation entry */ | |
396 | afs_int32 na; /* next thread */ | |
397 | int ni; | |
398 | afs_int32 eid = 0; | |
399 | int count = 0; /* number of members, set to > 9999 if */ | |
400 | /* list ends early */ | |
401 | int i; | |
402 | int noErrors = 1; | |
403 | int length; /* length of chain */ | |
404 | #if defined(SUPERGROUPS) | |
405 | int sgcount = 0; /* number of sgentrys */ | |
406 | afs_int32 sghead; | |
407 | #define g (((struct prentryg *)e)) | |
408 | #endif | |
409 | ||
410 | if (e) { | |
411 | head = ntohl(e->next); | |
412 | eid = ntohl(e->id); | |
413 | bit = MAP_CONT; | |
414 | #if defined(SUPERGROUPS) | |
415 | sghead = ntohl(g->next); | |
416 | #endif | |
417 | for (i = 0; i < PRSIZE; i++) { | |
418 | afs_int32 id = ntohl(e->entries[i]); | |
419 | if (id == PRBADID) | |
420 | continue; | |
421 | else if (id) { | |
422 | int eid_s, id_s; | |
423 | count++; | |
424 | /* in case the ids are large, convert to pure sign. */ | |
425 | if (id > 0) | |
426 | id_s = 1; | |
427 | else | |
428 | id_s = -1; | |
429 | if (eid > 0) | |
430 | eid_s = 1; | |
431 | else | |
432 | eid_s = -1; | |
433 | #if defined(SUPERGROUPS) | |
434 | if (id_s > 0 && eid_s > 0) { | |
435 | fprintf(stderr, | |
436 | "User can't be member of user in membership list\n"); | |
437 | if (PrintEntryError(misc, ea, e, 2)) | |
438 | return PRDBBAD; | |
439 | noErrors = 0; | |
440 | } | |
441 | #else | |
442 | if (id_s * eid_s > 0) { /* sign should be different */ | |
443 | fprintf(stderr, | |
444 | "Bad user/group dicotomy in membership list\n"); | |
445 | if (PrintEntryError(misc, ea, e, 2)) | |
446 | return PRDBBAD; | |
447 | noErrors = 0; | |
448 | } | |
449 | #endif /* SUPERGROUPS */ | |
450 | /* count each user as a group, and each group a user is in */ | |
451 | #if defined(SUPERGROUPS) | |
452 | if (!(id < 0 && eid < 0) && (id != ANONYMOUSID)) | |
453 | inccount(&misc->idmap, id); | |
454 | #else | |
455 | if ((id >= misc->minId) && (id <= misc->maxId) | |
456 | && (id != ANONYMOUSID)) | |
457 | misc->idmap[id - misc->minId]++; | |
458 | #endif /* SUPERGROUPS */ | |
459 | } else if (head) | |
460 | count = 9999; | |
461 | else | |
462 | break; | |
463 | } | |
464 | #if defined(SUPERGROUPS) | |
465 | sghead = ntohl(g->nextsg); | |
466 | if ((e->flags & htonl(PRGRP))) { | |
467 | for (i = 0; i < SGSIZE; ++i) { | |
468 | afs_int32 id = ntohl(g->supergroup[i]); | |
469 | if (id == PRBADID) | |
470 | continue; | |
471 | else if (id) { | |
472 | if (id > 0) { | |
473 | fprintf(stderr, | |
474 | "User can't be member of supergroup list\n"); | |
475 | if (PrintEntryError(misc, ea, e, 2)) | |
476 | return PRDBBAD; | |
477 | noErrors = 0; | |
478 | } | |
479 | sgcount++; | |
480 | inccount(&misc->idmap, id); | |
481 | } | |
482 | } | |
483 | } | |
484 | #endif /* SUPERGROUPS */ | |
485 | } else { | |
486 | head = ntohl(cheader.freePtr); | |
487 | #if defined(SUPERGROUPS) | |
488 | sghead = 0; | |
489 | #endif | |
490 | bit = MAP_FREE; | |
491 | } | |
492 | ||
493 | #if defined(SUPERGROUPS) | |
494 | length = 0; | |
495 | for (na = sghead; na; na = ntohl(c.next)) { | |
496 | code = ConvertDiskAddress(na, &ni); | |
497 | if (code) { | |
498 | fprintf(stderr, "Bad SGcontinuation ptr %d", na); | |
499 | if (PrintEntryError(misc, ea, e, 2)) | |
500 | return PRDBBAD; | |
501 | if (na != sghead) { | |
502 | fprintf(stderr, "last block: \n"); | |
503 | if (PrintContError(misc, na, &c, 4)) | |
504 | return PRDBBAD; | |
505 | } | |
506 | return 0; | |
507 | } | |
508 | code = pr_Read(na, (char *)&c, sizeof(c)); | |
509 | if (code) | |
510 | return code; | |
511 | length++; | |
512 | ||
513 | if (map[ni]) { | |
514 | fprintf(stderr, "Continuation entry reused\n"); | |
515 | if (PrintEntryError(misc, ea, e, 2)) | |
516 | return PRDBBAD; | |
517 | if (PrintContError(misc, na, &c, 4)) | |
518 | return PRDBBAD; | |
519 | noErrors = 0; | |
520 | break; | |
521 | } | |
522 | map[ni] |= bit; | |
523 | if ((ntohl(c.id) != eid)) { | |
524 | fprintf(stderr, "Continuation id mismatch\n"); | |
525 | if (PrintEntryError(misc, ea, e, 2)) | |
526 | return PRDBBAD; | |
527 | if (PrintContError(misc, na, &c, 4)) | |
528 | return PRDBBAD; | |
529 | noErrors = 0; | |
530 | continue; | |
531 | } | |
532 | ||
533 | /* update membership count */ | |
534 | for (i = 0; i < COSIZE; i++) { | |
535 | afs_int32 id = ntohl(c.entries[i]); | |
536 | if (id == PRBADID) | |
537 | continue; | |
538 | else if (id) { | |
539 | int id_s; | |
540 | sgcount++; | |
541 | /* in case the ids are large, convert to pure sign. */ | |
542 | if (id > 0) | |
543 | id_s = 1; | |
544 | else | |
545 | id_s = -1; | |
546 | if (id_s > 0) { | |
547 | fprintf(stderr, | |
548 | "User can't be member of supergroup list\n"); | |
549 | if (PrintEntryError(misc, ea, e, 2)) | |
550 | return PRDBBAD; | |
551 | if (PrintContError(misc, na, &c, 4)) | |
552 | return PRDBBAD; | |
553 | noErrors = 0; | |
554 | } | |
555 | /* count each user as a group, and each group a user is in */ | |
556 | if ((id != ANONYMOUSID)) | |
557 | inccount(&misc->idmap, id); | |
558 | } else if (c.next) | |
559 | count = 9999; | |
560 | else | |
561 | break; | |
562 | } | |
563 | } | |
564 | if (length > misc->maxContLength) | |
565 | misc->maxContLength = length; | |
566 | #endif /* SUPERGROUPS */ | |
567 | length = 0; | |
568 | for (na = head; na; na = ntohl(c.next)) { | |
569 | code = ConvertDiskAddress(na, &ni); | |
570 | if (code) { | |
571 | fprintf(stderr, "Bad continuation ptr %d", na); | |
572 | if (e == 0) | |
573 | fprintf(stderr, "walking free list"); | |
574 | else if (PrintEntryError(misc, ea, e, 2)) | |
575 | return PRDBBAD; | |
576 | if (na != head) { | |
577 | fprintf(stderr, "last block: \n"); | |
578 | if (PrintContError(misc, na, &c, 4)) | |
579 | return PRDBBAD; | |
580 | } | |
581 | return 0; | |
582 | } | |
583 | code = pr_Read(na, (char *)&c, sizeof(c)); | |
584 | if (code) | |
585 | return code; | |
586 | length++; | |
587 | ||
588 | if (map[ni]) { | |
589 | fprintf(stderr, "Continuation entry reused\n"); | |
590 | if (e == 0) | |
591 | fprintf(stderr, "walking free list"); | |
592 | else if (PrintEntryError(misc, ea, e, 2)) | |
593 | return PRDBBAD; | |
594 | if (PrintContError(misc, na, &c, 4)) | |
595 | return PRDBBAD; | |
596 | noErrors = 0; | |
597 | break; | |
598 | } | |
599 | map[ni] |= bit; | |
600 | if (e && (ntohl(c.id) != eid)) { | |
601 | fprintf(stderr, "Continuation id mismatch\n"); | |
602 | if (e == 0) | |
603 | fprintf(stderr, "walking free list"); | |
604 | else if (PrintEntryError(misc, ea, e, 2)) | |
605 | return PRDBBAD; | |
606 | if (PrintContError(misc, na, &c, 4)) | |
607 | return PRDBBAD; | |
608 | noErrors = 0; | |
609 | continue; | |
610 | } | |
611 | ||
612 | /* update membership count */ | |
613 | if (e) | |
614 | for (i = 0; i < COSIZE; i++) { | |
615 | afs_int32 id = ntohl(c.entries[i]); | |
616 | if (id == PRBADID) | |
617 | continue; | |
618 | else if (id) { | |
619 | int eid_s, id_s; | |
620 | count++; | |
621 | /* in case the ids are large, convert to pure sign. */ | |
622 | if (id > 0) | |
623 | id_s = 1; | |
624 | else | |
625 | id_s = -1; | |
626 | if (eid > 0) | |
627 | eid_s = 1; | |
628 | else | |
629 | eid_s = -1; | |
630 | #if defined(SUPERGROUPS) | |
631 | if (id_s > 0 && eid_s > 0) { | |
632 | fprintf(stderr, | |
633 | "User can't be member of user in membership list\n"); | |
634 | if (PrintEntryError(misc, ea, e, 2)) | |
635 | return PRDBBAD; | |
636 | if (PrintContError(misc, na, &c, 4)) | |
637 | return PRDBBAD; | |
638 | noErrors = 0; | |
639 | } | |
640 | #else | |
641 | if (id_s * eid_s > 0) { /* sign should be different */ | |
642 | fprintf(stderr, | |
643 | "Bad user/group dicotomy in membership list\n"); | |
644 | if (PrintEntryError(misc, ea, e, 2)) | |
645 | return PRDBBAD; | |
646 | if (PrintContError(misc, na, &c, 4)) | |
647 | return PRDBBAD; | |
648 | noErrors = 0; | |
649 | } | |
650 | #endif /* SUPERGROUPS */ | |
651 | /* count each user as a group, and each group a user is in */ | |
652 | #if defined(SUPERGROUPS) | |
653 | if (!(id < 0 && eid < 0) && (id != ANONYMOUSID)) | |
654 | inccount(&misc->idmap, id); | |
655 | #else | |
656 | if ((id >= misc->minId) && (id <= misc->maxId) | |
657 | && (id != ANONYMOUSID)) | |
658 | misc->idmap[id - misc->minId]++; | |
659 | #endif /* SUPERGROUPS */ | |
660 | } else if (c.next) | |
661 | count = 9999; | |
662 | else | |
663 | break; | |
664 | } | |
665 | } | |
666 | if (e && noErrors && (count != ntohl(e->count))) { | |
667 | #if defined(SUPERGROUPS) | |
668 | if (count >= 9999) | |
669 | fprintf(stderr, "Membership list ends early\n"); | |
670 | #else | |
671 | if (count > 9999) | |
672 | fprintf(stderr, "Membership list ends early\n"); | |
673 | #endif /* SUPERGROUPS */ | |
674 | fprintf(stderr, "Count was %d should be %d\n", count, | |
675 | ntohl(e->count)); | |
676 | if (PrintEntryError(misc, ea, e, 2)) | |
677 | return PRDBBAD; | |
678 | #if defined(SUPERGROUPS) | |
679 | noErrors = 0; | |
680 | } | |
681 | if (e && (e->flags & htonl(PRGRP)) && (sgcount != ntohl(g->countsg))) { | |
682 | fprintf(stderr, "SGCount was %d should be %d\n", sgcount, | |
683 | ntohl(g->countsg)); | |
684 | if (PrintEntryError(misc, ea, e, 2)) | |
685 | return PRDBBAD; | |
686 | #endif | |
687 | } | |
688 | ||
689 | if (e) { | |
690 | if (length > misc->maxContLength) | |
691 | misc->maxContLength = length; | |
692 | } else | |
693 | misc->freeLength = length; | |
694 | ||
695 | return 0; | |
696 | #if defined(SUPERGROUPS) | |
697 | #undef g | |
698 | #endif | |
699 | } | |
700 | ||
701 | afs_int32 | |
702 | WalkOwnedChain(char map[], /* one byte per db entry */ | |
703 | struct misc_data *misc, /* stuff to keep track of */ | |
704 | afs_int32 ea, struct prentry *e) | |
705 | { | |
706 | afs_int32 head; | |
707 | afs_int32 code; | |
708 | struct prentry te; /* next entry in owner chain */ | |
709 | afs_int32 na; /* next thread */ | |
710 | int ni; | |
711 | afs_int32 eid = 0; | |
712 | int length; /* length of chain */ | |
713 | ||
714 | if (e) { | |
715 | head = ntohl(e->owned); | |
716 | eid = ntohl(e->id); | |
717 | } else | |
718 | head = ntohl(cheader.orphan); | |
719 | ||
720 | length = 0; | |
721 | for (na = head; na; na = ntohl(te.nextOwned)) { | |
722 | code = ConvertDiskAddress(na, &ni); | |
723 | if (code) { | |
724 | fprintf(stderr, "Bad owned list ptr %d", na); | |
725 | if (e == 0) | |
726 | fprintf(stderr, "walking orphan list"); | |
727 | else if (PrintEntryError(misc, ea, e, 2)) | |
728 | return PRDBBAD; | |
729 | if (na != head) { | |
730 | fprintf(stderr, "last block: \n"); | |
731 | if (PrintEntryError(misc, na, &te, 4)) | |
732 | return PRDBBAD; | |
733 | } | |
734 | return 0; | |
735 | } | |
736 | code = pr_Read(na, (char *)&te, sizeof(te)); | |
737 | if (code) | |
738 | return code; | |
739 | length++; | |
740 | ||
741 | if ((ntohl(te.flags) & PRTYPE) == PRCONT) { | |
742 | fprintf(stderr, "Continuation entry found on owner chain\n"); | |
743 | if (e == 0) | |
744 | fprintf(stderr, "walking orphan list"); | |
745 | else if (PrintEntryError(misc, ea, e, 2)) | |
746 | return PRDBBAD; | |
747 | if (PrintEntryError(misc, na, &te, 4)) | |
748 | return PRDBBAD; | |
749 | break; | |
750 | } | |
751 | if (map[ni] & MAP_OWNED) { | |
752 | fprintf(stderr, "Entry on multiple owner chains\n"); | |
753 | if (e == 0) | |
754 | fprintf(stderr, "walking orphan list"); | |
755 | else if (PrintEntryError(misc, ea, e, 2)) | |
756 | return PRDBBAD; | |
757 | if (PrintEntryError(misc, na, &te, 4)) | |
758 | return PRDBBAD; | |
759 | break; | |
760 | } | |
761 | map[ni] |= MAP_OWNED; | |
762 | if ((map[ni] & MAP_HASHES) != MAP_HASHES) { | |
763 | fprintf(stderr, "Owned entry not hashed properly\n"); | |
764 | abort: | |
765 | if (e == 0) | |
766 | fprintf(stderr, "walking orphan list"); | |
767 | else if (PrintEntryError(misc, ea, e, 2)) | |
768 | return PRDBBAD; | |
769 | if (PrintEntryError(misc, na, &te, 4)) | |
770 | return PRDBBAD; | |
771 | continue; | |
772 | } | |
773 | if (e) { | |
774 | if (ntohl(te.owner) != eid) { | |
775 | fprintf(stderr, "Owner id mismatch\n"); | |
776 | goto abort; | |
777 | } | |
778 | } else /* orphan */ if (te.owner) { | |
779 | fprintf(stderr, "Orphan group owner not zero\n"); | |
780 | goto abort; | |
781 | } | |
782 | } | |
783 | ||
784 | if (e) { | |
785 | if (length > misc->maxOwnerLength) | |
786 | misc->maxOwnerLength = length; | |
787 | } else | |
788 | misc->orphanLength = length; | |
789 | ||
790 | return 0; | |
791 | } | |
792 | ||
793 | afs_int32 | |
794 | WalkChains(char map[], /* one byte per db entry */ | |
795 | struct misc_data *misc) /* stuff to keep track of */ | |
796 | { | |
797 | afs_int32 code; | |
798 | int ei; | |
799 | afs_int32 ea; /* entry's db addr */ | |
800 | struct prentry e; | |
801 | afs_int32 id; | |
802 | int type; | |
803 | ||
804 | /* check all entries found in hash table walks */ | |
805 | for (ei = 0; ei < misc->nEntries; ei++) | |
806 | if (map[ei] & MAP_HASHES) { | |
807 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
808 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
809 | if (code) | |
810 | return code; | |
811 | ||
812 | if ((map[ei] & MAP_HASHES) != MAP_HASHES) { | |
813 | fprintf(stderr, "entry not in both hashtables\n"); | |
814 | if ((map[ei] & MAP_NAMEHASH) != MAP_NAMEHASH) | |
815 | fprintf(stderr, "--> entry not in Name hashtable\n"); | |
816 | if ((map[ei] & MAP_IDHASH) != MAP_IDHASH) | |
817 | fprintf(stderr, "--> entry not in ID hashtable\n"); | |
818 | ||
819 | abort: | |
820 | if (PrintEntryError(misc, ea, &e, 2)) | |
821 | return PRDBBAD; | |
822 | continue; | |
823 | } | |
824 | ||
825 | id = ntohl(e.id); | |
826 | ||
827 | type = ntohl(e.flags) & PRTYPE; | |
828 | switch (type) { | |
829 | case PRGRP: | |
830 | if (id >= 0) { | |
831 | fprintf(stderr, "Group id not negative\n"); | |
832 | goto abort; | |
833 | } | |
834 | /* special case sysadmin: it owns itself */ | |
835 | if (id == SYSADMINID) { | |
836 | if (ntohl(e.owner) != SYSADMINID) { | |
837 | fprintf(stderr, | |
838 | "System:administrators doesn't own itself\n"); | |
839 | goto abort; | |
840 | } | |
841 | } | |
842 | code = WalkOwnedChain(map, misc, ea, &e); | |
843 | if (code) | |
844 | return code; | |
845 | code = WalkNextChain(map, misc, ea, &e); | |
846 | if (code) | |
847 | return code; | |
848 | misc->ngroups++; | |
849 | break; | |
850 | case PRUSER: | |
851 | if (id <= 0) { | |
852 | #if defined(SUPERGROUPS) | |
853 | fprintf(stderr, "User id not positive\n"); | |
854 | #else | |
855 | fprintf(stderr, "User id negative\n"); | |
856 | #endif | |
857 | goto abort; | |
858 | } | |
859 | ||
860 | /* Users are owned by sysadmin, but sysadmin doesn't have an owner | |
861 | * chain. Check this then set the owned bit. */ | |
862 | if (ntohl(e.owner) != SYSADMINID) { | |
863 | fprintf(stderr, | |
864 | "User not owned by system:administrators\n"); | |
865 | goto abort; | |
866 | } | |
867 | if (e.nextOwned) { | |
868 | fprintf(stderr, "User has owned pointer\n"); | |
869 | goto abort; | |
870 | } | |
871 | map[ei] |= MAP_OWNED; | |
872 | ||
873 | code = WalkOwnedChain(map, misc, ea, &e); | |
874 | if (code) | |
875 | return code; | |
876 | code = WalkNextChain(map, misc, ea, &e); | |
877 | if (code) | |
878 | return code; | |
879 | if (strchr(e.name, '@') == 0) { | |
880 | misc->nusers++; /* Not a foreign user */ | |
881 | } else { | |
882 | misc->nforeigns++; /* A foreign user */ | |
883 | } | |
884 | break; | |
885 | case PRFREE: | |
886 | case PRCONT: | |
887 | case PRCELL: | |
888 | misc->ncells++; | |
889 | break; | |
890 | case PRFOREIGN: | |
891 | fprintf(stderr, | |
892 | "ENTRY IS unexpected type [PRFOREIGN] (flags=0x%x)\n", | |
893 | ntohl(e.flags)); | |
894 | break; | |
895 | case PRINST: | |
896 | misc->ninsts++; | |
897 | break; | |
898 | default: | |
899 | fprintf(stderr, "entry with unexpected type"); | |
900 | goto abort; | |
901 | } | |
902 | } | |
903 | ||
904 | return 0; | |
905 | } | |
906 | ||
907 | afs_int32 | |
908 | GC(char map[], struct misc_data *misc) | |
909 | { | |
910 | afs_int32 code; | |
911 | int ei; | |
912 | afs_int32 ea; | |
913 | struct prentry e; | |
914 | char m; | |
915 | ||
916 | for (ei = 0; ei < misc->nEntries; ei++) { | |
917 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
918 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
919 | if (code) | |
920 | return code; | |
921 | m = map[ei]; | |
922 | if (m == 0) { | |
923 | fprintf(stderr, "Unreferenced entry:"); | |
924 | if (PrintEntryError(misc, ea, &e, 2)) | |
925 | return PRDBBAD; | |
926 | } | |
927 | /* all users and groups should be owned, and their membership counts | |
928 | * should be okay */ | |
929 | else if ((m & MAP_HASHES) == MAP_HASHES) { | |
930 | afs_int32 id; | |
931 | int refCount; | |
932 | if (!(m & MAP_OWNED)) { | |
933 | fprintf(stderr, "Entry not on any owner chain:\n"); | |
934 | if (PrintEntryError(misc, ea, &e, 2)) | |
935 | return PRDBBAD; | |
936 | } | |
937 | id = ntohl(e.id); | |
938 | #if defined(SUPERGROUPS) | |
939 | if ((id != ANONYMOUSID) | |
940 | && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count))) | |
941 | #else | |
942 | if ((id >= misc->minId) && (id <= misc->maxId) | |
943 | && (id != ANONYMOUSID) | |
944 | && ((refCount = misc->idmap[id - misc->minId]) != | |
945 | ntohl(e.count))) | |
946 | #endif /* SUPERGROUPS */ | |
947 | { | |
948 | afs_int32 na; | |
949 | fprintf(stderr, | |
950 | "Entry membership count is inconsistent: %d entries refer to this one\n", | |
951 | refCount); | |
952 | if (PrintEntryError(misc, ea, &e, 2)) | |
953 | return PRDBBAD; | |
954 | ||
955 | /* get continuation blocks too */ | |
956 | for (na = ntohl(e.next); na; na = ntohl(e.next)) { | |
957 | int ni; | |
958 | code = ConvertDiskAddress(na, &ni); | |
959 | if (code) | |
960 | return code; | |
961 | code = pr_Read(na, (char *)&e, sizeof(e)); | |
962 | if (code) | |
963 | return code; | |
964 | if (PrintEntryError(misc, na, &e, 4)) | |
965 | return PRDBBAD; | |
966 | } | |
967 | } | |
968 | } | |
969 | } | |
970 | return 0; | |
971 | } | |
972 | ||
973 | char * | |
974 | QuoteName(char *s) | |
975 | { | |
976 | char *qs; | |
977 | if (strpbrk(s, " \t")) { | |
978 | if (asprintf(&qs, "\"%s\"", s) < 0) | |
979 | qs = "<<-OUT-OF-MEMORY->>"; | |
980 | } else | |
981 | qs = s; | |
982 | return qs; | |
983 | } | |
984 | ||
985 | afs_int32 | |
986 | DumpRecreate(char map[], struct misc_data *misc) | |
987 | { | |
988 | afs_int32 code; | |
989 | int ei; | |
990 | afs_int32 ea; | |
991 | struct prentry e; | |
992 | afs_int32 id; | |
993 | afs_int32 flags; | |
994 | afs_int32 owner; | |
995 | char *name; | |
996 | int builtinUsers = 0; | |
997 | int createLow = 0; /* users uncreate from here */ | |
998 | #if defined(SUPERGROUPS) | |
999 | struct idused *idmap; /* map of all id's */ | |
1000 | #else | |
1001 | afs_int32 *idmap; /* map of all id's */ | |
1002 | #endif | |
1003 | int found; | |
1004 | FILE *rc; | |
1005 | ||
1006 | rc = misc->recreate; | |
1007 | idmap = misc->idmap; | |
1008 | #if defined(SUPERGROUPS) | |
1009 | zeromap(idmap); | |
1010 | #else | |
1011 | memset(idmap, 0, misc->idRange * sizeof(misc->idmap[0])); | |
1012 | #endif | |
1013 | do { | |
1014 | found = 0; | |
1015 | for (ei = createLow; ei < misc->nEntries; ei++) { | |
1016 | if ((map[ei] & MAP_HASHES) && (map[ei] & MAP_RECREATE) == 0) { | |
1017 | afs_int32 mask; | |
1018 | afs_int32 access; | |
1019 | int gq, uq; | |
1020 | ||
1021 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
1022 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
1023 | if (code) | |
1024 | return code; | |
1025 | ||
1026 | if (misc->listentries) | |
1027 | pr_PrintEntry(stdout, 0 /*not in host order */ , ea, &e, | |
1028 | 0); | |
1029 | ||
1030 | id = ntohl(e.id); | |
1031 | flags = ntohl(e.flags); | |
1032 | owner = ntohl(e.owner); | |
1033 | name = QuoteName(e.name); | |
1034 | ||
1035 | if (!strcmp(e.name, "system:administrators") | |
1036 | || !strcmp(e.name, "system:anyuser") | |
1037 | || !strcmp(e.name, "system:authuser") | |
1038 | || !strcmp(e.name, "system:backup") | |
1039 | || !strcmp(e.name, "anonymous")) { | |
1040 | builtinUsers++; | |
1041 | goto user_done; | |
1042 | } | |
1043 | ||
1044 | /* check for duplicate id. This may still lead to duplicate | |
1045 | * names. */ | |
1046 | #if defined(SUPERGROUPS) | |
1047 | if (idcount(&idmap, id)) | |
1048 | #else | |
1049 | if (idmap[id - misc->minId]) | |
1050 | #endif | |
1051 | { | |
1052 | fprintf(stderr, "Skipping entry with duplicate id %di\n", | |
1053 | id); | |
1054 | goto user_done; | |
1055 | } | |
1056 | ||
1057 | /* If owner doesn't exist skip for now, unless we're our own | |
1058 | * owner. If so, a special case allows a group to own itself | |
1059 | * if caller is sysadmin. This leaves only owner cycles to | |
1060 | * deal with. */ | |
1061 | ||
1062 | if ((owner < misc->minId) || (owner > misc->maxId)) { | |
1063 | if (owner == ANONYMOUSID) | |
1064 | fprintf(stderr, | |
1065 | "Warning: id %di is owned by ANONYMOUS; using sysadmin instead\n", | |
1066 | id); | |
1067 | else | |
1068 | fprintf(stderr, | |
1069 | "Bogus owner (%d) of id %di; using sysadmin instead\n", | |
1070 | owner, id); | |
1071 | owner = SYSADMINID; | |
1072 | } | |
1073 | if (id == owner) { | |
1074 | fprintf(stderr, "Warning: group %s is self owning\n", | |
1075 | name); | |
1076 | } else if (owner == 0) { | |
1077 | fprintf(stderr, | |
1078 | "Warning: orphan group %s will become self owning.\n", | |
1079 | name); | |
1080 | owner = id; | |
1081 | } | |
1082 | #if defined(SUPERGROUPS) | |
1083 | else if (!idcount(&idmap, owner)) | |
1084 | goto user_skip; | |
1085 | #else | |
1086 | else if (idmap[owner - misc->minId] == 0) | |
1087 | goto user_skip; | |
1088 | #endif | |
1089 | ||
1090 | if (rc) | |
1091 | fprintf(rc, "cr %s %d %d\n", name, id, owner); | |
1092 | ||
1093 | gq = uq = access = mask = 0; | |
1094 | if (flags & PRACCESS) { | |
1095 | access = (flags >> PRIVATE_SHIFT); | |
1096 | mask |= PR_SF_ALLBITS; | |
1097 | } | |
1098 | if (flags & PRQUOTA) { | |
1099 | gq = ntohl(e.ngroups); | |
1100 | uq = ntohl(e.nusers); | |
1101 | mask |= PR_SF_NGROUPS | PR_SF_NUSERS; | |
1102 | } | |
1103 | if (mask && rc) { | |
1104 | fprintf(rc, "sf %d %x %x %d %d\n", id, mask, access, gq, | |
1105 | uq); | |
1106 | } | |
1107 | user_done: | |
1108 | map[ei] |= MAP_RECREATE; | |
1109 | #if defined(SUPERGROUPS) | |
1110 | if (id != ANONYMOUSID) | |
1111 | inccount(&idmap, id); | |
1112 | #else | |
1113 | if (id != ANONYMOUSID) | |
1114 | idmap[id - misc->minId]++; | |
1115 | #endif | |
1116 | found++; | |
1117 | } | |
1118 | /* bump low water mark if possible */ | |
1119 | if (ei == createLow) | |
1120 | createLow++; | |
1121 | user_skip:; | |
1122 | } | |
1123 | misc->verbose = 0; | |
1124 | } while (found); | |
1125 | ||
1126 | /* Now create the entries with circular owner dependencies and make them | |
1127 | * own themselves. This is the only way to create them with the correct | |
1128 | * names. */ | |
1129 | for (ei = 0; ei < misc->nEntries; ei++) | |
1130 | if (((map[ei] & MAP_HASHES) == MAP_HASHES) | |
1131 | && (map[ei] & MAP_RECREATE) == 0) { | |
1132 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
1133 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
1134 | if (code) | |
1135 | return code; | |
1136 | ||
1137 | id = ntohl(e.id); | |
1138 | name = QuoteName(e.name); | |
1139 | fprintf(stderr, "Warning: group %s in self owning cycle\n", name); | |
1140 | if (rc) | |
1141 | fprintf(rc, "cr %s %d %d\n", name, id, id); | |
1142 | #if defined(SUPERGROUPS) | |
1143 | inccount(&idmap, id); | |
1144 | #else | |
1145 | idmap[id - misc->minId]++; | |
1146 | #endif | |
1147 | } | |
1148 | for (ei = 0; ei < misc->nEntries; ei++) | |
1149 | if (((map[ei] & MAP_HASHES) == MAP_HASHES) | |
1150 | && (map[ei] & MAP_RECREATE) == 0) { | |
1151 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
1152 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
1153 | if (code) | |
1154 | return code; | |
1155 | ||
1156 | owner = ntohl(e.owner); | |
1157 | #if defined(SUPERGROUPS) | |
1158 | if (!idcount(&idmap, owner)) | |
1159 | #else | |
1160 | if (idmap[owner - misc->minId] == 0) | |
1161 | #endif | |
1162 | { | |
1163 | fprintf(stderr, | |
1164 | "Skipping chown of '%s' to non-existant owner %di\n", | |
1165 | e.name, owner); | |
1166 | } else if (rc) | |
1167 | fprintf(rc, "ce %d \"\" %d 0\n", ntohl(e.id), e.owner); | |
1168 | } | |
1169 | ||
1170 | if (rc == 0) | |
1171 | return 0; | |
1172 | ||
1173 | /* Reconstruct membership information based on the groups' user lists. */ | |
1174 | for (ei = 0; ei < misc->nEntries; ei++) { | |
1175 | if ((map[ei] & MAP_HASHES) == MAP_HASHES) { | |
1176 | ea = ei * sizeof(struct prentry) + sizeof(cheader); | |
1177 | code = pr_Read(ea, (char *)&e, sizeof(e)); | |
1178 | if (code) | |
1179 | return code; | |
1180 | ||
1181 | id = ntohl(e.id); | |
1182 | flags = ntohl(e.flags); | |
1183 | ||
1184 | if ((id < 0) && (flags & PRGRP)) { | |
1185 | int count = 0; | |
1186 | afs_int32 na; | |
1187 | int i; | |
1188 | for (i = 0; i < PRSIZE; i++) { | |
1189 | afs_int32 uid = ntohl(e.entries[i]); | |
1190 | if (uid == 0) | |
1191 | break; | |
1192 | if (uid == PRBADID) | |
1193 | continue; | |
1194 | #if !defined(SUPERGROUPS) | |
1195 | if (uid > 0) { | |
1196 | #endif | |
1197 | fprintf(rc, "au %d %d\n", uid, id); | |
1198 | count++; | |
1199 | #if !defined(SUPERGROUPS) | |
1200 | } else | |
1201 | fprintf(stderr, "Skipping %di in group %di\n", uid, | |
1202 | id); | |
1203 | #endif | |
1204 | } | |
1205 | na = ntohl(e.next); | |
1206 | while (na) { | |
1207 | struct contentry c; | |
1208 | code = pr_Read(na, (char *)&c, sizeof(c)); | |
1209 | if (code) | |
1210 | return code; | |
1211 | ||
1212 | if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) { | |
1213 | for (i = 0; i < COSIZE; i++) { | |
1214 | afs_int32 uid = ntohl(c.entries[i]); | |
1215 | if (uid == 0) | |
1216 | break; | |
1217 | if (uid == PRBADID) | |
1218 | continue; | |
1219 | #if !defined(SUPERGROUPS) | |
1220 | if (uid > 0) { | |
1221 | #endif | |
1222 | fprintf(rc, "au %d %d\n", uid, id); | |
1223 | count++; | |
1224 | #if !defined(SUPERGROUPS) | |
1225 | } else | |
1226 | fprintf(stderr, "Skipping %di in group %di\n", | |
1227 | uid, id); | |
1228 | #endif | |
1229 | } | |
1230 | } else { | |
1231 | fprintf(stderr, "Skipping continuation block at %d\n", | |
1232 | na); | |
1233 | break; | |
1234 | } | |
1235 | na = ntohl(c.next); | |
1236 | } | |
1237 | if (count != ntohl(e.count)) | |
1238 | fprintf(stderr, | |
1239 | "Group membership count problem found %d should be %d\n", | |
1240 | count, ntohl(e.count)); | |
1241 | } else if ((id < 0) || (flags & PRGRP)) { | |
1242 | fprintf(stderr, "Skipping group %di\n", id); | |
1243 | } | |
1244 | } | |
1245 | } | |
1246 | return 0; | |
1247 | } | |
1248 | ||
1249 | afs_int32 | |
1250 | CheckPrDatabase(struct misc_data *misc) /* info & statistics */ | |
1251 | { | |
1252 | afs_int32 code; | |
1253 | afs_int32 eof; | |
1254 | int n; | |
1255 | char *map; /* map of each entry in db */ | |
1256 | ||
1257 | eof = ntohl(cheader.eofPtr); | |
1258 | eof -= sizeof(cheader); | |
1259 | n = eof / sizeof(struct prentry); | |
1260 | if ((eof < 0) || (n * sizeof(struct prentry) != eof)) { | |
1261 | code = PRDBBAD; | |
1262 | afs_com_err(whoami, code, | |
1263 | "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT, | |
1264 | eof, sizeof(struct prentry)); | |
1265 | abort: | |
1266 | return code; | |
1267 | } | |
1268 | if (misc->verbose) | |
1269 | printf("Database has %d entries\n", n); | |
1270 | map = calloc(1, n); | |
1271 | misc->nEntries = n; | |
1272 | ||
1273 | if (misc->verbose) { | |
1274 | printf("\nChecking name hash table\n"); | |
1275 | fflush(stdout); | |
1276 | } | |
1277 | code = WalkHashTable(cheader.nameHash, MAP_NAMEHASH, map, misc); | |
1278 | if (code) { | |
1279 | afs_com_err(whoami, code, "walking name hash"); | |
1280 | goto abort; | |
1281 | } | |
1282 | if (misc->verbose) { | |
1283 | printf("\nChecking id hash table\n"); | |
1284 | fflush(stdout); | |
1285 | } | |
1286 | code = WalkHashTable(cheader.idHash, MAP_IDHASH, map, misc); | |
1287 | if (code) { | |
1288 | afs_com_err(whoami, code, "walking id hash"); | |
1289 | goto abort; | |
1290 | } | |
1291 | ||
1292 | /* hash walk calculates min and max id */ | |
1293 | #if defined(SUPERGROUPS) | |
1294 | misc->idmap = 0; | |
1295 | #else | |
1296 | n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId); | |
1297 | misc->idRange = n - misc->minId + 1; | |
1298 | misc->idmap = calloc(misc->idRange, sizeof(afs_int32)); | |
1299 | if (!misc->idmap) { | |
1300 | afs_com_err(whoami, 0, "Unable to malloc space for max ids of %d", | |
1301 | misc->idRange); | |
1302 | code = -1; | |
1303 | goto abort; | |
1304 | } | |
1305 | #endif /* SUPERGROUPS */ | |
1306 | ||
1307 | if (misc->verbose) { | |
1308 | printf("\nChecking entry chains\n"); | |
1309 | fflush(stdout); | |
1310 | } | |
1311 | code = WalkChains(map, misc); | |
1312 | if (code) { | |
1313 | afs_com_err(whoami, code, "walking chains"); | |
1314 | goto abort; | |
1315 | } | |
1316 | if (misc->verbose) { | |
1317 | printf("\nChecking free list\n"); | |
1318 | fflush(stdout); | |
1319 | } | |
1320 | code = WalkNextChain(map, misc, 0, 0); | |
1321 | if (code) { | |
1322 | afs_com_err(whoami, code, "walking free list"); | |
1323 | goto abort; | |
1324 | } | |
1325 | if (misc->verbose) { | |
1326 | printf("\nChecking orphans list\n"); | |
1327 | fflush(stdout); | |
1328 | } | |
1329 | code = WalkOwnedChain(map, misc, 0, 0); | |
1330 | if (code) { | |
1331 | afs_com_err(whoami, code, "walking orphan list"); | |
1332 | goto abort; | |
1333 | } | |
1334 | ||
1335 | if (misc->verbose) { | |
1336 | printf("\nChecking for unreferenced entries\n"); | |
1337 | fflush(stdout); | |
1338 | } | |
1339 | code = GC(map, misc); | |
1340 | if (code) { | |
1341 | afs_com_err(whoami, code, "looking for unreferenced entries"); | |
1342 | goto abort; | |
1343 | } | |
1344 | ||
1345 | DumpRecreate(map, misc); /* check for owner cycles */ | |
1346 | if (misc->recreate) | |
1347 | fclose(misc->recreate); | |
1348 | ||
1349 | if (misc->anon != 2) /* once for each hash table */ | |
1350 | fprintf(stderr, "Problems with ANON=%d\n", misc->anon); | |
1351 | if (misc->ncells || misc->ninsts) | |
1352 | fprintf(stderr, "Unexpected entry type\n"); | |
1353 | if (misc->nusers != ntohl(cheader.usercount)) { | |
1354 | fprintf(stderr, | |
1355 | "User count inconsistent: should be %d, header claims: %d\n", | |
1356 | misc->nusers, ntohl(cheader.usercount)); | |
1357 | } | |
1358 | if (misc->ngroups != ntohl(cheader.groupcount)) { | |
1359 | fprintf(stderr, | |
1360 | "Group count inconsistent: should be %d, header claims: %d\n", | |
1361 | misc->ngroups, ntohl(cheader.groupcount)); | |
1362 | } | |
1363 | if (misc->maxId > ntohl(cheader.maxID)) | |
1364 | fprintf(stderr, | |
1365 | "Database's max user Id (%d) is smaller than largest user's Id (%d).\n", | |
1366 | ntohl(cheader.maxID), misc->maxId); | |
1367 | if (misc->minId < ntohl(cheader.maxGroup)) | |
1368 | fprintf(stderr, | |
1369 | "Database's max group Id (%d) is smaller than largest group's Id (%d).\n", | |
1370 | ntohl(cheader.maxGroup), misc->minId); | |
1371 | ||
1372 | if (misc->verbose) { | |
1373 | printf("\nMaxId = %d, MinId = %d, MaxForeignId = %d\n", misc->maxId, | |
1374 | misc->minId, misc->maxForId); | |
1375 | printf | |
1376 | ("Free list is %d entries in length, %d groups on orphan list\n", | |
1377 | misc->freeLength, misc->orphanLength); | |
1378 | printf | |
1379 | ("The longest owner list is %d, the longest continuation block chain is %d\n", | |
1380 | misc->maxOwnerLength, misc->maxContLength); | |
1381 | printf("%d users ; %d foreign users ; and %d groups\n", misc->nusers, | |
1382 | misc->nforeigns, misc->ngroups); | |
1383 | } | |
1384 | ||
1385 | free(map); | |
1386 | return code; | |
1387 | } | |
1388 | ||
1389 | #include "AFS_component_version_number.c" | |
1390 | ||
1391 | int | |
1392 | WorkerBee(struct cmd_syndesc *as, void *arock) | |
1393 | { | |
1394 | afs_int32 code; | |
1395 | char *recreateFile; | |
1396 | struct misc_data misc; /* info & statistics */ | |
1397 | ||
1398 | initialize_PT_error_table(); | |
1399 | initialize_U_error_table(); | |
1400 | ||
1401 | pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH; | |
1402 | memset(&misc, 0, sizeof(misc)); | |
1403 | ||
1404 | pr_dbaseName = as->parms[0].items->data; /* -database */ | |
1405 | misc.listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */ | |
1406 | misc.listpheader = (as->parms[2].items ? 1 : 0); /* -pheader */ | |
1407 | misc.listentries = (as->parms[3].items ? 1 : 0); /* -entries */ | |
1408 | misc.verbose = (as->parms[4].items ? 1 : 0); /* -verbose */ | |
1409 | recreateFile = (as->parms[5].items ? as->parms[5].items->data : NULL); /* -rebuild */ | |
1410 | ||
1411 | fd = open(pr_dbaseName, O_RDONLY, 0); | |
1412 | if (fd == -1) { | |
1413 | afs_com_err(whoami, errno, "Open failed on db %s", pr_dbaseName); | |
1414 | exit(2); | |
1415 | } | |
1416 | ||
1417 | /* Read the ubik header */ | |
1418 | if (misc.listuheader) { | |
1419 | readUbikHeader(&misc); | |
1420 | } | |
1421 | ||
1422 | code = ReadHeader(); | |
1423 | if (code) | |
1424 | return code; | |
1425 | if (misc.listpheader) | |
1426 | printheader(&cheader); | |
1427 | ||
1428 | if (recreateFile) { | |
1429 | misc.recreate = fopen(recreateFile, "w"); | |
1430 | if (misc.recreate == 0) { | |
1431 | afs_com_err(whoami, errno, | |
1432 | "can't create file for recreation instructions: %s", | |
1433 | recreateFile); | |
1434 | exit(4); | |
1435 | } | |
1436 | } | |
1437 | code = CheckPrDatabase(&misc); | |
1438 | if (code) { | |
1439 | afs_com_err(whoami, code, "Checking prserver database"); | |
1440 | exit(3); | |
1441 | } | |
1442 | exit(0); | |
1443 | } | |
1444 | ||
1445 | int | |
1446 | main(int argc, char *argv[]) | |
1447 | { | |
1448 | struct cmd_syndesc *ts; | |
1449 | ||
1450 | setlinebuf(stdout); | |
1451 | ||
1452 | ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "PRDB check"); | |
1453 | cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file"); | |
1454 | cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, | |
1455 | "Display UBIK header"); | |
1456 | cmd_AddParm(ts, "-pheader", CMD_FLAG, CMD_OPTIONAL, | |
1457 | "Display KADB header"); | |
1458 | cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries"); | |
1459 | cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose"); | |
1460 | cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL | CMD_HIDE, | |
1461 | "out_file"); | |
1462 | ||
1463 | return cmd_Dispatch(argc, argv); | |
1464 | } | |
1465 | ||
1466 | ||
1467 | #if defined(SUPERGROUPS) | |
1468 | ||
1469 | /* new routines to deal with very large ID numbers */ | |
1470 | ||
1471 | void | |
1472 | zeromap(struct idused *idmap) | |
1473 | { | |
1474 | while (idmap) { | |
1475 | memset(idmap->idcount, 0, sizeof idmap->idcount); | |
1476 | idmap = idmap->idnext; | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | void | |
1481 | inccount(struct idused **idmapp, int id) | |
1482 | { | |
1483 | struct idused *idmap; | |
1484 | ||
1485 | if (IDCOUNT & (IDCOUNT - 1)) { | |
1486 | fprintf(stderr, "IDCOUNT must be power of 2!\n"); | |
1487 | exit(1); | |
1488 | } | |
1489 | while ((idmap = *idmapp) != NULL) { | |
1490 | if (idmap->idstart == (id & ~(IDCOUNT - 1))) | |
1491 | break; | |
1492 | idmapp = &idmap->idnext; | |
1493 | } | |
1494 | if (!idmap) { | |
1495 | idmap = calloc(1, sizeof *idmap); | |
1496 | if (!idmap) { | |
1497 | perror("idmap"); | |
1498 | exit(1); | |
1499 | } | |
1500 | idmap->idstart = id & ~(IDCOUNT - 1); | |
1501 | idmap->idnext = *idmapp; | |
1502 | *idmapp = idmap; | |
1503 | } | |
1504 | ++idmap->idcount[id & (IDCOUNT - 1)]; | |
1505 | } | |
1506 | ||
1507 | int | |
1508 | idcount(struct idused **idmapp, int id) | |
1509 | { | |
1510 | struct idused *idmap; | |
1511 | ||
1512 | if (IDCOUNT & (IDCOUNT - 1)) { | |
1513 | fprintf(stderr, "IDCOUNT must be power of 2!\n"); | |
1514 | exit(1); | |
1515 | } | |
1516 | while ((idmap = *idmapp) != NULL) { | |
1517 | if (idmap->idstart == (id & ~(IDCOUNT - 1))) { | |
1518 | return idmap->idcount[id & (IDCOUNT - 1)]; | |
1519 | } | |
1520 | idmapp = &idmap->idnext; | |
1521 | } | |
1522 | return 0; | |
1523 | } | |
1524 | #endif /* SUPERGROUPS */ |