]>
Commit | Line | Data |
---|---|---|
a04caf14 | 1 | /* $Header$ |
2 | * | |
3 | */ | |
4 | ||
5 | #include <mit-copyright.h> | |
6 | #include <stdio.h> | |
7 | #include <sys/file.h> | |
8 | #include <rx/xdr.h> | |
dba0cf81 | 9 | #include <afs/ptint.h> |
10 | #include <afs/ptserver.h> | |
11 | #include <afs/pterror.h> | |
e88f0823 | 12 | #include <moira.h> |
13 | #include <moira_site.h> | |
a04caf14 | 14 | #include <ctype.h> |
15 | ||
16 | ||
17 | #define min(x,y) ((x) < (y) ? (x) : (y)) | |
18 | #define abs(x) (((x) > 0) ? (x) : -(x)) | |
19 | struct hash *users, *groups, *usersid, *groupsid; | |
20 | char *whoami = "sync"; | |
21 | ||
e88f0823 | 22 | char *malloc(), *strsave(), *perm_malloc(); |
a04caf14 | 23 | int dbase_fd; |
e88f0823 | 24 | int replaceflag = 0; |
a04caf14 | 25 | struct prheader prh; |
26 | ||
27 | ||
28 | main(argc, argv) | |
29 | int argc; | |
30 | char **argv; | |
31 | { | |
e88f0823 | 32 | int i; |
33 | char *file = NULL; | |
a04caf14 | 34 | int ingerr(); |
35 | ||
e88f0823 | 36 | for (i = 1; i < argc; i++) { |
37 | if (argv[i][0] == '-') { | |
38 | switch (argv[i][1]) { | |
39 | case 'r': | |
40 | replaceflag++; | |
41 | break; | |
42 | default: | |
43 | usage(argv[0]); | |
44 | } | |
45 | } else { | |
46 | if (file == NULL) | |
47 | file = argv[i]; | |
48 | else | |
49 | usage(argv[0]); | |
50 | } | |
a04caf14 | 51 | } |
52 | ||
e88f0823 | 53 | i = O_RDONLY; |
54 | if (replaceflag) | |
55 | i = O_RDWR; | |
56 | dbase_fd = open(file, i, 0660); | |
a04caf14 | 57 | if (dbase_fd < 0) { |
e88f0823 | 58 | perror("opening file %s", file); |
a04caf14 | 59 | exit(1); |
60 | } | |
61 | IIseterr(ingerr); | |
62 | initialize_sms_error_table (); | |
63 | ||
64 | ## ingres sms | |
65 | ## set lockmode session where level = table | |
66 | ## begin transaction | |
67 | ||
68 | get_users(); | |
69 | get_groups(); | |
70 | get_members(); | |
71 | ||
72 | ## end transaction | |
73 | ## exit | |
74 | ||
75 | pr_Read(NULL, 0, 0, &prh, sizeof(prh)); | |
76 | check_users_and_groups(); | |
77 | ||
e88f0823 | 78 | exit(MR_SUCCESS); |
79 | } | |
80 | ||
81 | usage(name) | |
82 | char *name; | |
83 | { | |
84 | fprintf(stderr, "usage: %s [-r] dbfile\n", name); | |
85 | exit(MR_ARGS); | |
a04caf14 | 86 | } |
87 | ||
88 | ||
89 | /* | |
90 | * ingerr: (supposedly) called when Ingres indicates an error. | |
91 | * I have not yet been able to get this to work to intercept a | |
92 | * database open error. | |
93 | */ | |
94 | #define INGRES_DEADLOCK 4700 | |
95 | ||
96 | static int ingerr(num) | |
97 | int *num; | |
98 | { | |
99 | char buf[256]; | |
100 | int ingres_errno; | |
101 | ||
102 | switch (*num) { | |
103 | case INGRES_DEADLOCK: | |
e88f0823 | 104 | ingres_errno = MR_DEADLOCK; |
a04caf14 | 105 | break; |
106 | default: | |
e88f0823 | 107 | ingres_errno = MR_INGRES_ERR; |
a04caf14 | 108 | } |
e88f0823 | 109 | com_err(whoami, MR_INGRES_ERR, " code %d\n", *num); |
a04caf14 | 110 | exit(ingres_errno); |
111 | } | |
112 | ||
113 | ||
114 | prserror(status, msg, arg1, arg2) | |
115 | int status; | |
116 | char *msg; | |
117 | unsigned long arg1, arg2; | |
118 | { | |
119 | char buf[512]; | |
120 | ||
121 | sprintf(buf, msg, arg1, arg2); | |
122 | switch (status) { | |
123 | case PREXIST: | |
124 | msg = "name already exists"; | |
125 | break; | |
126 | case PRIDEXIST: | |
127 | msg = "ID already exists"; | |
128 | break; | |
129 | case PRNOIDS: | |
130 | msg = "no IDs available"; | |
131 | break; | |
132 | case PRDBFAIL: | |
133 | msg = "database failed"; | |
134 | break; | |
135 | case PRNOENT: | |
136 | msg = "no space left in database"; | |
137 | break; | |
138 | case PRPERM: | |
139 | msg = "permission denied"; | |
140 | break; | |
141 | case PRNOTGROUP: | |
142 | msg = "not a group"; | |
143 | break; | |
144 | case PRNOTUSER: | |
145 | msg = "not a user"; | |
146 | break; | |
147 | case PRBADNAM: | |
148 | msg = "bad name"; | |
149 | break; | |
150 | case 0: | |
151 | msg = "no error"; | |
152 | break; | |
153 | default: | |
154 | msg = "unknown code"; | |
155 | break; | |
156 | } | |
157 | fprintf(stderr, "%s (%d): %s\n", msg, status, buf); | |
158 | } | |
159 | ||
160 | ||
161 | nomem(msg) | |
162 | char *msg; | |
163 | { | |
164 | fprintf(stderr, "Out of memory: %s\n", msg); | |
165 | exit(1); | |
166 | } | |
167 | ||
168 | ||
169 | struct user { | |
170 | char login[9]; | |
171 | char flag; | |
172 | short uid; | |
173 | }; | |
174 | ||
175 | ||
176 | get_users() | |
177 | ##{ | |
178 | ## char login[9]; | |
179 | ## int uid, id; | |
180 | struct user *u; | |
181 | ||
182 | fprintf(stderr, "Loading users from Moira\n"); | |
183 | users = create_hash(10000); | |
184 | usersid = create_hash(10000); | |
185 | ## range of u is users | |
186 | ## retrieve (login = u.#login, uid = u.#uid, id = u.users_id) | |
187 | ## where u.#status = 1 { | |
188 | strtrim(login); | |
e88f0823 | 189 | u = (struct user *)perm_malloc(sizeof(struct user)); |
a04caf14 | 190 | if (u == NULL) |
191 | nomem("loading users"); | |
192 | strncpy(u->login, login, 9); | |
193 | u->flag = 0; | |
194 | u->uid = uid; | |
195 | hash_store(users, uid, u); | |
196 | hash_store(usersid, id, u); | |
197 | ## } | |
198 | ##} | |
199 | ||
200 | ||
e88f0823 | 201 | #define CHUNKSIZE 5 |
a04caf14 | 202 | struct chunk { |
203 | short member[CHUNKSIZE]; | |
204 | struct chunk *xmem; | |
205 | }; | |
206 | ||
207 | struct group { | |
208 | char name[33]; | |
209 | char flag; | |
210 | short gid; | |
211 | short members; | |
212 | struct chunk ch; | |
213 | }; | |
214 | ||
215 | ||
216 | get_groups() | |
217 | ##{ | |
218 | ## char name[33]; | |
219 | ## int gid, id; | |
220 | struct group *g; | |
221 | ||
222 | fprintf(stderr, "Loading groups from Moira\n"); | |
223 | groups = create_hash(10000); | |
224 | groupsid = create_hash(10000); | |
225 | ## range of l is list | |
226 | ## retrieve (name = l.#name, gid = l.#gid, id = l.list_id) | |
227 | ## where l.#active = 1 and l.#group = 1 { | |
228 | strtrim(name); | |
e88f0823 | 229 | g = (struct group *)perm_malloc(sizeof(struct group)); |
a04caf14 | 230 | if (g == NULL) |
231 | nomem("loading groups"); | |
232 | bzero(g, sizeof(struct group)); | |
233 | strncpy(g->name, name, 33); | |
e88f0823 | 234 | g->gid = gid; |
a04caf14 | 235 | hash_store(groups, gid, g); |
236 | hash_store(groupsid, id, g); | |
237 | ## } | |
238 | ##} | |
239 | ||
240 | ||
241 | get_members() | |
242 | ##{ | |
243 | struct user *u; | |
244 | struct group *g; | |
245 | ## int id, lid; | |
246 | ||
247 | fprintf(stderr, "Fetching members from Moira\n"); | |
248 | ||
249 | ## range of m is imembers | |
250 | ||
251 | ## retrieve (lid = m.list_id, id = m.member_id) | |
252 | ## where m.member_type = "USER" { | |
253 | if ((u = (struct user *) hash_lookup(usersid, id)) && | |
254 | (g = (struct group *) hash_lookup(groupsid, lid))) { | |
255 | if (g->members < CHUNKSIZE) { | |
256 | g->ch.member[g->members] = u->uid; | |
257 | } else { | |
258 | int i = g->members - CHUNKSIZE; | |
259 | struct chunk *c; | |
260 | ||
261 | if ((c = g->ch.xmem) == NULL) { | |
e88f0823 | 262 | c = (struct chunk *) perm_malloc(sizeof(struct chunk)); |
a04caf14 | 263 | if (c == NULL) |
264 | nomem("loading members"); | |
265 | g->ch.xmem = c; | |
266 | } | |
267 | while (i >= CHUNKSIZE) { | |
268 | i -= CHUNKSIZE; | |
269 | if (c->xmem == NULL) { | |
e88f0823 | 270 | c->xmem = (struct chunk *) perm_malloc(sizeof(struct chunk)); |
a04caf14 | 271 | if (c->xmem == NULL) |
272 | nomem("loading members"); | |
273 | } | |
274 | c = c->xmem; | |
275 | } | |
276 | c->member[i] = u->uid; | |
277 | } | |
278 | g->members++; | |
279 | } | |
280 | ## } | |
281 | ||
282 | ##} | |
283 | ||
284 | ||
285 | ||
286 | checkuser(id, u) | |
287 | int id; | |
288 | struct user *u; | |
289 | { | |
e88f0823 | 290 | int status; |
291 | ||
292 | if (u->flag == 0) { | |
293 | printf("< User %s id %d is in Moira but not in prs\n", | |
294 | u->login, u->uid); | |
295 | if (replaceflag) { | |
296 | status = PR_INewEntry(NULL, u->login, u->uid, 0); | |
297 | if (status) { | |
298 | prserror(status, "adding user %s uid %d to prs database", | |
299 | u->login, u->uid); | |
300 | } | |
301 | } | |
302 | } | |
a04caf14 | 303 | } |
304 | ||
305 | checkgroup(id, g) | |
306 | int id; | |
307 | struct group *g; | |
308 | { | |
e88f0823 | 309 | register int i, j, status; |
a04caf14 | 310 | struct chunk *c; |
311 | ||
e88f0823 | 312 | if (g->flag == 0) { |
313 | printf("< Group %s id %d is in Moira but not in prs\n", | |
314 | g->name, g->gid); | |
315 | if (replaceflag) { | |
316 | char namebuf[64]; | |
317 | sprintf(namebuf, "system:%s", g->name); | |
318 | status = PR_INewEntry(NULL, namebuf, -g->gid, SYSADMINID); | |
319 | if (status) | |
320 | prserror(status, "adding list %s gid %d to prs database", | |
321 | namebuf, -g->gid); | |
322 | } | |
323 | } | |
a04caf14 | 324 | c = (struct chunk *)&(g->ch); |
325 | for (i = 0; i < g->members; i++) { | |
326 | j = i % CHUNKSIZE; | |
327 | printf("< Group %s contains user %d in Moira but not in prs\n", | |
328 | g->name, c->member[j]); | |
e88f0823 | 329 | if (replaceflag) { |
330 | status = PR_AddToGroup(NULL, c->member[j], -g->gid); | |
331 | if (status) | |
332 | prserror(status, "adding %d to group %d in prs", | |
333 | c->member[j], -g->gid); | |
334 | } | |
a04caf14 | 335 | if (j == CHUNKSIZE - 1) |
336 | c = c->xmem; | |
337 | } | |
338 | } | |
339 | ||
340 | check_users_and_groups() | |
341 | { | |
342 | register int i; | |
343 | int offset; | |
344 | ||
345 | fprintf(stderr, "Scanning PRS database\n"); | |
346 | ||
347 | for (i = 0; i < HASHSIZE; i++) { | |
348 | offset = ntohl(prh.idHash[i]); | |
349 | while (offset) | |
350 | offset = check_entry(offset); | |
351 | } | |
352 | hash_step(users, checkuser, NULL); | |
353 | hash_step(groups, checkgroup, NULL); | |
354 | } | |
355 | ||
356 | check_entry(offset) | |
357 | int offset; | |
358 | { | |
359 | struct prentry entry; | |
360 | int flags, id, status; | |
361 | struct user *u; | |
362 | struct group *g; | |
363 | ||
364 | status = pr_Read(NULL, 0, offset, &entry, sizeof(entry)); | |
365 | if (status) | |
366 | prserror(status, "reading prentry at %d", offset, 0); | |
367 | flags = ntohl(entry.flags); | |
368 | id = ntohl(entry.id); | |
369 | if ((flags & PRFREE) == 0) { | |
370 | if (flags & PRGRP) { | |
371 | g = (struct group *) hash_lookup(groups, abs(id)); | |
e88f0823 | 372 | if (g == NULL) { |
373 | if (!strncmp(entry.name, "system:", 7)) { | |
374 | printf("> Group %s, id %d is in prs but not moira\n", | |
375 | entry.name, id); | |
376 | if (replaceflag) { | |
377 | status = PR_Delete(NULL, id); | |
378 | if (status) | |
379 | prserror(status, "deleting group %d from prs", id); | |
380 | } | |
381 | } | |
382 | } else if (strcasecmp(g->name, index(entry.name, ':')+1)) { | |
383 | printf("> GID %d in prs is %s, but GID %d in moira is %s\n", | |
384 | id, entry.name, -id, g->name); | |
385 | if (replaceflag) { | |
386 | printf("*** Dont' know how to fix this!!!!!\n"); | |
387 | } | |
388 | } else { | |
a04caf14 | 389 | g->flag = 1; |
390 | if (entry.entries[0]) | |
391 | do_members(&entry, g); | |
392 | } | |
393 | } else { | |
394 | u = (struct user *) hash_lookup(users, abs(id)); | |
e88f0823 | 395 | if (u == NULL) { |
396 | printf("> User %s, id %d is in prs but not moira\n", | |
397 | entry.name, id); | |
398 | if (replaceflag) { | |
399 | status = PR_Delete(NULL, id); | |
400 | if (status) | |
401 | prserror(status, "while deleting user %d from prs", id); | |
402 | } | |
403 | } else if (strcasecmp(u->login, entry.name)) { | |
404 | printf("> User id %d in prs is %s, but UID %d in moira is %s\n", | |
405 | id, entry.name, id, u->login); | |
406 | if (replaceflag) { | |
407 | printf("*** don't know how to fix this!!!!!\n"); | |
408 | } | |
409 | } else | |
a04caf14 | 410 | u->flag = 1; |
411 | } | |
412 | } | |
413 | return(ntohl(entry.nextID)); | |
414 | } | |
415 | ||
416 | ||
417 | do_members(e, g) | |
418 | struct prentry *e; | |
419 | struct group *g; | |
420 | { | |
421 | register int i; | |
422 | int offset; | |
423 | struct contentry prco; | |
424 | ||
425 | for (i = 0; i < PRSIZE; i++) { | |
426 | if (e->entries[i] == 0) | |
427 | return; | |
428 | mark_member(g, ntohl(e->entries[i])); | |
429 | } | |
430 | offset = ntohl(e->next); | |
431 | while (offset) { | |
432 | pr_Read(NULL, 0, offset, &prco, sizeof(struct contentry)); | |
433 | for (i = 0; i < COSIZE; i++) { | |
434 | if (prco.entries[i] == 0) | |
435 | return; | |
436 | mark_member(g, ntohl(prco.entries[i])); | |
437 | } | |
438 | offset = ntohl(prco.next); | |
439 | } | |
440 | } | |
441 | ||
442 | ||
443 | mark_member(g, uid) | |
444 | struct group *g; | |
445 | int uid; | |
446 | { | |
e88f0823 | 447 | register int i, j, status; |
a04caf14 | 448 | |
e88f0823 | 449 | if (uid == PRBADID) |
450 | return; | |
a04caf14 | 451 | if (g->members >= CHUNKSIZE) { |
452 | short *s = NULL, s1; | |
453 | struct chunk *c = (struct chunk *)&(g->ch); | |
454 | ||
455 | for (i = 0; i < g->members; i++) { | |
456 | j = i % CHUNKSIZE; | |
457 | if (c->member[j] == uid) { | |
458 | s = &(c->member[j]); | |
459 | } | |
460 | if (j == CHUNKSIZE - 1) { | |
461 | s1 = c->member[CHUNKSIZE - 1]; | |
462 | c = c->xmem; | |
463 | } | |
464 | } | |
465 | if (j != CHUNKSIZE - 1) | |
466 | s1 = c->member[j]; | |
467 | if (s) { | |
468 | *s = s1; | |
469 | g->members--; | |
470 | return; | |
471 | } | |
472 | printf("> Group %s contains user %d in prs but not in Moira\n", g->name, | |
473 | uid); | |
e88f0823 | 474 | if (replaceflag) { |
475 | status = PR_RemoveFromGroup(NULL, uid, -g->gid); | |
476 | if (status) | |
477 | prserror(status, "While removing user %d from group %d in prs", | |
478 | uid, g->gid); | |
479 | } | |
a04caf14 | 480 | return; |
481 | } | |
482 | for (i = 0; i < g->members; i++) { | |
483 | if (g->ch.member[i] == uid) { | |
484 | if (g->members == i + 1) | |
485 | g->ch.member[i] = 0; | |
486 | else { | |
487 | g->ch.member[i] = g->ch.member[g->members]; | |
488 | g->ch.member[g->members] = 0; | |
489 | } | |
490 | g->members--; | |
491 | return; | |
492 | } | |
493 | } | |
494 | printf("> Group %s contains user %d in prs but not in Moira\n", g->name, | |
495 | uid); | |
e88f0823 | 496 | if (replaceflag) { |
497 | status = PR_RemoveFromGroup(NULL, uid, -g->gid); | |
498 | if (status) | |
499 | prserror(status, "While removing user %d from group %d in prs", | |
500 | uid, g->gid); | |
501 | } | |
a04caf14 | 502 | } |
e88f0823 | 503 | |
504 | ||
505 | #define MALLOC_BLOCK 102400 | |
506 | ||
507 | char *perm_malloc(size) | |
508 | unsigned size; | |
509 | { | |
510 | static char *pool = NULL; | |
511 | static unsigned pool_size = 0; | |
512 | register char *ret; | |
513 | ||
514 | if (size > pool_size) { | |
515 | pool = (char *) malloc(MALLOC_BLOCK); | |
516 | pool_size = MALLOC_BLOCK; | |
517 | } | |
518 | ret = pool; | |
519 | pool += size; | |
520 | pool = (char *)(((unsigned) (pool + 1)) & ~1); | |
521 | pool_size -= (pool - ret); | |
522 | return(ret); | |
523 | } | |
524 |