reindent-20030715
[openafs.git] / src / ptserver / pt_util.c
1 /* $Id$ */
2
3 /*
4  *
5  * pt_util: Program to dump the AFS protection server database
6  *         into an ascii file.
7  *
8  *      Assumptions: We *cheat* here and read the datafile directly, ie.
9  *                   not going through the ubik distributed data manager.
10  *                   therefore the database must be quiescent for the
11  *                   output of this program to be valid.
12  */
13
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/file.h>
21
22 #include <afsconfig.h>
23 #include <afs/param.h>
24
25 RCSID
26     ("$Header$");
27
28 #include <errno.h>
29 #include <lock.h>
30 #include <netinet/in.h>
31 #define UBIK_INTERNALS
32 #include <ubik.h>
33 #include <rx/xdr.h>
34 #include <rx/rx.h>
35 #include "ptint.h"
36 #include "ptserver.h"
37 #include "pterror.h"
38
39 #define IDHash(x) (abs(x) % HASHSIZE)
40 #define print_id(x) ( ((flags&DO_SYS)==0 && (x<-32767 || x>97536)) || \
41                       ((flags&DO_OTR)==0 && (x>-32768 && x<97537)))
42
43 extern char *optarg;
44 extern int optind;
45
46 int display_entry();
47 void add_group();
48 void display_groups();
49 void display_group();
50 void fix_pre();
51 char *checkin();
52 char *check_core();
53 char *id_to_name();
54
55 struct hash_entry {
56     char h_name[PR_MAXNAMELEN];
57     int h_id;
58     struct hash_entry *next;
59 };
60 struct hash_entry *hat[HASHSIZE];
61
62 static struct contentry prco;
63 static struct prentry pre;
64 static struct prheader prh;
65 static struct ubik_version uv;
66
67 struct grp_list {
68     struct grp_list *next;
69     long groups[1024];
70 };
71 static struct grp_list *grp_head = 0;
72 static long grp_count = 0;
73
74 struct usr_list {
75     struct usr_list *next;
76     char name[PR_MAXNAMELEN];
77     long uid;
78 };
79 static struct usr_list *usr_head = 0;
80
81 char buffer[1024];
82 int dbase_fd;
83 FILE *dfp;
84
85 #define FMT_BASE "%-10s %d/%d %d %d %d\n"
86 #define FMT_MEM  "   %-8s %d\n"
87
88 #define DO_USR 1
89 #define DO_GRP 2
90 #define DO_MEM 4
91 #define DO_SYS 8
92 #define DO_OTR 16
93
94 int nflag = 0;
95 int wflag = 0;
96 int flags = 0;
97
98 main(argc, argv)
99      int argc;
100      char **argv;
101 {
102     register int i;
103     register long code;
104     long cc, upos, gpos;
105     struct prentry uentry, gentry;
106     struct ubik_hdr *uh;
107     char *dfile = 0;
108     char *pfile = "/usr/afs/db/prdb.DB0";
109
110     while ((cc = getopt(argc, argv, "wugmxsnp:d:")) != EOF) {
111         switch (cc) {
112         case 'p':
113             pfile = optarg;
114             break;
115         case 'd':
116             dfile = optarg;
117             break;
118         case 'n':
119             nflag++;
120             break;
121         case 'w':
122             wflag++;
123             break;
124         case 'u':
125             flags |= DO_USR;
126             break;
127         case 'm':
128             flags |= (DO_GRP | DO_MEM);
129             break;
130         case 'g':
131             flags |= DO_GRP;
132             break;
133         case 's':
134             flags |= DO_SYS;
135             break;
136         case 'x':
137             flags |= DO_OTR;
138             break;
139         default:
140             fprintf(stderr, "Usage: pt_util [options] [-d data] [-p prdb]\n");
141             fputs("  Options:\n", stderr);
142             fputs("    -w  Update prdb with contents of data file\n", stderr);
143             fputs("    -u  Display users\n", stderr);
144             fputs("    -g  Display groups\n", stderr);
145             fputs("    -m  Display group members\n", stderr);
146             fputs("    -n  Follow name hash chains (not id hashes)\n",
147                   stderr);
148             fputs("    -s  Display only system data\n", stderr);
149             fputs("    -x  Display extra users/groups\n", stderr);
150             exit(1);
151         }
152     }
153     if ((dbase_fd = open(pfile, (wflag ? O_RDWR : O_RDONLY) | O_CREAT, 0600))
154         < 0) {
155         fprintf(stderr, "pt_util: cannot open %s: %s\n", pfile,
156                 strerror(errno));
157         exit(1);
158     }
159     if (read(dbase_fd, buffer, HDRSIZE) < 0) {
160         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
161                 strerror(errno));
162         exit(1);
163     }
164
165     if (dfile) {
166         if ((dfp = fopen(dfile, wflag ? "r" : "w")) == 0) {
167             fprintf(stderr, "pt_util: error opening %s: %s\n", dfile,
168                     strerror(errno));
169             exit(1);
170         }
171     } else
172         dfp = (wflag ? stdin : stdout);
173
174     uh = (struct ubik_hdr *)buffer;
175     if (ntohl(uh->magic) != UBIK_MAGIC)
176         fprintf(stderr, "pt_util: %s: Bad UBIK_MAGIC. Is %x should be %x\n",
177                 pfile, ntohl(uh->magic), UBIK_MAGIC);
178     memcpy(&uv, &uh->version, sizeof(struct ubik_version));
179     if (wflag && uv.epoch == 0 && uv.counter == 0) {
180         uv.epoch = 2;           /* a ubik version of 0 or 1 has special meaning */
181         memcpy(&uh->version, &uv, sizeof(struct ubik_version));
182         lseek(dbase_fd, 0, SEEK_SET);
183         if (write(dbase_fd, buffer, HDRSIZE) < 0) {
184             fprintf(stderr, "pt_util: error writing ubik version to %s: %s\n",
185                     pfile, strerror(errno));
186             exit(1);
187         }
188     }
189     fprintf(stderr, "Ubik Version is: %d.%d\n", uv.epoch, uv.counter);
190     if (read(dbase_fd, &prh, sizeof(struct prheader)) < 0) {
191         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
192                 strerror(errno));
193         exit(1);
194     }
195
196     Initdb();
197     initialize_PT_error_table();
198
199     if (wflag) {
200         struct usr_list *u;
201
202         while (fgets(buffer, sizeof(buffer), dfp)) {
203             int id, oid, cid, flags, quota, uid;
204             char name[PR_MAXNAMELEN], mem[PR_MAXNAMELEN];
205
206             if (isspace(*buffer)) {
207                 sscanf(buffer, "%s %d", mem, &uid);
208
209                 for (u = usr_head; u; u = u->next)
210                     if (u->uid && u->uid == uid)
211                         break;
212                 if (u) {
213                     /* Add user - deferred because it is probably foreign */
214                     u->uid = 0;
215                     if (FindByID(0, uid))
216                         code = PRIDEXIST;
217                     else {
218                         if (!code
219                             && (flags & (PRGRP | PRQUOTA)) ==
220                             (PRGRP | PRQUOTA)) {
221                             gentry.ngroups++;
222                             code = pr_WriteEntry(0, 0, gpos, &gentry);
223                             if (code)
224                                 fprintf(stderr,
225                                         "Error setting group count on %s: %s\n",
226                                         name, error_message(code));
227                         }
228                         code =
229                             CreateEntry(0, u->name, &uid, 1 /*idflag */ ,
230                                         1 /*gflag */ ,
231                                         SYSADMINID /*oid */ ,
232                                         SYSADMINID /*cid */ );
233                     }
234                     if (code)
235                         fprintf(stderr, "Error while creating %s: %s\n",
236                                 u->name, error_message(code));
237                     continue;
238                 }
239                 /* Add user to group */
240                 if (id == ANYUSERID || id == AUTHUSERID || uid == ANONYMOUSID) {
241                     code = PRPERM;
242                 } else if ((upos = FindByID(0, uid))
243                            && (gpos = FindByID(0, id))) {
244                     code = pr_ReadEntry(0, 0, upos, &uentry);
245                     if (!code)
246                         code = pr_ReadEntry(0, 0, gpos, &gentry);
247                     if (!code)
248                         code = AddToEntry(0, &gentry, gpos, uid);
249                     if (!code)
250                         code = AddToEntry(0, &uentry, upos, id);
251                 } else
252                     code = PRNOENT;
253
254                 if (code)
255                     fprintf(stderr, "Error while adding %s to %s: %s\n", mem,
256                             name, error_message(code));
257             } else {
258                 sscanf(buffer, "%s %d/%d %d %d %d", name, &flags, &quota, &id,
259                        &oid, &cid);
260
261                 if (FindByID(0, id))
262                     code = PRIDEXIST;
263                 else
264                     code = CreateEntry(0, name, &id, 1 /*idflag */ ,
265                                        flags & PRGRP, oid, cid);
266                 if (code == PRBADNAM) {
267                     u = (struct usr_list *)malloc(sizeof(struct usr_list));
268                     u->next = usr_head;
269                     u->uid = id;
270                     strcpy(u->name, name);
271                     usr_head = u;
272                 } else if (code) {
273                     fprintf(stderr, "Error while creating %s: %s\n", name,
274                             error_message(code));
275                 } else if ((flags & PRACCESS)
276                            || (flags & (PRGRP | PRQUOTA)) ==
277                            (PRGRP | PRQUOTA)) {
278                     gpos = FindByID(0, id);
279                     code = pr_ReadEntry(0, 0, gpos, &gentry);
280                     if (!code) {
281                         gentry.flags = flags;
282                         gentry.ngroups = quota;
283                         code = pr_WriteEntry(0, 0, gpos, &gentry);
284                     }
285                     if (code)
286                         fprintf(stderr,
287                                 "Error while setting flags on %s: %s\n", name,
288                                 error_message(code));
289                 }
290             }
291         }
292         for (u = usr_head; u; u = u->next)
293             if (u->uid)
294                 fprintf(stderr, "Error while creating %s: %s\n", u->name,
295                         error_message(PRBADNAM));
296     } else {
297         for (i = 0; i < HASHSIZE; i++) {
298             upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
299             while (upos)
300                 upos = display_entry(upos);
301         }
302         if (flags & DO_GRP)
303             display_groups();
304     }
305
306     lseek(dbase_fd, 0, L_SET);  /* rewind to beginning of file */
307     if (read(dbase_fd, buffer, HDRSIZE) < 0) {
308         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
309                 strerror(errno));
310         exit(1);
311     }
312     uh = (struct ubik_hdr *)buffer;
313     if ((uh->version.epoch != uv.epoch)
314         || (uh->version.counter != uv.counter)) {
315         fprintf(stderr,
316                 "pt_util: Ubik Version number changed during execution.\n");
317         fprintf(stderr, "Old Version = %d.%d, new version = %d.%d\n",
318                 uv.epoch, uv.counter, uh->version.epoch, uh->version.counter);
319     }
320     close(dbase_fd);
321     exit(0);
322 }
323
324 int
325 display_entry(offset)
326      int offset;
327 {
328     register int i;
329
330     lseek(dbase_fd, offset + HDRSIZE, L_SET);
331     read(dbase_fd, &pre, sizeof(struct prentry));
332
333     fix_pre(&pre);
334
335     if ((pre.flags & PRFREE) == 0) {
336         if (pre.flags & PRGRP) {
337             if (flags & DO_GRP)
338                 add_group(pre.id);
339         } else {
340             if (print_id(pre.id) && (flags & DO_USR))
341                 fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups,
342                         pre.id, pre.owner, pre.creator);
343             checkin(&pre);
344         }
345     }
346     return (nflag ? pre.nextName : pre.nextID);
347 }
348
349 void
350 add_group(id)
351      long id;
352 {
353     struct grp_list *g;
354     register long i;
355
356     i = grp_count++ % 1024;
357     if (i == 0) {
358         g = (struct grp_list *)malloc(sizeof(struct grp_list));
359         g->next = grp_head;
360         grp_head = g;
361     }
362     g = grp_head;
363     g->groups[i] = id;
364 }
365
366 void
367 display_groups()
368 {
369     register int i, id;
370     struct grp_list *g;
371
372     g = grp_head;
373     while (grp_count--) {
374         i = grp_count % 1024;
375         id = g->groups[i];
376         display_group(id);
377         if (i == 0) {
378             grp_head = g->next;
379             free(g);
380             g = grp_head;
381         }
382     }
383 }
384
385 void
386 display_group(id)
387      int id;
388 {
389     register int i, offset;
390     int print_grp = 0;
391
392     offset = ntohl(prh.idHash[IDHash(id)]);
393     while (offset) {
394         lseek(dbase_fd, offset + HDRSIZE, L_SET);
395         if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
396             fprintf(stderr, "pt_util: read i/o error: %s\n", strerror(errno));
397             exit(1);
398         }
399         fix_pre(&pre);
400         if (pre.id == id)
401             break;
402         offset = pre.nextID;
403     }
404
405     if (print_id(id)) {
406         fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups, pre.id,
407                 pre.owner, pre.creator);
408         print_grp = 1;
409     }
410
411     if ((flags & DO_MEM) == 0)
412         return;
413
414     for (i = 0; i < PRSIZE; i++) {
415         if ((id = pre.entries[i]) == 0)
416             break;
417         if (id == PRBADID)
418             continue;
419         if (print_id(id) || print_grp == 1) {
420             if (print_grp == 0) {
421                 fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups,
422                         pre.id, pre.owner, pre.creator);
423                 print_grp = 2;
424             }
425             fprintf(dfp, FMT_MEM, id_to_name(id), id);
426         }
427     }
428     if (i == PRSIZE) {
429         offset = pre.next;
430         while (offset) {
431             lseek(dbase_fd, offset + HDRSIZE, L_SET);
432             read(dbase_fd, &prco, sizeof(struct contentry));
433             prco.next = ntohl(prco.next);
434             for (i = 0; i < COSIZE; i++) {
435                 prco.entries[i] = ntohl(prco.entries[i]);
436                 if ((id = prco.entries[i]) == 0)
437                     break;
438                 if (id == PRBADID)
439                     continue;
440                 if (print_id(id) || print_grp == 1) {
441                     if (print_grp == 0) {
442                         fprintf(dfp, FMT_BASE, pre.name, pre.flags,
443                                 pre.ngroups, pre.id, pre.owner, pre.creator);
444                         print_grp = 2;
445                     }
446                     fprintf(dfp, FMT_MEM, id_to_name(id), id);
447                 }
448             }
449             if ((i == COSIZE) && prco.next)
450                 offset = prco.next;
451             else
452                 offset = 0;
453         }
454     }
455 }
456
457 void
458 fix_pre(pre)
459      struct prentry *pre;
460 {
461     register int i;
462
463     pre->flags = ntohl(pre->flags);
464     pre->id = ntohl(pre->id);
465     pre->cellid = ntohl(pre->cellid);
466     pre->next = ntohl(pre->next);
467     pre->nextID = ntohl(pre->nextID);
468     pre->nextName = ntohl(pre->nextName);
469     pre->owner = ntohl(pre->owner);
470     pre->creator = ntohl(pre->creator);
471     pre->ngroups = ntohl(pre->ngroups);
472     pre->nusers = ntohl(pre->nusers);
473     pre->count = ntohl(pre->count);
474     pre->instance = ntohl(pre->instance);
475     pre->owned = ntohl(pre->owned);
476     pre->nextOwned = ntohl(pre->nextOwned);
477     pre->parent = ntohl(pre->parent);
478     pre->sibling = ntohl(pre->sibling);
479     pre->child = ntohl(pre->child);
480     for (i = 0; i < PRSIZE; i++) {
481         pre->entries[i] = ntohl(pre->entries[i]);
482     }
483 }
484
485 char *
486 id_to_name(id)
487      int id;
488 {
489     register int offset;
490     static struct prentry pre;
491     char *name;
492
493     name = check_core(id);
494     if (name)
495         return (name);
496     offset = ntohl(prh.idHash[IDHash(id)]);
497     while (offset) {
498         lseek(dbase_fd, offset + HDRSIZE, L_SET);
499         if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
500             fprintf(stderr, "pt_util: read i/o error: %s\n", strerror(errno));
501             exit(1);
502         }
503         pre.id = ntohl(pre.id);
504         if (pre.id == id) {
505             name = checkin(&pre);
506             return (name);
507         }
508         offset = ntohl(pre.nextID);
509     }
510     return 0;
511 }
512
513 char *
514 checkin(pre)
515      struct prentry *pre;
516 {
517     struct hash_entry *he, *last;
518     register int id;
519
520     id = pre->id;
521     last = (struct hash_entry *)0;
522     he = hat[IDHash(id)];
523     while (he) {
524         if (id == he->h_id)
525             return (he->h_name);
526         last = he;
527         he = he->next;
528     }
529     he = (struct hash_entry *)malloc(sizeof(struct hash_entry));
530     if (he == 0) {
531         fprintf(stderr, "pt_util: No Memory for internal hash table.\n");
532         exit(1);
533     }
534     he->h_id = id;
535     he->next = (struct hash_entry *)0;
536     strncpy(he->h_name, pre->name, PR_MAXNAMELEN);
537     if (last == (struct hash_entry *)0)
538         hat[IDHash(id)] = he;
539     else
540         last->next = he;
541     return (he->h_name);
542 }
543
544 char *
545 check_core(id)
546      register int id;
547 {
548     struct hash_entry *he;
549     he = hat[IDHash(id)];
550     while (he) {
551         if (id == he->h_id)
552             return (he->h_name);
553         he = he->next;
554     }
555     return 0;
556 }