]>
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> | |
9 | #include "print.h" | |
10 | #include "prserver.h" | |
11 | #include "prerror.h" | |
12 | #include <sms.h> | |
13 | #include <sms_app.h> | |
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 | ||
22 | char *malloc(), *strsave(); | |
23 | int dbase_fd; | |
24 | struct prheader prh; | |
25 | ||
26 | ||
27 | main(argc, argv) | |
28 | int argc; | |
29 | char **argv; | |
30 | { | |
31 | int ingerr(); | |
32 | ||
33 | if (argc != 2) { | |
34 | fprintf(stderr, "usage: %s dbfile\n", argv[0]); | |
35 | exit(SMS_ARGS); | |
36 | } | |
37 | ||
38 | dbase_fd = open(argv[1], O_RDONLY, 0660); | |
39 | if (dbase_fd < 0) { | |
40 | perror("opening file %s", argv[1]); | |
41 | exit(1); | |
42 | } | |
43 | IIseterr(ingerr); | |
44 | initialize_sms_error_table (); | |
45 | ||
46 | ## ingres sms | |
47 | ## set lockmode session where level = table | |
48 | ## begin transaction | |
49 | ||
50 | get_users(); | |
51 | get_groups(); | |
52 | get_members(); | |
53 | ||
54 | ## end transaction | |
55 | ## exit | |
56 | ||
57 | pr_Read(NULL, 0, 0, &prh, sizeof(prh)); | |
58 | check_users_and_groups(); | |
59 | ||
60 | exit(SMS_SUCCESS); | |
61 | } | |
62 | ||
63 | ||
64 | /* | |
65 | * ingerr: (supposedly) called when Ingres indicates an error. | |
66 | * I have not yet been able to get this to work to intercept a | |
67 | * database open error. | |
68 | */ | |
69 | #define INGRES_DEADLOCK 4700 | |
70 | ||
71 | static int ingerr(num) | |
72 | int *num; | |
73 | { | |
74 | char buf[256]; | |
75 | int ingres_errno; | |
76 | ||
77 | switch (*num) { | |
78 | case INGRES_DEADLOCK: | |
79 | ingres_errno = SMS_DEADLOCK; | |
80 | break; | |
81 | default: | |
82 | ingres_errno = SMS_INGRES_ERR; | |
83 | } | |
84 | com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num); | |
85 | exit(ingres_errno); | |
86 | } | |
87 | ||
88 | ||
89 | prserror(status, msg, arg1, arg2) | |
90 | int status; | |
91 | char *msg; | |
92 | unsigned long arg1, arg2; | |
93 | { | |
94 | char buf[512]; | |
95 | ||
96 | sprintf(buf, msg, arg1, arg2); | |
97 | switch (status) { | |
98 | case PREXIST: | |
99 | msg = "name already exists"; | |
100 | break; | |
101 | case PRIDEXIST: | |
102 | msg = "ID already exists"; | |
103 | break; | |
104 | case PRNOIDS: | |
105 | msg = "no IDs available"; | |
106 | break; | |
107 | case PRDBFAIL: | |
108 | msg = "database failed"; | |
109 | break; | |
110 | case PRNOENT: | |
111 | msg = "no space left in database"; | |
112 | break; | |
113 | case PRPERM: | |
114 | msg = "permission denied"; | |
115 | break; | |
116 | case PRNOTGROUP: | |
117 | msg = "not a group"; | |
118 | break; | |
119 | case PRNOTUSER: | |
120 | msg = "not a user"; | |
121 | break; | |
122 | case PRBADNAM: | |
123 | msg = "bad name"; | |
124 | break; | |
125 | case 0: | |
126 | msg = "no error"; | |
127 | break; | |
128 | default: | |
129 | msg = "unknown code"; | |
130 | break; | |
131 | } | |
132 | fprintf(stderr, "%s (%d): %s\n", msg, status, buf); | |
133 | } | |
134 | ||
135 | ||
136 | nomem(msg) | |
137 | char *msg; | |
138 | { | |
139 | fprintf(stderr, "Out of memory: %s\n", msg); | |
140 | exit(1); | |
141 | } | |
142 | ||
143 | ||
144 | struct user { | |
145 | char login[9]; | |
146 | char flag; | |
147 | short uid; | |
148 | }; | |
149 | ||
150 | ||
151 | get_users() | |
152 | ##{ | |
153 | ## char login[9]; | |
154 | ## int uid, id; | |
155 | struct user *u; | |
156 | ||
157 | fprintf(stderr, "Loading users from Moira\n"); | |
158 | users = create_hash(10000); | |
159 | usersid = create_hash(10000); | |
160 | ## range of u is users | |
161 | ## retrieve (login = u.#login, uid = u.#uid, id = u.users_id) | |
162 | ## where u.#status = 1 { | |
163 | strtrim(login); | |
164 | u = (struct user *)malloc(sizeof(struct user)); | |
165 | if (u == NULL) | |
166 | nomem("loading users"); | |
167 | strncpy(u->login, login, 9); | |
168 | u->flag = 0; | |
169 | u->uid = uid; | |
170 | hash_store(users, uid, u); | |
171 | hash_store(usersid, id, u); | |
172 | ## } | |
173 | ##} | |
174 | ||
175 | ||
176 | #define CHUNKSIZE 10 | |
177 | struct chunk { | |
178 | short member[CHUNKSIZE]; | |
179 | struct chunk *xmem; | |
180 | }; | |
181 | ||
182 | struct group { | |
183 | char name[33]; | |
184 | char flag; | |
185 | short gid; | |
186 | short members; | |
187 | struct chunk ch; | |
188 | }; | |
189 | ||
190 | ||
191 | get_groups() | |
192 | ##{ | |
193 | ## char name[33]; | |
194 | ## int gid, id; | |
195 | struct group *g; | |
196 | ||
197 | fprintf(stderr, "Loading groups from Moira\n"); | |
198 | groups = create_hash(10000); | |
199 | groupsid = create_hash(10000); | |
200 | ## range of l is list | |
201 | ## retrieve (name = l.#name, gid = l.#gid, id = l.list_id) | |
202 | ## where l.#active = 1 and l.#group = 1 { | |
203 | strtrim(name); | |
204 | g = (struct group *)malloc(sizeof(struct group)); | |
205 | if (g == NULL) | |
206 | nomem("loading groups"); | |
207 | bzero(g, sizeof(struct group)); | |
208 | strncpy(g->name, name, 33); | |
209 | hash_store(groups, gid, g); | |
210 | hash_store(groupsid, id, g); | |
211 | ## } | |
212 | ##} | |
213 | ||
214 | ||
215 | get_members() | |
216 | ##{ | |
217 | struct user *u; | |
218 | struct group *g; | |
219 | ## int id, lid; | |
220 | ||
221 | fprintf(stderr, "Fetching members from Moira\n"); | |
222 | ||
223 | ## range of m is imembers | |
224 | ||
225 | ## retrieve (lid = m.list_id, id = m.member_id) | |
226 | ## where m.member_type = "USER" { | |
227 | if ((u = (struct user *) hash_lookup(usersid, id)) && | |
228 | (g = (struct group *) hash_lookup(groupsid, lid))) { | |
229 | if (g->members < CHUNKSIZE) { | |
230 | g->ch.member[g->members] = u->uid; | |
231 | } else { | |
232 | int i = g->members - CHUNKSIZE; | |
233 | struct chunk *c; | |
234 | ||
235 | if ((c = g->ch.xmem) == NULL) { | |
236 | c = (struct chunk *) malloc(sizeof(struct chunk)); | |
237 | if (c == NULL) | |
238 | nomem("loading members"); | |
239 | g->ch.xmem = c; | |
240 | } | |
241 | while (i >= CHUNKSIZE) { | |
242 | i -= CHUNKSIZE; | |
243 | if (c->xmem == NULL) { | |
244 | c->xmem = (struct chunk *) malloc(sizeof(struct chunk)); | |
245 | if (c->xmem == NULL) | |
246 | nomem("loading members"); | |
247 | } | |
248 | c = c->xmem; | |
249 | } | |
250 | c->member[i] = u->uid; | |
251 | } | |
252 | g->members++; | |
253 | } | |
254 | ## } | |
255 | ||
256 | ##} | |
257 | ||
258 | ||
259 | ||
260 | checkuser(id, u) | |
261 | int id; | |
262 | struct user *u; | |
263 | { | |
264 | if (u->flag == 0) | |
265 | printf("< User %s id %d is in Moira but not in prs\n", u->login, u->uid); | |
266 | } | |
267 | ||
268 | checkgroup(id, g) | |
269 | int id; | |
270 | struct group *g; | |
271 | { | |
272 | register int i, j; | |
273 | struct chunk *c; | |
274 | ||
275 | if (g->flag == 0) | |
276 | printf("< Group %s id %d is in Moira but not in prs\n", g->name, g->gid); | |
277 | c = (struct chunk *)&(g->ch); | |
278 | for (i = 0; i < g->members; i++) { | |
279 | j = i % CHUNKSIZE; | |
280 | printf("< Group %s contains user %d in Moira but not in prs\n", | |
281 | g->name, c->member[j]); | |
282 | if (j == CHUNKSIZE - 1) | |
283 | c = c->xmem; | |
284 | } | |
285 | } | |
286 | ||
287 | check_users_and_groups() | |
288 | { | |
289 | register int i; | |
290 | int offset; | |
291 | ||
292 | fprintf(stderr, "Scanning PRS database\n"); | |
293 | ||
294 | for (i = 0; i < HASHSIZE; i++) { | |
295 | offset = ntohl(prh.idHash[i]); | |
296 | while (offset) | |
297 | offset = check_entry(offset); | |
298 | } | |
299 | hash_step(users, checkuser, NULL); | |
300 | hash_step(groups, checkgroup, NULL); | |
301 | } | |
302 | ||
303 | check_entry(offset) | |
304 | int offset; | |
305 | { | |
306 | struct prentry entry; | |
307 | int flags, id, status; | |
308 | struct user *u; | |
309 | struct group *g; | |
310 | ||
311 | status = pr_Read(NULL, 0, offset, &entry, sizeof(entry)); | |
312 | if (status) | |
313 | prserror(status, "reading prentry at %d", offset, 0); | |
314 | flags = ntohl(entry.flags); | |
315 | id = ntohl(entry.id); | |
316 | if ((flags & PRFREE) == 0) { | |
317 | if (flags & PRGRP) { | |
318 | g = (struct group *) hash_lookup(groups, abs(id)); | |
319 | if (g == NULL) | |
320 | printf("> Group %s, id %d is in prs but not moira\n", | |
321 | entry.name, id); | |
322 | else if (strcasecmp(g->name, index(entry.name, ':')+1)) | |
323 | printf("> Group id %d in prs is %s, but GID %d in moira is %s\n", | |
324 | id, entry.name, -id, g->name); | |
325 | else { | |
326 | g->flag = 1; | |
327 | if (entry.entries[0]) | |
328 | do_members(&entry, g); | |
329 | } | |
330 | } else { | |
331 | u = (struct user *) hash_lookup(users, abs(id)); | |
332 | if (u == NULL) | |
333 | printf("> User %s, id %d is in prs but not moira\n", | |
334 | entry.name, id); | |
335 | else if (strcasecmp(u->login, entry.name)) | |
336 | printf("> User id %d in prs is %s, but UID %d in moira is %s\n", | |
337 | id, entry.name, id, u->login); | |
338 | else | |
339 | u->flag = 1; | |
340 | } | |
341 | } | |
342 | return(ntohl(entry.nextID)); | |
343 | } | |
344 | ||
345 | ||
346 | do_members(e, g) | |
347 | struct prentry *e; | |
348 | struct group *g; | |
349 | { | |
350 | register int i; | |
351 | int offset; | |
352 | struct contentry prco; | |
353 | ||
354 | for (i = 0; i < PRSIZE; i++) { | |
355 | if (e->entries[i] == 0) | |
356 | return; | |
357 | mark_member(g, ntohl(e->entries[i])); | |
358 | } | |
359 | offset = ntohl(e->next); | |
360 | while (offset) { | |
361 | pr_Read(NULL, 0, offset, &prco, sizeof(struct contentry)); | |
362 | for (i = 0; i < COSIZE; i++) { | |
363 | if (prco.entries[i] == 0) | |
364 | return; | |
365 | mark_member(g, ntohl(prco.entries[i])); | |
366 | } | |
367 | offset = ntohl(prco.next); | |
368 | } | |
369 | } | |
370 | ||
371 | ||
372 | mark_member(g, uid) | |
373 | struct group *g; | |
374 | int uid; | |
375 | { | |
376 | register int i, j; | |
377 | ||
378 | if (g->members >= CHUNKSIZE) { | |
379 | short *s = NULL, s1; | |
380 | struct chunk *c = (struct chunk *)&(g->ch); | |
381 | ||
382 | for (i = 0; i < g->members; i++) { | |
383 | j = i % CHUNKSIZE; | |
384 | if (c->member[j] == uid) { | |
385 | s = &(c->member[j]); | |
386 | } | |
387 | if (j == CHUNKSIZE - 1) { | |
388 | s1 = c->member[CHUNKSIZE - 1]; | |
389 | c = c->xmem; | |
390 | } | |
391 | } | |
392 | if (j != CHUNKSIZE - 1) | |
393 | s1 = c->member[j]; | |
394 | if (s) { | |
395 | *s = s1; | |
396 | g->members--; | |
397 | return; | |
398 | } | |
399 | printf("> Group %s contains user %d in prs but not in Moira\n", g->name, | |
400 | uid); | |
401 | return; | |
402 | } | |
403 | for (i = 0; i < g->members; i++) { | |
404 | if (g->ch.member[i] == uid) { | |
405 | if (g->members == i + 1) | |
406 | g->ch.member[i] = 0; | |
407 | else { | |
408 | g->ch.member[i] = g->ch.member[g->members]; | |
409 | g->ch.member[g->members] = 0; | |
410 | } | |
411 | g->members--; | |
412 | return; | |
413 | } | |
414 | } | |
415 | printf("> Group %s contains user %d in prs but not in Moira\n", g->name, | |
416 | uid); | |
417 | } |